Skip to content

Handle RecursionAssignment, SwitchCase, and CaughtException statement types in CustomJavaDocCommentBuilder #888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package examples.controlflow

import examples.CustomJavaDocTagsEnabler
import examples.SummaryTestCaseGeneratorTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.utbot.examples.controlflow.Switch
import org.utbot.framework.plugin.api.MockStrategyApi
import org.utbot.tests.infrastructure.DoNotCalculate

@ExtendWith(CustomJavaDocTagsEnabler::class)
class SummarySwitchTest : SummaryTestCaseGeneratorTest(
Switch::class
) {
@Test
fun testDifferentExceptions() {
val summary1 = "@utbot.classUnderTest {@link Switch}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
"@utbot.activatesSwitch {@code case 10}\n" +
"@utbot.returnsFrom {@code return 10;}"
val summary2 = "@utbot.classUnderTest {@link Switch}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
"@utbot.activatesSwitch {@code case default}\n" +
"@utbot.returnsFrom {@code return -1;}"
val summary3 = "@utbot.classUnderTest {@link Switch}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
"@utbot.activatesSwitch {@code case 12}\n" +
"@utbot.returnsFrom {@code return 12;}"
val summary4 = "@utbot.classUnderTest {@link Switch}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Switch#simpleSwitch(int)}\n" +
"@utbot.activatesSwitch {@code case 13}\n" +
"@utbot.returnsFrom {@code return 13;}"

val methodName1 = "testSimpleSwitch_Return10"
val methodName2 = "testSimpleSwitch_ReturnNegative1"
val methodName3 = "testSimpleSwitch_Return12"
val methodName4 = "testSimpleSwitch_Return13"

val displayName1 = "switch(x) case: 10 -> return 10"
val displayName2 = "switch(x) case: Default -> return -1"
val displayName3 = "switch(x) case: 12 -> return 12"
val displayName4 = "switch(x) case: 13 -> return 13"

val summaryKeys = listOf(
summary1,
summary2,
summary3,
summary4
)

val displayNames = listOf(
displayName1,
displayName2,
displayName3,
displayName4
)

val methodNames = listOf(
methodName1,
methodName2,
methodName3,
methodName4
)

val method = Switch::simpleSwitch
val mockStrategy = MockStrategyApi.NO_MOCKS
val coverage = DoNotCalculate

summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package examples.exceptions

import examples.CustomJavaDocTagsEnabler
import examples.SummaryTestCaseGeneratorTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.utbot.examples.exceptions.ExceptionExamples
import org.utbot.framework.plugin.api.MockStrategyApi
import org.utbot.tests.infrastructure.DoNotCalculate

@ExtendWith(CustomJavaDocTagsEnabler::class)
class SummaryExceptionExampleTest : SummaryTestCaseGeneratorTest(
ExceptionExamples::class
) {
@Test
fun testDifferentExceptions() {
val summary1 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
"@utbot.returnsFrom {@code return checkAll(i);}"
val summary2 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
"@utbot.returnsFrom {@code return -100;}\n" +
"@utbot.caughtException {@code RuntimeException e}"
val summary3 = "@utbot.classUnderTest {@link ExceptionExamples}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionExamples#nestedExceptions(int)}\n" +
"@utbot.returnsFrom {@code return 100;}\n" +
"@utbot.caughtException {@code NullPointerException e}"

val methodName1 = "testNestedExceptions_ReturnCheckAll"
val methodName2 = "testNestedExceptions_CatchRuntimeException"
val methodName3 = "testNestedExceptions_CatchNullPointerException"

val displayName1 = "-> return checkAll(i)"
val displayName2 = "Catch (RuntimeException e) -> return -100"
val displayName3 = "Catch (NullPointerException e) -> return 100"

val summaryKeys = listOf(
summary1,
summary2,
summary3
)

val displayNames = listOf(
displayName1,
displayName2,
displayName3
)

val methodNames = listOf(
methodName1,
methodName2,
methodName3
)

val method = ExceptionExamples::nestedExceptions
val mockStrategy = MockStrategyApi.NO_MOCKS
val coverage = DoNotCalculate

summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package examples.recursion

import examples.CustomJavaDocTagsEnabler
import examples.SummaryTestCaseGeneratorTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.utbot.examples.recursion.Recursion
import org.utbot.framework.plugin.api.MockStrategyApi
import org.utbot.tests.infrastructure.DoNotCalculate

@ExtendWith(CustomJavaDocTagsEnabler::class)
class SummaryRecursionTest : SummaryTestCaseGeneratorTest(
Recursion::class
) {
@Test
fun testFib() {
val summary1 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
"@utbot.executesCondition {@code (n == 0): False},\n" +
Copy link
Collaborator

@amandelpie amandelpie Sep 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thought that in future we could have something like testing dsl

javadoc {
methodUnderTest = "org.utbot.examples.recursion.Recursion#fib(int)"
executesCondition = "(n == 0): False"
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yesss, it would be awesome!

"{@code (n == 1): True}\n" +
"@utbot.returnsFrom {@code return 1;}"
val summary2 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
"@utbot.executesCondition {@code (n == 0): True}\n" +
"@utbot.returnsFrom {@code return 0;}\n"
val summary3 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
"@utbot.executesCondition {@code (n == 1): False}\n" +
"@utbot.returnsFrom {@code return fib(n - 1) + fib(n - 2);}"
val summary4 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#fib(int)}\n" +
"@utbot.executesCondition {@code (n < 0): True}\n" +
"@utbot.throwsException {@link java.lang.IllegalArgumentException} in: n < 0"

val methodName1 = "testFib_Return1"
val methodName2 = "testFib_ReturnZero"
val methodName3 = "testFib_NNotEquals1"
val methodName4 = "testFib_NLessThanZero"

val displayName1 = "n == 0 : False -> return 1"
val displayName2 = "n == 0 : True -> return 0"
val displayName3 = "return 1 -> return 0" //it looks weird
val displayName4 = "n < 0 -> ThrowIllegalArgumentException"

val summaryKeys = listOf(
summary1,
summary2,
summary3,
summary4
)

val displayNames = listOf(
displayName1,
displayName2,
displayName3,
displayName4
)

val methodNames = listOf(
methodName1,
methodName2,
methodName3,
methodName4
)

val method = Recursion::fib
val mockStrategy = MockStrategyApi.NO_MOCKS
val coverage = DoNotCalculate

summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
}

@Test
fun testFactorial() {
val summary1 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
//TODO: Lost information about executed condition,
// see [issue-900](https://github.com/UnitTestBot/UTBotJava/issues/900)
//"@utbot.executesCondition {@code (n == 0): True}\n"
"@utbot.returnsFrom {@code return 1;}"
val summary2 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
"@utbot.executesCondition {@code (n == 0): False}\n" +
"@utbot.returnsFrom {@code return n * factorial(n - 1);}"
val summary3 = "@utbot.classUnderTest {@link Recursion}\n" +
"@utbot.methodUnderTest {@link org.utbot.examples.recursion.Recursion#factorial(int)}\n" +
"@utbot.executesCondition {@code (n < 0): True}\n" +
"@utbot.throwsException {@link java.lang.IllegalArgumentException} after condition: n < 0"

val methodName1 = "testFactorial_Return1"
val methodName2 = "testFactorial_NNotEqualsZero"
val methodName3 = "testFactorial_NLessThanZero"

//TODO: Display names are not complete, see [issue-899](https://github.com/UnitTestBot/UTBotJava/issues/899).
//they should be equal "n == 0 : True -> return 1" and "n == 0 : False -> return n * factorial(n - 1)" respectively
val displayName1 = "-> return 1"
val displayName2 = "-> return 1"
val displayName3 = "n < 0 -> ThrowIllegalArgumentException"

val summaryKeys = listOf(
summary1,
summary2,
summary3
)

val displayNames = listOf(
displayName1,
displayName2,
displayName3
)

val methodNames = listOf(
methodName1,
methodName2,
methodName3
)

val method = Recursion::factorial
val mockStrategy = MockStrategyApi.NO_MOCKS
val coverage = DoNotCalculate

summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ package org.utbot.summary.comment
* Represents a set of plugin's custom JavaDoc tags.
*/
data class CustomJavaDocComment(
val classUnderTest: String = "",
val methodUnderTest: String = "",
val expectedResult: String = "",
val actualResult: String = "",
val classUnderTest: String = EMPTY_STRING,
val methodUnderTest: String = EMPTY_STRING,
val expectedResult: String = EMPTY_STRING,
val actualResult: String = EMPTY_STRING,
var executesCondition: List<String> = listOf(),
var invokes: List<String> = listOf(),
var iterates: List<String> = listOf(),
var returnsFrom: String = "",
var throwsException: String = ""
var switchCase: String = EMPTY_STRING,
var recursion: String = EMPTY_STRING,
var returnsFrom: String = EMPTY_STRING,
var countedReturn: String = EMPTY_STRING,
var caughtException: String = EMPTY_STRING,
var throwsException: String = EMPTY_STRING
)
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CustomJavaDocCommentBuilder(
)
val classReference = getClassReference(currentMethod.declaringClass.javaStyleName)

val customJavaDocComment = CustomJavaDocComment(
val comment = CustomJavaDocComment(
classUnderTest = classReference,
methodUnderTest = methodReference,
)
Expand All @@ -49,33 +49,46 @@ class CustomJavaDocCommentBuilder(
val exceptionName = thrownException.javaClass.name
val reason = findExceptionReason(currentMethod, thrownException)

customJavaDocComment.throwsException = "{@link $exceptionName} $reason"
comment.throwsException = "{@link $exceptionName} $reason"
}

// builds Iterates section
rootSentenceBlock.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) ->
customJavaDocComment.iterates += stringTemplates.iterationSentence.format(
stringTemplates.codeSentence.format(loopDesc),
numberOccurrencesToText(
sentenceBlocks.size
)
)
}

// builds Invoke, Execute, Return sections
generateSequence(rootSentenceBlock) { it.nextBlock }.forEach {
for (statement in it.stmtTexts) {
when (statement.stmtType) {
StmtType.Invoke -> customJavaDocComment.invokes += "{@code ${statement.description}}"
StmtType.Condition -> customJavaDocComment.executesCondition += "{@code ${statement.description}}"
StmtType.Return -> customJavaDocComment.returnsFrom = "{@code ${statement.description}}"
else -> {
//TODO: see [issue-773](https://github.com/UnitTestBot/UTBotJava/issues/773)
}
it.stmtTexts.forEach { statement ->
processStatement(statement, comment)
}

it.invokeSentenceBlock?.let {
comment.invokes += it.first
it.second.stmtTexts.forEach { statement ->
processStatement(statement, comment)
}
}

it.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) ->
comment.iterates += stringTemplates.iterationSentence.format(
stringTemplates.codeSentence.format(loopDesc),
numberOccurrencesToText(
sentenceBlocks.size
)
)
}
}

return customJavaDocComment
return comment
}

private fun processStatement(
statement: StmtDescription,
comment: CustomJavaDocComment
) {
when (statement.stmtType) {
StmtType.Invoke -> comment.invokes += "{@code ${statement.description}}"
StmtType.Condition -> comment.executesCondition += "{@code ${statement.description}}"
StmtType.Return -> comment.returnsFrom = "{@code ${statement.description}}"
StmtType.CaughtException -> comment.caughtException = "{@code ${statement.description}}"
StmtType.SwitchCase -> comment.switchCase = "{@code case ${statement.description}}"
StmtType.CountedReturn -> comment.countedReturn = "{@code ${statement.description}}"
StmtType.RecursionAssignment -> comment.recursion = "of {@code ${statement.description}}"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ class CustomJavaDocTagProvider {
CustomJavaDocTag.Executes,
CustomJavaDocTag.Invokes,
CustomJavaDocTag.Iterates,
CustomJavaDocTag.SwitchCase,
CustomJavaDocTag.Recursion,
CustomJavaDocTag.ReturnsFrom,
CustomJavaDocTag.CaughtException,
CustomJavaDocTag.ThrowsException,
)
}
Expand All @@ -41,7 +44,14 @@ sealed class CustomJavaDocTag(

object Invokes : CustomJavaDocTag("utbot.invokes", "Invokes", CustomJavaDocComment::invokes)
object Iterates : CustomJavaDocTag("utbot.iterates", "Iterates", CustomJavaDocComment::iterates)
object SwitchCase : CustomJavaDocTag("utbot.activatesSwitch", "Activates switch", CustomJavaDocComment::switchCase)
object Recursion :
CustomJavaDocTag("utbot.triggersRecursion", "Triggers recursion ", CustomJavaDocComment::recursion)

object ReturnsFrom : CustomJavaDocTag("utbot.returnsFrom", "Returns from", CustomJavaDocComment::returnsFrom)
object CaughtException :
CustomJavaDocTag("utbot.caughtException", "Caught exception", CustomJavaDocComment::caughtException)

object ThrowsException :
CustomJavaDocTag("utbot.throwsException", "Throws exception", CustomJavaDocComment::throwsException)

Expand Down