Skip to content

Commit 3d89fdf

Browse files
authored
Add options for clinit sections (#1636)
1 parent 7922e63 commit 3d89fdf

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,20 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS
505505
* The behaviour of further analysis if tests generation cancellation is requested.
506506
*/
507507
var cancellationStrategyType by getEnumProperty(CancellationStrategyType.SAVE_PROCESSED_RESULTS)
508+
509+
/**
510+
* Depending on this option, <clinit> sections might be analyzed or not.
511+
* Note that some clinit sections still will be initialized using runtime information.
512+
*/
513+
var enableClinitSectionsAnalysis by getBooleanProperty(true)
514+
515+
/**
516+
* Process all clinit sections concretely.
517+
*
518+
* If [enableClinitSectionsAnalysis] is false, it disables effect of this option as well.
519+
* Note that values processed concretely won't be replaced with unbounded symbolic variables.
520+
*/
521+
var processAllClinitSectionsConcretely by getBooleanProperty(false)
508522
}
509523

510524
/**

utbot-framework-api/src/main/kotlin/org/utbot/testcheckers/SettingsModificators.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ inline fun <reified T> withoutConcrete(block: () -> T): T {
109109
}
110110
}
111111

112+
inline fun <reified T> withProcessingClinitSections(value: Boolean, block: () -> T): T {
113+
val prev = UtSettings.enableClinitSectionsAnalysis
114+
UtSettings.enableClinitSectionsAnalysis = value
115+
try {
116+
return block()
117+
} finally {
118+
UtSettings.enableClinitSectionsAnalysis = prev
119+
}
120+
}
121+
122+
inline fun <reified T> withProcessingAllClinitSectionsConcretely(value: Boolean, block: () -> T): T {
123+
val prev = UtSettings.processAllClinitSectionsConcretely
124+
UtSettings.processAllClinitSectionsConcretely = value
125+
try {
126+
return block()
127+
} finally {
128+
UtSettings.processAllClinitSectionsConcretely = prev
129+
}
130+
}
131+
132+
112133
/**
113134
* Run [block] with disabled sandbox in the concrete executor
114135
*/
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.utbot.examples.objects
2+
3+
import org.junit.jupiter.api.Test
4+
import org.utbot.testcheckers.eq
5+
import org.utbot.testcheckers.withProcessingAllClinitSectionsConcretely
6+
import org.utbot.testcheckers.withoutConcrete
7+
import org.utbot.testcheckers.withProcessingClinitSections
8+
import org.utbot.testing.UtValueTestCaseChecker
9+
import org.utbot.testing.atLeast
10+
11+
internal class ClassForTestClinitSectionsTest : UtValueTestCaseChecker(testClass = ClassForTestClinitSections::class) {
12+
@Test
13+
fun testClinitWithoutClinitAnalysis() {
14+
withoutConcrete {
15+
withProcessingClinitSections(value = false) {
16+
check(
17+
ClassForTestClinitSections::resultDependingOnStaticSection,
18+
eq(2),
19+
{ r -> r == -1 },
20+
{ r -> r == 1 }
21+
)
22+
}
23+
}
24+
}
25+
26+
@Test
27+
fun testClinitWithClinitAnalysis() {
28+
withoutConcrete {
29+
check(
30+
ClassForTestClinitSections::resultDependingOnStaticSection,
31+
eq(2),
32+
{ r -> r == -1 },
33+
{ r -> r == 1 }
34+
)
35+
}
36+
}
37+
38+
@Test
39+
fun testProcessConcretelyWithoutClinitAnalysis() {
40+
withoutConcrete {
41+
withProcessingClinitSections(value = false) {
42+
withProcessingAllClinitSectionsConcretely(value = true) {
43+
check(
44+
ClassForTestClinitSections::resultDependingOnStaticSection,
45+
eq(2),
46+
{ r -> r == -1 },
47+
{ r -> r == 1 }
48+
)
49+
}
50+
}
51+
}
52+
}
53+
54+
@Test
55+
fun testProcessClinitConcretely() {
56+
withoutConcrete {
57+
withProcessingAllClinitSectionsConcretely(value = true) {
58+
check(
59+
ClassForTestClinitSections::resultDependingOnStaticSection,
60+
eq(1),
61+
{ r -> r == -1 },
62+
coverage = atLeast(71)
63+
)
64+
}
65+
}
66+
}
67+
}
68+

utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,23 @@ class Traverser(
483483
fieldRef: StaticFieldRef,
484484
stmt: Stmt
485485
): Boolean {
486+
// This order of processing options is important.
487+
// First, we should process classes that
488+
// cannot be analyzed without clinit sections, e.g., enums
486489
if (shouldProcessStaticFieldConcretely(fieldRef)) {
487490
return processStaticFieldConcretely(fieldRef, stmt)
488491
}
489492

493+
// Then we should check if we should analyze clinit sections at all
494+
if (!UtSettings.enableClinitSectionsAnalysis) {
495+
return false
496+
}
497+
498+
// Finally, we decide whether we should analyze clinit sections concretely or not
499+
if (UtSettings.processAllClinitSectionsConcretely) {
500+
return processStaticFieldConcretely(fieldRef, stmt)
501+
}
502+
490503
val field = fieldRef.field
491504
val declaringClass = field.declaringClass
492505
val declaringClassId = declaringClass.id
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.utbot.examples.objects;
2+
3+
public class ClassForTestClinitSections {
4+
private static int x = 5;
5+
6+
public int resultDependingOnStaticSection() {
7+
if (x == 5) {
8+
return -1;
9+
}
10+
11+
return 1;
12+
}
13+
}

0 commit comments

Comments
 (0)