Skip to content

Commit 7677d10

Browse files
authored
Handle RecursionAssignment, SwitchCase, and CaughtException statement types in CustomJavaDocCommentBuilder (#888)
* Add tags for recursion, switch case, and caught recursion * Add tests for recursion tag * Add tests for activatesSwitch and caughtException tags * Review fixes #773
1 parent df62dc0 commit 7677d10

File tree

6 files changed

+311
-28
lines changed

6 files changed

+311
-28
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package examples.controlflow
2+
3+
import examples.CustomJavaDocTagsEnabler
4+
import examples.SummaryTestCaseGeneratorTest
5+
import org.junit.jupiter.api.Test
6+
import org.junit.jupiter.api.extension.ExtendWith
7+
import org.utbot.examples.controlflow.Switch
8+
import org.utbot.framework.plugin.api.MockStrategyApi
9+
import org.utbot.tests.infrastructure.DoNotCalculate
10+
11+
@ExtendWith(CustomJavaDocTagsEnabler::class)
12+
class SummarySwitchTest : SummaryTestCaseGeneratorTest(
13+
Switch::class
14+
) {
15+
@Test
16+
fun testDifferentExceptions() {
17+
val summary1 = "@utbot.classUnderTest {@link Switch}\n" +
18+
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
19+
"@utbot.activatesSwitch {@code case 10}\n" +
20+
"@utbot.returnsFrom {@code return 10;}"
21+
val summary2 = "@utbot.classUnderTest {@link Switch}\n" +
22+
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
23+
"@utbot.activatesSwitch {@code case default}\n" +
24+
"@utbot.returnsFrom {@code return -1;}"
25+
val summary3 = "@utbot.classUnderTest {@link Switch}\n" +
26+
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
27+
"@utbot.activatesSwitch {@code case 12}\n" +
28+
"@utbot.returnsFrom {@code return 12;}"
29+
val summary4 = "@utbot.classUnderTest {@link Switch}\n" +
30+
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
31+
"@utbot.activatesSwitch {@code case 13}\n" +
32+
"@utbot.returnsFrom {@code return 13;}"
33+
34+
val methodName1 = "testSimpleSwitch_Return10"
35+
val methodName2 = "testSimpleSwitch_ReturnNegative1"
36+
val methodName3 = "testSimpleSwitch_Return12"
37+
val methodName4 = "testSimpleSwitch_Return13"
38+
39+
val displayName1 = "switch(x) case: 10 -> return 10"
40+
val displayName2 = "switch(x) case: Default -> return -1"
41+
val displayName3 = "switch(x) case: 12 -> return 12"
42+
val displayName4 = "switch(x) case: 13 -> return 13"
43+
44+
val summaryKeys = listOf(
45+
summary1,
46+
summary2,
47+
summary3,
48+
summary4
49+
)
50+
51+
val displayNames = listOf(
52+
displayName1,
53+
displayName2,
54+
displayName3,
55+
displayName4
56+
)
57+
58+
val methodNames = listOf(
59+
methodName1,
60+
methodName2,
61+
methodName3,
62+
methodName4
63+
)
64+
65+
val method = Switch::simpleSwitch
66+
val mockStrategy = MockStrategyApi.NO_MOCKS
67+
val coverage = DoNotCalculate
68+
69+
summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
70+
}
71+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package examples.exceptions
2+
3+
import examples.CustomJavaDocTagsEnabler
4+
import examples.SummaryTestCaseGeneratorTest
5+
import org.junit.jupiter.api.Test
6+
import org.junit.jupiter.api.extension.ExtendWith
7+
import org.utbot.examples.exceptions.ExceptionExamples
8+
import org.utbot.framework.plugin.api.MockStrategyApi
9+
import org.utbot.tests.infrastructure.DoNotCalculate
10+
11+
@ExtendWith(CustomJavaDocTagsEnabler::class)
12+
class SummaryExceptionExampleTest : SummaryTestCaseGeneratorTest(
13+
ExceptionExamples::class
14+
) {
15+
@Test
16+
fun testDifferentExceptions() {
17+
val summary1 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
18+
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
19+
"@utbot.returnsFrom {@code return checkAll(i);}"
20+
val summary2 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
21+
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
22+
"@utbot.returnsFrom {@code return -100;}\n" +
23+
"@utbot.caughtException {@code RuntimeException e}"
24+
val summary3 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
25+
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
26+
"@utbot.returnsFrom {@code return 100;}\n" +
27+
"@utbot.caughtException {@code NullPointerException e}"
28+
29+
val methodName1 = "testNestedExceptions_ReturnCheckAll"
30+
val methodName2 = "testNestedExceptions_CatchRuntimeException"
31+
val methodName3 = "testNestedExceptions_CatchNullPointerException"
32+
33+
val displayName1 = "-> return checkAll(i)"
34+
val displayName2 = "Catch (RuntimeException e) -> return -100"
35+
val displayName3 = "Catch (NullPointerException e) -> return 100"
36+
37+
val summaryKeys = listOf(
38+
summary1,
39+
summary2,
40+
summary3
41+
)
42+
43+
val displayNames = listOf(
44+
displayName1,
45+
displayName2,
46+
displayName3
47+
)
48+
49+
val methodNames = listOf(
50+
methodName1,
51+
methodName2,
52+
methodName3
53+
)
54+
55+
val method = ExceptionExamples::nestedExceptions
56+
val mockStrategy = MockStrategyApi.NO_MOCKS
57+
val coverage = DoNotCalculate
58+
59+
summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
60+
}
61+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package examples.recursion
2+
3+
import examples.CustomJavaDocTagsEnabler
4+
import examples.SummaryTestCaseGeneratorTest
5+
import org.junit.jupiter.api.Test
6+
import org.junit.jupiter.api.extension.ExtendWith
7+
import org.utbot.examples.recursion.Recursion
8+
import org.utbot.framework.plugin.api.MockStrategyApi
9+
import org.utbot.tests.infrastructure.DoNotCalculate
10+
11+
@ExtendWith(CustomJavaDocTagsEnabler::class)
12+
class SummaryRecursionTest : SummaryTestCaseGeneratorTest(
13+
Recursion::class
14+
) {
15+
@Test
16+
fun testFib() {
17+
val summary1 = "@utbot.classUnderTest {@link Recursion}\n" +
18+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
19+
"@utbot.executesCondition {@code (n == 0): False},\n" +
20+
"{@code (n == 1): True}\n" +
21+
"@utbot.returnsFrom {@code return 1;}"
22+
val summary2 = "@utbot.classUnderTest {@link Recursion}\n" +
23+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
24+
"@utbot.executesCondition {@code (n == 0): True}\n" +
25+
"@utbot.returnsFrom {@code return 0;}\n"
26+
val summary3 = "@utbot.classUnderTest {@link Recursion}\n" +
27+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
28+
"@utbot.executesCondition {@code (n == 1): False}\n" +
29+
"@utbot.returnsFrom {@code return fib(n - 1) + fib(n - 2);}"
30+
val summary4 = "@utbot.classUnderTest {@link Recursion}\n" +
31+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
32+
"@utbot.executesCondition {@code (n < 0): True}\n" +
33+
"@utbot.throwsException {@link java.lang.IllegalArgumentException} in: n < 0"
34+
35+
val methodName1 = "testFib_Return1"
36+
val methodName2 = "testFib_ReturnZero"
37+
val methodName3 = "testFib_NNotEquals1"
38+
val methodName4 = "testFib_NLessThanZero"
39+
40+
val displayName1 = "n == 0 : False -> return 1"
41+
val displayName2 = "n == 0 : True -> return 0"
42+
val displayName3 = "return 1 -> return 0" //it looks weird
43+
val displayName4 = "n < 0 -> ThrowIllegalArgumentException"
44+
45+
val summaryKeys = listOf(
46+
summary1,
47+
summary2,
48+
summary3,
49+
summary4
50+
)
51+
52+
val displayNames = listOf(
53+
displayName1,
54+
displayName2,
55+
displayName3,
56+
displayName4
57+
)
58+
59+
val methodNames = listOf(
60+
methodName1,
61+
methodName2,
62+
methodName3,
63+
methodName4
64+
)
65+
66+
val method = Recursion::fib
67+
val mockStrategy = MockStrategyApi.NO_MOCKS
68+
val coverage = DoNotCalculate
69+
70+
summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
71+
}
72+
73+
@Test
74+
fun testFactorial() {
75+
val summary1 = "@utbot.classUnderTest {@link Recursion}\n" +
76+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
77+
//TODO: Lost information about executed condition,
78+
// see [issue-900](https://github.com/UnitTestBot/UTBotJava/issues/900)
79+
//"@utbot.executesCondition {@code (n == 0): True}\n"
80+
"@utbot.returnsFrom {@code return 1;}"
81+
val summary2 = "@utbot.classUnderTest {@link Recursion}\n" +
82+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
83+
"@utbot.executesCondition {@code (n == 0): False}\n" +
84+
"@utbot.returnsFrom {@code return n * factorial(n - 1);}"
85+
val summary3 = "@utbot.classUnderTest {@link Recursion}\n" +
86+
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
87+
"@utbot.executesCondition {@code (n < 0): True}\n" +
88+
"@utbot.throwsException {@link java.lang.IllegalArgumentException} after condition: n < 0"
89+
90+
val methodName1 = "testFactorial_Return1"
91+
val methodName2 = "testFactorial_NNotEqualsZero"
92+
val methodName3 = "testFactorial_NLessThanZero"
93+
94+
//TODO: Display names are not complete, see [issue-899](https://github.com/UnitTestBot/UTBotJava/issues/899).
95+
//they should be equal "n == 0 : True -> return 1" and "n == 0 : False -> return n * factorial(n - 1)" respectively
96+
val displayName1 = "-> return 1"
97+
val displayName2 = "-> return 1"
98+
val displayName3 = "n < 0 -> ThrowIllegalArgumentException"
99+
100+
val summaryKeys = listOf(
101+
summary1,
102+
summary2,
103+
summary3
104+
)
105+
106+
val displayNames = listOf(
107+
displayName1,
108+
displayName2,
109+
displayName3
110+
)
111+
112+
val methodNames = listOf(
113+
methodName1,
114+
methodName2,
115+
methodName3
116+
)
117+
118+
val method = Recursion::factorial
119+
val mockStrategy = MockStrategyApi.NO_MOCKS
120+
val coverage = DoNotCalculate
121+
122+
summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
123+
}
124+
}

utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ package org.utbot.summary.comment
44
* Represents a set of plugin's custom JavaDoc tags.
55
*/
66
data class CustomJavaDocComment(
7-
val classUnderTest: String = "",
8-
val methodUnderTest: String = "",
9-
val expectedResult: String = "",
10-
val actualResult: String = "",
7+
val classUnderTest: String = EMPTY_STRING,
8+
val methodUnderTest: String = EMPTY_STRING,
9+
val expectedResult: String = EMPTY_STRING,
10+
val actualResult: String = EMPTY_STRING,
1111
var executesCondition: List<String> = listOf(),
1212
var invokes: List<String> = listOf(),
1313
var iterates: List<String> = listOf(),
14-
var returnsFrom: String = "",
15-
var throwsException: String = ""
14+
var switchCase: String = EMPTY_STRING,
15+
var recursion: String = EMPTY_STRING,
16+
var returnsFrom: String = EMPTY_STRING,
17+
var countedReturn: String = EMPTY_STRING,
18+
var caughtException: String = EMPTY_STRING,
19+
var throwsException: String = EMPTY_STRING
1620
)

utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class CustomJavaDocCommentBuilder(
3333
)
3434
val classReference = getClassReference(currentMethod.declaringClass.javaStyleName)
3535

36-
val customJavaDocComment = CustomJavaDocComment(
36+
val comment = CustomJavaDocComment(
3737
classUnderTest = classReference,
3838
methodUnderTest = methodReference,
3939
)
@@ -49,33 +49,46 @@ class CustomJavaDocCommentBuilder(
4949
val exceptionName = thrownException.javaClass.name
5050
val reason = findExceptionReason(currentMethod, thrownException)
5151

52-
customJavaDocComment.throwsException = "{@link $exceptionName} $reason"
52+
comment.throwsException = "{@link $exceptionName} $reason"
5353
}
5454

55-
// builds Iterates section
56-
rootSentenceBlock.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) ->
57-
customJavaDocComment.iterates += stringTemplates.iterationSentence.format(
58-
stringTemplates.codeSentence.format(loopDesc),
59-
numberOccurrencesToText(
60-
sentenceBlocks.size
61-
)
62-
)
63-
}
64-
65-
// builds Invoke, Execute, Return sections
6655
generateSequence(rootSentenceBlock) { it.nextBlock }.forEach {
67-
for (statement in it.stmtTexts) {
68-
when (statement.stmtType) {
69-
StmtType.Invoke -> customJavaDocComment.invokes += "{@code ${statement.description}}"
70-
StmtType.Condition -> customJavaDocComment.executesCondition += "{@code ${statement.description}}"
71-
StmtType.Return -> customJavaDocComment.returnsFrom = "{@code ${statement.description}}"
72-
else -> {
73-
//TODO: see [issue-773](https://github.com/UnitTestBot/UTBotJava/issues/773)
74-
}
56+
it.stmtTexts.forEach { statement ->
57+
processStatement(statement, comment)
58+
}
59+
60+
it.invokeSentenceBlock?.let {
61+
comment.invokes += it.first
62+
it.second.stmtTexts.forEach { statement ->
63+
processStatement(statement, comment)
7564
}
7665
}
66+
67+
it.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) ->
68+
comment.iterates += stringTemplates.iterationSentence.format(
69+
stringTemplates.codeSentence.format(loopDesc),
70+
numberOccurrencesToText(
71+
sentenceBlocks.size
72+
)
73+
)
74+
}
7775
}
7876

79-
return customJavaDocComment
77+
return comment
78+
}
79+
80+
private fun processStatement(
81+
statement: StmtDescription,
82+
comment: CustomJavaDocComment
83+
) {
84+
when (statement.stmtType) {
85+
StmtType.Invoke -> comment.invokes += "{@code ${statement.description}}"
86+
StmtType.Condition -> comment.executesCondition += "{@code ${statement.description}}"
87+
StmtType.Return -> comment.returnsFrom = "{@code ${statement.description}}"
88+
StmtType.CaughtException -> comment.caughtException = "{@code ${statement.description}}"
89+
StmtType.SwitchCase -> comment.switchCase = "{@code case ${statement.description}}"
90+
StmtType.CountedReturn -> comment.countedReturn = "{@code ${statement.description}}"
91+
StmtType.RecursionAssignment -> comment.recursion = "of {@code ${statement.description}}"
92+
}
8093
}
8194
}

utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ class CustomJavaDocTagProvider {
1616
CustomJavaDocTag.Executes,
1717
CustomJavaDocTag.Invokes,
1818
CustomJavaDocTag.Iterates,
19+
CustomJavaDocTag.SwitchCase,
20+
CustomJavaDocTag.Recursion,
1921
CustomJavaDocTag.ReturnsFrom,
22+
CustomJavaDocTag.CaughtException,
2023
CustomJavaDocTag.ThrowsException,
2124
)
2225
}
@@ -41,7 +44,14 @@ sealed class CustomJavaDocTag(
4144

4245
object Invokes : CustomJavaDocTag("utbot.invokes", "Invokes", CustomJavaDocComment::invokes)
4346
object Iterates : CustomJavaDocTag("utbot.iterates", "Iterates", CustomJavaDocComment::iterates)
47+
object SwitchCase : CustomJavaDocTag("utbot.activatesSwitch", "Activates switch", CustomJavaDocComment::switchCase)
48+
object Recursion :
49+
CustomJavaDocTag("utbot.triggersRecursion", "Triggers recursion ", CustomJavaDocComment::recursion)
50+
4451
object ReturnsFrom : CustomJavaDocTag("utbot.returnsFrom", "Returns from", CustomJavaDocComment::returnsFrom)
52+
object CaughtException :
53+
CustomJavaDocTag("utbot.caughtException", "Caught exception", CustomJavaDocComment::caughtException)
54+
4555
object ThrowsException :
4656
CustomJavaDocTag("utbot.throwsException", "Throws exception", CustomJavaDocComment::throwsException)
4757

0 commit comments

Comments
 (0)