Before the Prohibit to set static fields from library classes
change was implemented, every static field outside the <clinit>
block (the so-called meaningful static fields)
was stored in modelBefore
and modelAfter
. These meaningful static fields were set (and reset for test isolation) during code generation. This led to explicit static field initializations, which looked unexpected for a user. For example, an EMPTY
static field from the Optional
class might be set for the following method under test
class OptionalEmptyExample {
public java.util.Optional<Integer> optionalExample(boolean isEmpty) {
return isEmpty ? java.util.Optional.empty() : java.util.Optional.of(42);
}
}
like:
setStaticField(optionalClazz, "EMPTY", empty);
Goal: we should not set such kind of static fields with initializers.
Having merged Prohibit to set static fields from library classes
, we now do not explicitly set the static fields of the classes from the so-called trusted libraries (by default,
they are JDK packages). This behavior is guided by the org.utbot.framework. UtSettings#getIgnoreStaticsFromTrustedLibraries
setting. Current solution possibly leads to coverage regression
and needs to be investigated: Investigate coverage regression because of not setting static fields.
So, take a look at other ways to fix the problem.
The essence of the problem is assigning values to the static fields that should be set at runtime. To prevent it, we can try to create models for the static fields according to their runtime values and filter out the static fields that are equal to runtime values, using the following algorithm:
- Extract a concrete value for a static field.
- Create
UtModel
for this value and store it. - Transform the produced model to soft constraints.
- Add them to the current symbolic state.
- Having resolved
stateBefore
, compare the resultingUtModel
for the static field with the stored model and then drop the resulting model fromstateBefore
if they are equal.
We can define the meaningful static fields in a different way: we can mark the static fields as meaningful if only they affect the method-under-test result. To decide if they do:
- find out whether a given statement reads a specific static value or not and store this info,
- while traversing the method graph, propagate this stored info to each of the following statements in a tree,
- upon reaching the
return
statement of the method under test, mark all these read static fields as meaningful.
Having collected all executions, we can analyze them and check whether the given static field affects the result of a current execution. Changing the static field value may have the same effect on every execution or no effect at all. It may also be required as an entry point during the executions (e.g., an if-statement as the first statement in the method under test):
class AlwaysThrowingException {
public void throwIfMagic() {
if (ClassWithStaticField.staticField == 42) {
throw new RuntimeException("Magic number");
}
}
}
class ClassWithStaticField {
public final static int staticField = 42;
}
*This solution should only be used with the propagation solution.