Skip to content

Commit d7ad5ed

Browse files
authored
Design document for problems and solutions for static initializers analysis (#877)
1 parent e87b09f commit d7ad5ed

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

docs/StaticInitializersAnalysis.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Symbolic analysis of static initializers
2+
3+
## Problem
4+
5+
Before the [Prohibit to set static fields from library classes](https://github.com/UnitTestBot/UTBotJava/pull/699)
6+
change was implemented, every static field outside the `<clinit>` block (the so-called _meaningful_ static fields)
7+
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
8+
9+
```java
10+
class OptionalEmptyExample {
11+
public java.util.Optional<Integer> optionalExample(boolean isEmpty) {
12+
return isEmpty ? java.util.Optional.empty() : java.util.Optional.of(42);
13+
}
14+
}
15+
```
16+
17+
like:
18+
19+
```java
20+
setStaticField(optionalClazz, "EMPTY", empty);
21+
```
22+
23+
**Goal**: we should not set such kind of static fields with initializers.
24+
25+
## Current solution
26+
27+
Having merged [Prohibit to set static fields from library classes](https://github.com/UnitTestBot/UTBotJava/pull/699)
28+
, we now do not explicitly set the static fields of the classes from the so-called _trusted_ libraries (by default,
29+
they are JDK packages). This behavior is guided by the `org.utbot.framework.
30+
UtSettings#getIgnoreStaticsFromTrustedLibraries` setting. Current solution possibly **leads to coverage regression**
31+
and needs to be investigated: [Investigate coverage regression because of not setting static fields](https://github.com/UnitTestBot/UTBotJava/issues/716).
32+
So, take a look at other ways to fix the problem.
33+
34+
## Alternative solutions
35+
36+
### Use concrete values as soft constraints _(not yet implemented)_
37+
38+
The essence of the problem is assigning values to the static fields that should be set at runtime. To prevent it,
39+
we can try to create models for the static fields according to their runtime values and filter out the static fields
40+
that are equal to runtime values, using the following algorithm:
41+
42+
1. Extract a concrete value for a static field.
43+
2. Create `UtModel` for this value and store it.
44+
3. Transform the produced model to soft constraints.
45+
4. Add them to the current symbolic state.
46+
5. Having resolved `stateBefore`, compare the resulting `UtModel` for the static field with the stored model and then drop the resulting model from `stateBefore` if they are equal.
47+
48+
### Propagate information on the read static fields _(not yet implemented)_
49+
50+
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:
51+
52+
- find out whether a given statement reads a specific static value or not and store this info,
53+
- while traversing the method graph, propagate this stored info to each of the following statements in a tree,
54+
- upon reaching the `return` statement of the method under test, mark all these read static fields as _meaningful_.
55+
56+
### Filter out static methods: check if they affect `UtExecution` _(not yet implemented)_*
57+
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):
58+
59+
```java
60+
class AlwaysThrowingException {
61+
public void throwIfMagic() {
62+
if (ClassWithStaticField.staticField == 42) {
63+
throw new RuntimeException("Magic number");
64+
}
65+
}
66+
}
67+
68+
class ClassWithStaticField {
69+
public final static int staticField = 42;
70+
}
71+
```
72+
73+
*This solution should only be used with the [propagation](#propagate-information-on-the-read-static-fields) solution.

0 commit comments

Comments
 (0)