Skip to content

Commit e1fe8da

Browse files
authored
Added simple custom JavaDocs for the tests produced by Fuzzer (#1069)
* Added an initial solution * Added a method and class references * Refactor to avoid bugs with private methods * Handled empty values * Fixed tests and add a TODO ticket * Fixed review comments
1 parent 5af1f48 commit e1fe8da

17 files changed

+308
-132
lines changed

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import com.intellij.psi.PsiReference
66
import com.intellij.psi.javadoc.CustomJavadocTagProvider
77
import com.intellij.psi.javadoc.JavadocTagInfo
88
import com.intellij.psi.javadoc.PsiDocTagValue
9-
import org.utbot.summary.comment.CustomJavaDocTag
10-
import org.utbot.summary.comment.CustomJavaDocTagProvider
9+
import org.utbot.summary.comment.customtags.symbolic.CustomJavaDocTag
10+
import org.utbot.summary.comment.customtags.symbolic.CustomJavaDocTagProvider
1111

1212
/**
1313
* Provides plugin's custom JavaDoc tags to make test summaries structured.

utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import org.utbot.summary.UtSummarySettings.GENERATE_NAMES
1616
import org.utbot.summary.analysis.ExecutionStructureAnalysis
1717
import org.utbot.summary.ast.JimpleToASTMap
1818
import org.utbot.summary.ast.SourceCodeParser
19-
import org.utbot.summary.comment.SymbolicExecutionClusterCommentBuilder
19+
import org.utbot.summary.comment.cluster.SymbolicExecutionClusterCommentBuilder
2020
import org.utbot.summary.comment.SimpleCommentBuilder
2121
import org.utbot.summary.name.SimpleNameBuilder
2222
import java.io.File
@@ -37,7 +37,7 @@ import org.utbot.fuzzer.FuzzedValue
3737
import org.utbot.fuzzer.UtFuzzedExecution
3838
import org.utbot.summary.fuzzer.names.MethodBasedNameSuggester
3939
import org.utbot.summary.fuzzer.names.ModelBasedNameSuggester
40-
import org.utbot.summary.comment.CustomJavaDocCommentBuilder
40+
import org.utbot.summary.comment.customtags.symbolic.CustomJavaDocCommentBuilder
4141
import soot.SootMethod
4242

4343
private val logger = KotlinLogging.logger {}
@@ -241,6 +241,7 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
241241

242242
utExecution.testMethodName = testMethodName?.testName
243243
utExecution.displayName = testMethodName?.displayName
244+
utExecution.summary = testMethodName?.javaDoc
244245

245246
when (utExecution.result) {
246247
is UtConcreteExecutionFailure -> unsuccessfulFuzzerExecutions.add(utExecution)

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

-70
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.utbot.summary.comment.classic.fuzzer
2+
3+
import org.utbot.framework.plugin.api.DocPreTagStatement
4+
import org.utbot.framework.plugin.api.DocStatement
5+
import org.utbot.framework.plugin.api.UtExecutionResult
6+
import org.utbot.fuzzer.FuzzedMethodDescription
7+
import org.utbot.fuzzer.FuzzedValue
8+
9+
// TODO: https://github.com/UnitTestBot/UTBotJava/issues/1127
10+
class SimpleCommentForTestProducedByFuzzerBuilder(
11+
description: FuzzedMethodDescription,
12+
values: List<FuzzedValue>,
13+
result: UtExecutionResult?
14+
) {
15+
fun buildDocStatements(): List<DocStatement> {
16+
return listOf<DocStatement>(DocPreTagStatement(emptyList()))
17+
}
18+
}

utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt utbot-summary/src/main/kotlin/org/utbot/summary/comment/classic/symbolic/SimpleCommentBuilder.kt

+1-39
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import org.utbot.framework.plugin.api.exceptionOrNull
1616
import org.utbot.summary.AbstractTextBuilder
1717
import org.utbot.summary.SummarySentenceConstants.CARRIAGE_RETURN
1818
import org.utbot.summary.ast.JimpleToASTMap
19+
import org.utbot.summary.comment.customtags.getMethodReference
1920
import org.utbot.summary.tag.BasicTypeTag
2021
import org.utbot.summary.tag.CallOrderTag
2122
import org.utbot.summary.tag.StatementTag
@@ -356,45 +357,6 @@ open class SimpleCommentBuilder(
356357
)
357358
}
358359

359-
/**
360-
* Returns a reference to the invoked method. IDE can't resolve references to private methods in comments,
361-
* so we add @link tag only if the invoked method is not private.
362-
*
363-
* It looks like {@link packageName.className#methodName(type1, type2)}.
364-
*
365-
* In case when an enclosing class in nested, we need to replace '$' with '.'
366-
* to render the reference.
367-
*/
368-
fun getMethodReference(
369-
className: String,
370-
methodName: String,
371-
methodParameterTypes: List<Type>,
372-
isPrivate: Boolean
373-
): String {
374-
val prettyClassName: String = className.replace("$", ".")
375-
376-
val text = if (methodParameterTypes.isEmpty()) {
377-
"$prettyClassName#$methodName()"
378-
} else {
379-
val methodParametersAsString = methodParameterTypes.joinToString(",")
380-
"$prettyClassName#$methodName($methodParametersAsString)"
381-
}
382-
383-
return if (isPrivate) {
384-
text
385-
} else {
386-
"{@link $text}"
387-
}
388-
}
389-
390-
/**
391-
* Returns a reference to the class.
392-
* Replaces '$' with '.' in case a class is nested.
393-
*/
394-
fun getClassReference(fullClasName: String): String {
395-
return "{@link ${fullClasName.replace("$", ".")}}"
396-
}
397-
398360
protected fun buildIterationsBlock(
399361
iterations: List<StatementTag>,
400362
activatedStep: Step,

utbot-summary/src/main/kotlin/org/utbot/summary/comment/SymbolicExecutionClusterCommentBuilder.kt utbot-summary/src/main/kotlin/org/utbot/summary/comment/cluster/SymbolicExecutionClusterCommentBuilder.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
package org.utbot.summary.comment
1+
package org.utbot.summary.comment.cluster
22

33
import com.github.javaparser.ast.stmt.CatchClause
44
import com.github.javaparser.ast.stmt.ForStmt
55
import org.utbot.framework.plugin.api.DocPreTagStatement
6-
import org.utbot.framework.plugin.api.DocRegularStmt
76
import org.utbot.framework.plugin.api.DocStatement
87
import org.utbot.summary.SummarySentenceConstants.CARRIAGE_RETURN
98
import org.utbot.summary.ast.JimpleToASTMap
9+
import org.utbot.summary.comment.*
10+
import org.utbot.summary.comment.customtags.getMethodReference
1011
import org.utbot.summary.tag.BasicTypeTag
1112
import org.utbot.summary.tag.CallOrderTag
1213
import org.utbot.summary.tag.StatementTag
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.utbot.summary.comment.customtags.symbolic
2+
3+
import org.utbot.framework.plugin.api.DocRegularStmt
4+
import org.utbot.summary.comment.customtags.fuzzer.CommentWithCustomTagForTestProducedByFuzzer
5+
6+
/**
7+
* Provides a list of supported custom JavaDoc tags.
8+
*/
9+
class CustomJavaDocTagProvider {
10+
// The tags' order is important because plugin builds final JavaDoc comment according to it.
11+
fun getPluginCustomTags(): List<CustomJavaDocTag> =
12+
listOf(
13+
CustomJavaDocTag.ClassUnderTest,
14+
CustomJavaDocTag.MethodUnderTest,
15+
CustomJavaDocTag.ExpectedResult,
16+
CustomJavaDocTag.ActualResult,
17+
CustomJavaDocTag.Executes,
18+
CustomJavaDocTag.Invokes,
19+
CustomJavaDocTag.Iterates,
20+
CustomJavaDocTag.SwitchCase,
21+
CustomJavaDocTag.Recursion,
22+
CustomJavaDocTag.ReturnsFrom,
23+
CustomJavaDocTag.CaughtException,
24+
CustomJavaDocTag.ThrowsException,
25+
)
26+
}
27+
28+
sealed class CustomJavaDocTag(
29+
val name: String,
30+
val message: String,
31+
private val valueRetriever: (CustomJavaDocComment) -> Any,
32+
private val valueRetrieverFuzzer: ((CommentWithCustomTagForTestProducedByFuzzer) -> Any)? // TODO: remove after refactoring
33+
) {
34+
object ClassUnderTest :
35+
CustomJavaDocTag(
36+
"utbot.classUnderTest",
37+
"Class under test",
38+
CustomJavaDocComment::classUnderTest,
39+
CommentWithCustomTagForTestProducedByFuzzer::classUnderTest
40+
)
41+
42+
object MethodUnderTest :
43+
CustomJavaDocTag(
44+
"utbot.methodUnderTest",
45+
"Method under test",
46+
CustomJavaDocComment::methodUnderTest,
47+
CommentWithCustomTagForTestProducedByFuzzer::methodUnderTest
48+
)
49+
50+
object ExpectedResult :
51+
CustomJavaDocTag("utbot.expectedResult", "Expected result", CustomJavaDocComment::expectedResult, null)
52+
53+
object ActualResult :
54+
CustomJavaDocTag("utbot.actualResult", "Actual result", CustomJavaDocComment::actualResult, null)
55+
56+
object Executes :
57+
CustomJavaDocTag("utbot.executesCondition", "Executes condition", CustomJavaDocComment::executesCondition, null)
58+
59+
object Invokes : CustomJavaDocTag("utbot.invokes", "Invokes", CustomJavaDocComment::invokes, null)
60+
object Iterates : CustomJavaDocTag("utbot.iterates", "Iterates", CustomJavaDocComment::iterates, null)
61+
object SwitchCase :
62+
CustomJavaDocTag("utbot.activatesSwitch", "Activates switch", CustomJavaDocComment::switchCase, null)
63+
64+
object Recursion :
65+
CustomJavaDocTag("utbot.triggersRecursion", "Triggers recursion ", CustomJavaDocComment::recursion, null)
66+
67+
object ReturnsFrom : CustomJavaDocTag("utbot.returnsFrom", "Returns from", CustomJavaDocComment::returnsFrom, null)
68+
object CaughtException :
69+
CustomJavaDocTag("utbot.caughtException", "Caught exception", CustomJavaDocComment::caughtException, null)
70+
71+
object ThrowsException :
72+
CustomJavaDocTag("utbot.throwsException", "Throws exception", CustomJavaDocComment::throwsException, null)
73+
74+
fun generateDocStatement(comment: CustomJavaDocComment): DocRegularStmt? =
75+
when (val value = valueRetriever.invoke(comment)) {
76+
is String -> value.takeIf { it.isNotEmpty() }?.let {
77+
DocRegularStmt("@$name $value\n")
78+
}
79+
is List<*> -> value.takeIf { it.isNotEmpty() }?.let {
80+
val valueToString = value.joinToString(separator = "\n", postfix = "\n") { "@$name $it" }
81+
82+
DocRegularStmt(valueToString)
83+
}
84+
else -> null
85+
}
86+
87+
// TODO: could be universal with the function above after creation of hierarchy data classes related to the comments
88+
fun generateDocStatementForTestProducedByFuzzer(comment: CommentWithCustomTagForTestProducedByFuzzer): DocRegularStmt? {
89+
if (valueRetrieverFuzzer != null) { //TODO: it required only when we have two different retrievers
90+
return when (val value = valueRetrieverFuzzer!!.invoke(comment)) { // TODO: unsafe !! - resolve
91+
is String -> value.takeIf { it.isNotEmpty() }?.let {
92+
DocRegularStmt("@$name $value\n")
93+
}
94+
95+
is List<*> -> value.takeIf { it.isNotEmpty() }?.let {
96+
val valueToString = value.joinToString(separator = ",\n", postfix = "\n")
97+
98+
DocRegularStmt("@$name $valueToString")
99+
}
100+
101+
else -> null
102+
}
103+
}
104+
return null
105+
}
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.utbot.summary.comment.customtags
2+
3+
import org.utbot.framework.plugin.api.ClassId
4+
import soot.Type
5+
6+
/**
7+
* Returns a reference to the invoked method. IDE can't resolve references to private methods in comments,
8+
* so we add @link tag only if the invoked method is not private.
9+
*
10+
* It looks like {@link packageName.className#methodName(type1, type2)}.
11+
*
12+
* In case when an enclosing class in nested, we need to replace '$' with '.'
13+
* to render the reference.
14+
*/
15+
fun getMethodReference(
16+
className: String,
17+
methodName: String,
18+
methodParameterTypes: List<Type>,
19+
isPrivate: Boolean
20+
): String {
21+
val prettyClassName: String = className.replace("$", ".")
22+
23+
val text = if (methodParameterTypes.isEmpty()) {
24+
"$prettyClassName#$methodName()"
25+
} else {
26+
val methodParametersAsString = methodParameterTypes.joinToString(",")
27+
"$prettyClassName#$methodName($methodParametersAsString)"
28+
}
29+
30+
return if (isPrivate) {
31+
text
32+
} else {
33+
"{@link $text}"
34+
}
35+
}
36+
37+
/**
38+
* Returns a reference to the class.
39+
* Replaces '$' with '.' in case a class is nested.
40+
*/
41+
fun getClassReference(fullClassName: String): String {
42+
return "{@link ${fullClassName.replace("$", ".")}}"
43+
}
44+
45+
/**
46+
* Returns a reference to the invoked method.
47+
*
48+
* It looks like {@link packageName.className#methodName(type1, type2)}.
49+
*
50+
* In case when an enclosing class in nested, we need to replace '$' with '.'
51+
* to render the reference.
52+
*/
53+
fun getMethodReferenceForFuzzingTest(className: String, methodName: String, methodParameterTypes: List<ClassId>, isPrivate: Boolean): String {
54+
val prettyClassName: String = className.replace("$", ".")
55+
56+
val text = if (methodParameterTypes.isEmpty()) {
57+
"$prettyClassName#$methodName()"
58+
} else {
59+
val methodParametersAsString = methodParameterTypes.joinToString(",") { it.canonicalName }
60+
"$prettyClassName#$methodName($methodParametersAsString)"
61+
}
62+
63+
return if (isPrivate) {
64+
text
65+
} else {
66+
"{@link $text}"
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.utbot.summary.comment.customtags.fuzzer
2+
3+
import org.utbot.summary.comment.EMPTY_STRING
4+
5+
/**
6+
* Represents a set of plugin's custom JavaDoc tags.
7+
*/
8+
data class CommentWithCustomTagForTestProducedByFuzzer(
9+
val classUnderTest: String = EMPTY_STRING,
10+
val methodUnderTest: String = EMPTY_STRING,
11+
val expectedResult: String = EMPTY_STRING,
12+
val actualResult: String = EMPTY_STRING,
13+
var returnsFrom: String = EMPTY_STRING,
14+
var throwsException: String = EMPTY_STRING
15+
)

0 commit comments

Comments
 (0)