From e88bd65849cb2d6ad5a7e09d41074b83799b8354 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Fri, 22 Jul 2022 17:04:01 +0300 Subject: [PATCH 01/29] Introduce custom plugin's JavaDoc tags #565 --- .../javadoc/UtCustomJavaDocTagProvider.kt | 48 +++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 2 + 2 files changed, 50 insertions(+) create mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt new file mode 100644 index 0000000000..26be3a0815 --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -0,0 +1,48 @@ +package org.utbot.intellij.plugin.javadoc + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiReference +import com.intellij.psi.javadoc.CustomJavadocTagProvider +import com.intellij.psi.javadoc.JavadocTagInfo +import com.intellij.psi.javadoc.PsiDocTagValue + +/** + * Provides plugin's custom JavaDoc tags to make test summaries structured. + */ +class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { + override fun getSupportedTags(): List = + listOf( + UtCustomTag.ClassUnderTest, + UtCustomTag.MethodUnderTest, + UtCustomTag.ExpectedResult, + UtCustomTag.ActualResult, + UtCustomTag.Executes, + UtCustomTag.Invokes, + UtCustomTag.ReturnsFrom, + UtCustomTag.ThrowsException, + ) + + sealed class UtCustomTag(private val name: String) : JavadocTagInfo { + override fun getName(): String = name + + override fun isInline() = false + + override fun checkTagValue(value: PsiDocTagValue?): String? = null + + override fun getReference(value: PsiDocTagValue?): PsiReference? = null + + override fun isValidInContext(element: PsiElement?): Boolean { + return element is PsiMethod + } + + object ClassUnderTest : UtCustomTag("utbot.classUnderTest") + object MethodUnderTest : UtCustomTag("utbot.methodUnderTest") + object ExpectedResult : UtCustomTag("utbot.expectedResult") + object ActualResult : UtCustomTag("utbot.actualResult") + object Executes : UtCustomTag("utbot.executes") + object Invokes : UtCustomTag("utbot.invokes") + object ReturnsFrom : UtCustomTag("utbot.returnsFrom") + object ThrowsException : UtCustomTag("utbot.throwsException") + } +} \ No newline at end of file diff --git a/utbot-intellij/src/main/resources/META-INF/plugin.xml b/utbot-intellij/src/main/resources/META-INF/plugin.xml index 87742b96f5..5e0bb93ad2 100644 --- a/utbot-intellij/src/main/resources/META-INF/plugin.xml +++ b/utbot-intellij/src/main/resources/META-INF/plugin.xml @@ -34,6 +34,8 @@ + + From 43c4cf0913bc4b4d928e62847b66bb939b6bd204 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 25 Jul 2022 17:43:43 +0300 Subject: [PATCH 02/29] Render UtBot custom JavaDoc tags correctly #565 --- .../javadoc/UtCustomJavaDocTagProvider.kt | 20 +- .../plugin/javadoc/UtDocumentationProvider.kt | 35 +++ .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 201 ++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 1 + 4 files changed, 248 insertions(+), 9 deletions(-) create mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt create mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index 26be3a0815..633a933e84 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -23,9 +23,11 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { UtCustomTag.ThrowsException, ) - sealed class UtCustomTag(private val name: String) : JavadocTagInfo { + sealed class UtCustomTag(private val name: String, private val message: String) : JavadocTagInfo { override fun getName(): String = name + fun getMessage(): String = message + override fun isInline() = false override fun checkTagValue(value: PsiDocTagValue?): String? = null @@ -36,13 +38,13 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { return element is PsiMethod } - object ClassUnderTest : UtCustomTag("utbot.classUnderTest") - object MethodUnderTest : UtCustomTag("utbot.methodUnderTest") - object ExpectedResult : UtCustomTag("utbot.expectedResult") - object ActualResult : UtCustomTag("utbot.actualResult") - object Executes : UtCustomTag("utbot.executes") - object Invokes : UtCustomTag("utbot.invokes") - object ReturnsFrom : UtCustomTag("utbot.returnsFrom") - object ThrowsException : UtCustomTag("utbot.throwsException") + object ClassUnderTest : UtCustomTag("utbot.classUnderTest", "Class under test") + object MethodUnderTest : UtCustomTag("utbot.methodUnderTest", "Method under test") + object ExpectedResult : UtCustomTag("utbot.expectedResult", "Expected result") + object ActualResult : UtCustomTag("utbot.actualResult", "Actual result") + object Executes : UtCustomTag("utbot.executes", "Executes") + object Invokes : UtCustomTag("utbot.invokes", "Invokes") + object ReturnsFrom : UtCustomTag("utbot.returnsFrom", "Returns from") + object ThrowsException : UtCustomTag("utbot.throwsException", "Throws exception") } } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt new file mode 100644 index 0000000000..6ea87ff656 --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt @@ -0,0 +1,35 @@ +package org.utbot.intellij.plugin.javadoc + +import com.intellij.codeInsight.javadoc.JavaDocExternalFilter +import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator +import com.intellij.lang.java.JavaDocumentationProvider +import com.intellij.psi.PsiDocCommentBase +import com.intellij.psi.PsiJavaDocumentedElement +import com.intellij.psi.javadoc.PsiDocComment + +/** + * To render UtBot custom JavaDoc tags correctly, we need to override the way it generates HTML tags for comments. + * We get JavaDoc info generated by IJ platform and include sections related to UTBot, + * each section relates to the specific JavaDoc tag. + * It renders text, code, and links. + */ +class UtDocumentationProvider : JavaDocumentationProvider() { + override fun generateRenderedDoc(comment: PsiDocCommentBase): String { + var target = comment.owner + if (target == null) target = comment + val docComment: PsiDocComment? + var finalJavaDoc = "" + if (target is PsiJavaDocumentedElement) { + docComment = target.docComment + if (docComment != null) { + val baseJavaDocInfoGenerator = JavaDocInfoGenerator(target.project, target) + val baseJavaDocInfo = baseJavaDocInfoGenerator.generateRenderedDocInfo() + val utJavaDocInfoGenerator = UtJavaDocInfoGenerator() + val javaDocInfoWithUtSections = + utJavaDocInfoGenerator.addUtBotSpecificSectionsToJavaDoc(baseJavaDocInfo, docComment) + finalJavaDoc = JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoWithUtSections)!! + } + } + return finalJavaDoc + } +} \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt new file mode 100644 index 0000000000..1352fe8578 --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -0,0 +1,201 @@ +package org.utbot.intellij.plugin.javadoc + +import com.intellij.codeInsight.documentation.DocumentationManagerUtil +import com.intellij.codeInsight.javadoc.JavaDocUtil +import com.intellij.lang.documentation.DocumentationMarkup +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.IndexNotReadyException +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.* +import com.intellij.psi.javadoc.PsiDocComment +import com.intellij.psi.javadoc.PsiDocTag +import com.intellij.psi.javadoc.PsiDocToken +import com.intellij.psi.javadoc.PsiInlineDocTag +import mu.KotlinLogging + +private const val LINK_TAG = "link" +private const val LINKPLAIN_TAG = "linkplain" +private const val LITERAL_TAG = "literal" +private const val CODE_TAG = "code" +private const val SYSTEM_PROPERTY_TAG = "systemProperty" +private const val MESSAGE_SEPARATOR = ":" + +private val logger = KotlinLogging.logger {} + +class UtJavaDocInfoGenerator { + /** + * Generates UtBot specific sections to include them to rendered JavaDoc comment. + */ + fun addUtBotSpecificSectionsToJavaDoc(javadoc: String?, comment: PsiDocComment): String { + val builder: StringBuilder = StringBuilder(javadoc) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ClassUnderTest) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.MethodUnderTest) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Invokes) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Executes) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ExpectedResult) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ActualResult) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ReturnsFrom) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ThrowsException) + return builder.toString() + } + + /** + * Searches for UtBot tag in the comment and generates a related section for it. + */ + private fun generateUtTagSection( + builder: StringBuilder, + comment: PsiDocComment?, + utTag: UtCustomJavaDocTagProvider.UtCustomTag + ) { + if (comment != null) { + val tag = comment.findTagByName(utTag.name) ?: return + startHeaderSection(builder, utTag.getMessage())?.append("

") + val tmp = StringBuilder() + generateValue(tmp, tag.dataElements) + builder.append(tmp.toString().trim { it <= ' ' }) + builder.append(DocumentationMarkup.SECTION_END) + } + } + + private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder? { + return builder.append(DocumentationMarkup.SECTION_HEADER_START) + .append(message) + .append(MESSAGE_SEPARATOR) + .append(DocumentationMarkup.SECTION_SEPARATOR) + } + + /** + * Generates info depending on tag's value type. + */ + private fun generateValue(builder: StringBuilder, elements: Array) { + var offset = if (elements.isNotEmpty()) { + elements[0].textOffset + elements[0].text.length + } else 0 + + for (i in elements.indices) { + if (elements[i].textOffset > offset) builder.append(' ') + offset = elements[i].textOffset + elements[i].text.length + val element = elements[i] + if (element is PsiInlineDocTag) { + when (element.name) { + LITERAL_TAG -> generateLiteralValue(builder, element) + CODE_TAG, SYSTEM_PROPERTY_TAG -> generateCodeValue(element, builder) + LINK_TAG -> generateLinkValue(element, builder, false) + LINKPLAIN_TAG -> generateLinkValue(element, builder, true) + } + } else { + appendPlainText(builder, element.text) + } + } + } + + private fun appendPlainText(builder: StringBuilder, text: String) { + builder.append(StringUtil.replaceUnicodeEscapeSequences(text)) + } + + private fun collectElementText(builder: StringBuilder, element: PsiElement) { + element.accept(object : PsiRecursiveElementWalkingVisitor() { + override fun visitElement(element: PsiElement) { + super.visitElement(element) + if (element is PsiWhiteSpace || + element is PsiJavaToken || + element is PsiDocToken && element.tokenType !== JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS + ) { + builder.append(element.text) + } + } + }) + } + + private fun generateCodeValue(tag: PsiInlineDocTag, builder: StringBuilder) { + builder.append("") + val pos = builder.length + generateLiteralValue(builder, tag) + builder.append("") + if (builder[pos] == '\n') builder.insert( + pos, + ' ' + ) // line break immediately after opening tag is ignored by JEditorPane + } + + private fun generateLiteralValue(builder: StringBuilder, tag: PsiDocTag) { + val tmpBuilder = StringBuilder() + val children = tag.children + for (i in 2 until children.size - 1) { // process all children except tag opening/closing elements + val child = children[i] + if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) continue + var elementText = child.text + if (child is PsiWhiteSpace) { + val pos = elementText.lastIndexOf('\n') + if (pos >= 0) elementText = elementText.substring(0, pos + 1) // skip whitespace before leading asterisk + } + appendPlainText(tmpBuilder, StringUtil.escapeXmlEntities(elementText)) + } + builder.append(StringUtil.trimLeading(tmpBuilder)) + } + + private fun generateLinkValue(tag: PsiInlineDocTag, builder: StringBuilder, plainLink: Boolean) { + val tagElements = tag.dataElements + val linkText: String = createLinkText(tagElements) + if (linkText.isNotEmpty()) { + val index = JavaDocUtil.extractReference(linkText) + val referenceText = linkText.substring(0, index).trim { it <= ' ' } + val label = StringUtil.nullize(linkText.substring(index).trim { it <= ' ' }) + generateLink(builder, referenceText, label, tagElements[0], plainLink) + } + } + + private fun createLinkText(tagElements: Array): String { + var offset = if (tagElements.isNotEmpty()) { + tagElements[0].textOffset + tagElements[0].text.length + } else { + 0 + } + + val builder = StringBuilder() + for (i in tagElements.indices) { + val tagElement = tagElements[i] + if (tagElement.textOffset > offset) builder.append(' ') + offset = tagElement.textOffset + tagElement.text.length + collectElementText(builder, tagElement) + if (i < tagElements.size - 1) { + builder.append(' ') + } + } + return builder.toString().trim { it <= ' ' } + } + + private fun generateLink( + builder: StringBuilder, + refText: String?, + label: String?, + context: PsiElement, + plainLink: Boolean + ) { + var linkLabel = label + if (label == null) { + val manager = context.manager + linkLabel = JavaDocUtil.getLabelText(manager.project, manager, refText, context) + } + + var target: PsiElement? = null + try { + if (refText != null) { + target = JavaDocUtil.findReferenceTarget(context.manager, refText, context) + } + } catch (e: IndexNotReadyException) { + logger.info(e) { "Failed to find a reference while generating JavaDoc comment. Details: ${e.message}" } + } + + if (target == null && DumbService.isDumb(context.project)) { + builder.append(linkLabel) + } else if (target == null) { + builder.append("").append(linkLabel).append("") + } else { + val referenceText = JavaDocUtil.getReferenceText(target.project, target) + if (referenceText != null) { + DocumentationManagerUtil.createHyperlink(builder, target, referenceText, linkLabel, plainLink) + } + } + } +} \ No newline at end of file diff --git a/utbot-intellij/src/main/resources/META-INF/plugin.xml b/utbot-intellij/src/main/resources/META-INF/plugin.xml index 5e0bb93ad2..ee853869d9 100644 --- a/utbot-intellij/src/main/resources/META-INF/plugin.xml +++ b/utbot-intellij/src/main/resources/META-INF/plugin.xml @@ -36,6 +36,7 @@ + From 760594ff5cc05c1224550c02ff92adba27f88e19 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 26 Jul 2022 18:46:23 +0300 Subject: [PATCH 03/29] Add an option to generate summaries using custom JavaDoc tags #565 --- .../kotlin/org/utbot/framework/UtSettings.kt | 2 +- .../model/visitor/CgAbstractRenderer.kt | 3 - .../javadoc/UtCustomJavaDocTagProvider.kt | 2 + .../kotlin/org/utbot/summary/Summarization.kt | 8 +- .../org/utbot/summary/UtSummarySettings.kt | 5 + .../summary/comment/CustomJavaDocComment.kt | 16 ++++ .../comment/CustomJavaDocCommentBuilder.kt | 93 +++++++++++++++++++ .../comment/SimpleClusterCommentBuilder.kt | 4 +- .../summary/comment/SimpleCommentBuilder.kt | 51 ++++++---- 9 files changed, 158 insertions(+), 26 deletions(-) create mode 100644 utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt create mode 100644 utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt index a44941c8a0..fde2cd6cbb 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt @@ -269,7 +269,7 @@ object UtSettings { /** * Set to true to start fuzzing if symbolic execution haven't return anything */ - var useFuzzing: Boolean by getBooleanProperty(true) + var useFuzzing: Boolean by getBooleanProperty(false) /** * Set the total attempts to improve coverage by fuzzer. diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt index 92e4aebf78..57d73a5c86 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt @@ -309,10 +309,7 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer: } override fun visit(element: CgDocPreTagStatement) { if (element.content.all { it.isEmpty() }) return - - println("

")
         for (stmt in element.content) stmt.accept(this)
-        println("
") } override fun visit(element: CgDocCodeStmt) { if (element.isEmpty()) return diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index 633a933e84..8e35c40669 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -19,6 +19,7 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { UtCustomTag.ActualResult, UtCustomTag.Executes, UtCustomTag.Invokes, + UtCustomTag.Iterates, UtCustomTag.ReturnsFrom, UtCustomTag.ThrowsException, ) @@ -44,6 +45,7 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { object ActualResult : UtCustomTag("utbot.actualResult", "Actual result") object Executes : UtCustomTag("utbot.executes", "Executes") object Invokes : UtCustomTag("utbot.invokes", "Invokes") + object Iterates : UtCustomTag("utbot.iterates", "Iterates") object ReturnsFrom : UtCustomTag("utbot.returnsFrom", "Returns from") object ThrowsException : UtCustomTag("utbot.throwsException", "Throws exception") } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt index b247d9c978..4f947cd0d1 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt @@ -5,6 +5,7 @@ import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.UtClusterInfo import org.utbot.framework.plugin.api.UtSymbolicExecution import org.utbot.framework.plugin.api.UtExecutionCluster +import org.utbot.framework.plugin.api.UtExecutionCreator import org.utbot.framework.plugin.api.UtMethodTestSet import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter import org.utbot.summary.SummarySentenceConstants.NEW_LINE @@ -28,6 +29,8 @@ import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.UtFuzzedExecution import org.utbot.summary.fuzzer.names.MethodBasedNameSuggester import org.utbot.summary.fuzzer.names.ModelBasedNameSuggester +import org.utbot.summary.UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS +import org.utbot.summary.comment.CustomJavaDocCommentBuilder import soot.SootMethod private val logger = KotlinLogging.logger {} @@ -154,7 +157,10 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List +) : SimpleCommentBuilder(traceTag, sootToAST, stringTemplates = StringsTemplatesPlural()) { + + /** + * Collects statements for final JavaDoc comment. + */ + fun buildDocStatements(method: SootMethod): List { + val comment: CustomJavaDocComment = buildCustomJavaDocComment(method) + val docStatementList = mutableListOf() + + docStatementList += DocRegularStmt("@utbot.classUnderTest ${comment.classUnderTest}\n") + docStatementList += DocRegularStmt("@utbot.methodUnderTest ${comment.methodUnderTest}\n") + if (comment.expectedResult != null) + docStatementList += DocRegularStmt("@utbot.expectedResult ${comment.expectedResult}\n") + if (comment.actualResult != null) + docStatementList += DocRegularStmt("@utbot.actualResult ${comment.actualResult}\n") + if (comment.executes != null) + docStatementList += DocRegularStmt("@utbot.executes ${comment.executes}\n") + if (comment.invokes != null) + docStatementList += DocRegularStmt("@utbot.invokes ${comment.invokes}\n") + if (comment.iterates != null) + docStatementList += DocRegularStmt("@utbot.iterates ${comment.iterates}\n") + if (comment.returnsFrom != null) + docStatementList += DocRegularStmt("@utbot.returnsFrom ${comment.returnsFrom}\n") + if (comment.throwsException != null) + docStatementList += DocRegularStmt("@utbot.throwsException ${comment.throwsException}") + + return listOf(DocPreTagStatement(docStatementList)) + } + + private fun buildCustomJavaDocComment(currentMethod: SootMethod): CustomJavaDocComment { + val methodReference = + getMethodReference(currentMethod.declaringClass.name, currentMethod.name, currentMethod.parameterTypes) + val classReference = getClassReference(currentMethod.declaringClass.javaStyleName) + + val thrownException = traceTag.result.exceptionOrNull() + val exceptionThrow: String? = if (thrownException == null) { + traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } + } else { + val exceptionName = thrownException.javaClass.simpleName + val reason = findExceptionReason(currentMethod, thrownException) + "{@link $exceptionName} $reason" + } + + val customJavaDocComment = CustomJavaDocComment( + classUnderTest = classReference, + methodUnderTest = methodReference, + expectedResult = null, + actualResult = null, + executes = null, + invokes = null, + iterates = null, + returnsFrom = null, + throwsException = exceptionThrow + ) + + val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) + + buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) + + for (stmtDescription: StmtDescription in rootSentenceBlock.stmtTexts) { + when (stmtDescription.stmtType.name) { + "Invoke" -> { + val info = stmtDescription.description + customJavaDocComment.invokes = "{@code $info}" + } + "Return" -> { + val info = stmtDescription.description + customJavaDocComment.returnsFrom = "{@code $info}" + } + "Condition" -> { + val info = stmtDescription.description + customJavaDocComment.executes = "{@code $info}" + } + } + } + + return customJavaDocComment + } +} \ No newline at end of file diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleClusterCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleClusterCommentBuilder.kt index 829308ed02..3c1328e1ad 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleClusterCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleClusterCommentBuilder.kt @@ -63,7 +63,7 @@ class SimpleClusterCommentBuilder( * Builds sentence blocks as parent one, * but ignores few types of statementTag that are considered in SimpleCommentBuilder */ - private fun buildSentenceBlock( + override fun buildSentenceBlock( statementTag: StatementTag?, sentenceBlock: SimpleSentenceBlock, currentMethod: SootMethod @@ -93,7 +93,7 @@ class SimpleClusterCommentBuilder( sentenceInvoke.squashStmtText() if (!sentenceInvoke.isEmpty()) { sentenceBlock.invokeSentenceBlock = - Pair(invokeDescription(className, methodName, methodParameterTypes), sentenceInvoke) + Pair(getMethodReference(className, methodName, methodParameterTypes), sentenceInvoke) createNextBlock = true invokeRegistered = true } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index eab1d0d3e6..d291aa197b 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -62,22 +62,11 @@ open class SimpleCommentBuilder( } /** - * Creates List from SimpleSentenceBlock + * Creates List<[DocStatement]> from [SimpleSentenceBlock]. */ open fun buildDocStmts(currentMethod: SootMethod): List { - val root = SimpleSentenceBlock(stringTemplates = stringTemplates) - - val thrownException = traceTag.result.exceptionOrNull() - if (thrownException == null) { - root.exceptionThrow = traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } - } else { - val exceptionName = thrownException.javaClass.simpleName - val reason = findExceptionReason(currentMethod, thrownException) - root.exceptionThrow = "$exceptionName $reason" - } - skippedIterations() - buildSentenceBlock(traceTag.rootStatementTag, root, currentMethod) - val docStmts = toDocStmts(root) + val sentenceBlock = buildSentenceBlock(currentMethod) + val docStmts = toDocStmts(sentenceBlock) if (docStmts.isEmpty()) { return listOf(DocRegularStmt(genWarnNotification())) //TODO SAT-1310 @@ -88,6 +77,22 @@ open class SimpleCommentBuilder( return listOf(DocPreTagStatement(docStmts)) } + private fun buildSentenceBlock(currentMethod: SootMethod): SimpleSentenceBlock { + val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) + + val thrownException = traceTag.result.exceptionOrNull() + if (thrownException == null) { + rootSentenceBlock.exceptionThrow = traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } + } else { + val exceptionName = thrownException.javaClass.simpleName + val reason = findExceptionReason(currentMethod, thrownException) + rootSentenceBlock.exceptionThrow = "$exceptionName $reason" + } + skippedIterations() + buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) + return rootSentenceBlock + } + protected fun genWarnNotification(): String = " " //why is it empty? /** @@ -114,7 +119,7 @@ open class SimpleCommentBuilder( return stmts } - private fun findExceptionReason(currentMethod: SootMethod, thrownException: Throwable): String { + fun findExceptionReason(currentMethod: SootMethod, thrownException: Throwable): String { val path = traceTag.path if (path.isEmpty()) { if (thrownException is ConcreteExecutionFailureException) { @@ -161,7 +166,7 @@ open class SimpleCommentBuilder( /** * Sentence blocks are built based on unique and partly unique statement tags. */ - private fun buildSentenceBlock( + open fun buildSentenceBlock( statementTag: StatementTag?, sentenceBlock: SimpleSentenceBlock, currentMethod: SootMethod @@ -191,7 +196,7 @@ open class SimpleCommentBuilder( sentenceInvoke.squashStmtText() if (!sentenceInvoke.isEmpty()) { sentenceBlock.invokeSentenceBlock = - Pair(invokeDescription(className, methodName, methodParameterTypes), sentenceInvoke) + Pair(getMethodReference(className, methodName, methodParameterTypes), sentenceInvoke) createNextBlock = true invokeRegistered = true } @@ -317,7 +322,7 @@ open class SimpleCommentBuilder( sentenceBlock.stmtTexts.add( StmtDescription( StmtType.Invoke, - invokeDescription(className, methodName, methodParameterTypes), + getMethodReference(className, methodName, methodParameterTypes), frequency ) ) @@ -349,7 +354,7 @@ open class SimpleCommentBuilder( * In case when an enclosing class in nested, we need to replace '$' with '.' * to render the reference. */ - fun invokeDescription(className: String, methodName: String, methodParameterTypes: List): String { + protected fun getMethodReference(className: String, methodName: String, methodParameterTypes: List): String { val prettyClassName: String = className.replace("$", ".") return if (methodParameterTypes.isEmpty()) { @@ -360,6 +365,14 @@ open class SimpleCommentBuilder( } } + /** + * Returns a reference to the class. + * Replaces '$' with '.' in case a class is nested. + */ + fun getClassReference(fullClasName: String): String { + return "{@link ${fullClasName.replace("$", ".")}}" + } + protected fun buildIterationsBlock( iterations: List, activatedStep: Step, From 050550fd3816b75df37c5719977226cf74891254 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Wed, 27 Jul 2022 18:31:40 +0300 Subject: [PATCH 04/29] Fill value of utbot.iterates tag #565 --- .../javadoc/UtCustomJavaDocTagProvider.kt | 2 +- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 1 + .../summary/comment/CustomJavaDocComment.kt | 4 +- .../comment/CustomJavaDocCommentBuilder.kt | 45 ++++++++++++------- .../summary/comment/SimpleCommentBuilder.kt | 4 +- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index 8e35c40669..a7fe326a30 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -43,7 +43,7 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { object MethodUnderTest : UtCustomTag("utbot.methodUnderTest", "Method under test") object ExpectedResult : UtCustomTag("utbot.expectedResult", "Expected result") object ActualResult : UtCustomTag("utbot.actualResult", "Actual result") - object Executes : UtCustomTag("utbot.executes", "Executes") + object Executes : UtCustomTag("utbot.executesCondition", "Executes condition") object Invokes : UtCustomTag("utbot.invokes", "Invokes") object Iterates : UtCustomTag("utbot.iterates", "Iterates") object ReturnsFrom : UtCustomTag("utbot.returnsFrom", "Returns from") diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index 1352fe8578..348d2b0540 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -32,6 +32,7 @@ class UtJavaDocInfoGenerator { generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.MethodUnderTest) generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Invokes) generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Executes) + generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Iterates) generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ExpectedResult) generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ActualResult) generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ReturnsFrom) diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt index eed982b4ab..724e964332 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt @@ -8,9 +8,9 @@ data class CustomJavaDocComment( val methodUnderTest: String, val expectedResult: String?, val actualResult: String?, - var executes: String?, + var executesCondition: String?, var invokes: String?, var iterates: String?, var returnsFrom: String?, - val throwsException: String? + var throwsException: String? ) \ No newline at end of file diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index e6141bed4a..ee2e04d194 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -27,8 +27,8 @@ class CustomJavaDocCommentBuilder( docStatementList += DocRegularStmt("@utbot.expectedResult ${comment.expectedResult}\n") if (comment.actualResult != null) docStatementList += DocRegularStmt("@utbot.actualResult ${comment.actualResult}\n") - if (comment.executes != null) - docStatementList += DocRegularStmt("@utbot.executes ${comment.executes}\n") + if (comment.executesCondition != null) + docStatementList += DocRegularStmt("@utbot.executesCondition ${comment.executesCondition}\n") if (comment.invokes != null) docStatementList += DocRegularStmt("@utbot.invokes ${comment.invokes}\n") if (comment.iterates != null) @@ -46,33 +46,47 @@ class CustomJavaDocCommentBuilder( getMethodReference(currentMethod.declaringClass.name, currentMethod.name, currentMethod.parameterTypes) val classReference = getClassReference(currentMethod.declaringClass.javaStyleName) - val thrownException = traceTag.result.exceptionOrNull() - val exceptionThrow: String? = if (thrownException == null) { - traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } - } else { - val exceptionName = thrownException.javaClass.simpleName - val reason = findExceptionReason(currentMethod, thrownException) - "{@link $exceptionName} $reason" - } - val customJavaDocComment = CustomJavaDocComment( classUnderTest = classReference, methodUnderTest = methodReference, expectedResult = null, actualResult = null, - executes = null, + executesCondition = null, invokes = null, iterates = null, returnsFrom = null, - throwsException = exceptionThrow + throwsException = null ) - val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) + // build throws exception section + val thrownException = traceTag.result.exceptionOrNull() + val exceptionThrow: String? = if (thrownException == null) { + traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } + } else { + val exceptionName = thrownException.javaClass.simpleName + val reason = findExceptionReason(currentMethod, thrownException) + "{@link $exceptionName} $reason" + } + customJavaDocComment.throwsException = exceptionThrow + val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) + skippedIterations() buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) + // builds iterates section + rootSentenceBlock.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) -> + customJavaDocComment.iterates = stringTemplates.iterationSentence.format( + stringTemplates.codeSentence.format(loopDesc), + numberOccurrencesToText( + sentenceBlocks.size + ) + ) + } + + // build invokes, executes, and returns from sections for (stmtDescription: StmtDescription in rootSentenceBlock.stmtTexts) { when (stmtDescription.stmtType.name) { + //TODO: support multiple invokes (calls) "Invoke" -> { val info = stmtDescription.description customJavaDocComment.invokes = "{@code $info}" @@ -81,9 +95,10 @@ class CustomJavaDocCommentBuilder( val info = stmtDescription.description customJavaDocComment.returnsFrom = "{@code $info}" } + //TODO: support multiple conditions "Condition" -> { val info = stmtDescription.description - customJavaDocComment.executes = "{@code $info}" + customJavaDocComment.executesCondition = "{@code $info}" } } } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index d291aa197b..8e2921d22b 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -154,8 +154,8 @@ open class SimpleCommentBuilder( if (exceptionNode == null) return "" reason += when { - exceptionNode is IfStmt -> exceptionNode.condition.toString() - isLoopStatement(exceptionNode) -> getTextIterationDescription(exceptionNode) + exceptionNode is IfStmt -> "{@code ${exceptionNode.condition}}" + isLoopStatement(exceptionNode) -> "{@code ${getTextIterationDescription(exceptionNode)}" exceptionNode is SwitchStmt -> textSwitchCase(step, jimpleToASTMap) else -> exceptionNode.toString() } From ca86976f0794d67a7d5221f3ab8a708ef8b84c60 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Thu, 28 Jul 2022 23:30:40 +0300 Subject: [PATCH 05/29] Collect info about Invoke, Iterate, and Return sections #565 --- .../summary/comment/CustomJavaDocComment.kt | 18 ++-- .../comment/CustomJavaDocCommentBuilder.kt | 98 +++++++++++-------- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt index 724e964332..55250e8ad5 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocComment.kt @@ -4,13 +4,13 @@ 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?, - var executesCondition: String?, - var invokes: String?, - var iterates: String?, - var returnsFrom: String?, - var throwsException: String? + val classUnderTest: String = "", + val methodUnderTest: String = "", + val expectedResult: String = "", + val actualResult: String = "", + var executesCondition: List = listOf(), + var invokes: List = listOf(), + var iterates: List = listOf(), + var returnsFrom: String = "", + var throwsException: String = "" ) \ No newline at end of file diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index ee2e04d194..fb8078094e 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -23,42 +23,51 @@ class CustomJavaDocCommentBuilder( docStatementList += DocRegularStmt("@utbot.classUnderTest ${comment.classUnderTest}\n") docStatementList += DocRegularStmt("@utbot.methodUnderTest ${comment.methodUnderTest}\n") - if (comment.expectedResult != null) + + if (comment.expectedResult.isNotEmpty()) docStatementList += DocRegularStmt("@utbot.expectedResult ${comment.expectedResult}\n") - if (comment.actualResult != null) + if (comment.actualResult.isNotEmpty()) docStatementList += DocRegularStmt("@utbot.actualResult ${comment.actualResult}\n") - if (comment.executesCondition != null) - docStatementList += DocRegularStmt("@utbot.executesCondition ${comment.executesCondition}\n") - if (comment.invokes != null) - docStatementList += DocRegularStmt("@utbot.invokes ${comment.invokes}\n") - if (comment.iterates != null) - docStatementList += DocRegularStmt("@utbot.iterates ${comment.iterates}\n") - if (comment.returnsFrom != null) + if (comment.executesCondition.isNotEmpty()) { + val statement = + "@utbot.executesCondition ${comment.executesCondition.joinToString(separator = ",\n")}\n" + docStatementList += DocRegularStmt(statement) + } + if (comment.invokes.isNotEmpty()) { + val statement = "@utbot.invokes ${comment.invokes.joinToString(separator = ",\n")}\n" + docStatementList += DocRegularStmt(statement) + } + if (comment.iterates.isNotEmpty()) { + val statement = "@utbot.iterates ${comment.iterates.joinToString(separator = ",\n")}\n" + docStatementList += DocRegularStmt(statement) + } + if (comment.returnsFrom.isNotEmpty()) docStatementList += DocRegularStmt("@utbot.returnsFrom ${comment.returnsFrom}\n") - if (comment.throwsException != null) + if (comment.throwsException.isNotEmpty()) docStatementList += DocRegularStmt("@utbot.throwsException ${comment.throwsException}") return listOf(DocPreTagStatement(docStatementList)) } private fun buildCustomJavaDocComment(currentMethod: SootMethod): CustomJavaDocComment { - val methodReference = - getMethodReference(currentMethod.declaringClass.name, currentMethod.name, currentMethod.parameterTypes) + val methodReference = getMethodReference( + currentMethod.declaringClass.name, + currentMethod.name, + currentMethod.parameterTypes + ) val classReference = getClassReference(currentMethod.declaringClass.javaStyleName) val customJavaDocComment = CustomJavaDocComment( classUnderTest = classReference, methodUnderTest = methodReference, - expectedResult = null, - actualResult = null, - executesCondition = null, - invokes = null, - iterates = null, - returnsFrom = null, - throwsException = null ) - // build throws exception section + val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) + skippedIterations() + buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) + rootSentenceBlock.squashStmtText() + + // builds Throws exception section val thrownException = traceTag.result.exceptionOrNull() val exceptionThrow: String? = if (thrownException == null) { traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } @@ -67,15 +76,13 @@ class CustomJavaDocCommentBuilder( val reason = findExceptionReason(currentMethod, thrownException) "{@link $exceptionName} $reason" } - customJavaDocComment.throwsException = exceptionThrow - - val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) - skippedIterations() - buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) + if (exceptionThrow != null) { + customJavaDocComment.throwsException = exceptionThrow + } - // builds iterates section + // builds Iterates section rootSentenceBlock.iterationSentenceBlocks.forEach { (loopDesc, sentenceBlocks) -> - customJavaDocComment.iterates = stringTemplates.iterationSentence.format( + customJavaDocComment.iterates += stringTemplates.iterationSentence.format( stringTemplates.codeSentence.format(loopDesc), numberOccurrencesToText( sentenceBlocks.size @@ -83,24 +90,29 @@ class CustomJavaDocCommentBuilder( ) } - // build invokes, executes, and returns from sections - for (stmtDescription: StmtDescription in rootSentenceBlock.stmtTexts) { - when (stmtDescription.stmtType.name) { - //TODO: support multiple invokes (calls) - "Invoke" -> { - val info = stmtDescription.description - customJavaDocComment.invokes = "{@code $info}" - } - "Return" -> { - val info = stmtDescription.description - customJavaDocComment.returnsFrom = "{@code $info}" - } - //TODO: support multiple conditions - "Condition" -> { - val info = stmtDescription.description - customJavaDocComment.executesCondition = "{@code $info}" + // builds Invoke, Execute, Return sections + var currentBlock: SimpleSentenceBlock? = rootSentenceBlock + while (currentBlock != null) { + for (statement in currentBlock.stmtTexts) { + when (statement.stmtType) { + StmtType.Invoke -> { + val info = statement.description + customJavaDocComment.invokes += "{@code $info}" + } + StmtType.Condition -> { + val info = statement.description + customJavaDocComment.executesCondition += "{@code $info}" + } + StmtType.Return -> { + val info = statement.description + customJavaDocComment.returnsFrom = "{@code $info}" + } + else -> { + //TODO + } } } + currentBlock = currentBlock.nextBlock } return customJavaDocComment From d77e73968882cfd09bb388a6082a9ce3f7fea45a Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 1 Aug 2022 17:04:56 +0300 Subject: [PATCH 06/29] Review fixes --- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index 348d2b0540..b79ffe8134 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -51,9 +51,11 @@ class UtJavaDocInfoGenerator { if (comment != null) { val tag = comment.findTagByName(utTag.name) ?: return startHeaderSection(builder, utTag.getMessage())?.append("

") - val tmp = StringBuilder() - generateValue(tmp, tag.dataElements) - builder.append(tmp.toString().trim { it <= ' ' }) + val sectionContent = buildString { + generateValue(this, tag.dataElements) + this.trim { it <= ' ' } + } + builder.append(sectionContent) builder.append(DocumentationMarkup.SECTION_END) } } @@ -120,19 +122,21 @@ class UtJavaDocInfoGenerator { } private fun generateLiteralValue(builder: StringBuilder, tag: PsiDocTag) { - val tmpBuilder = StringBuilder() - val children = tag.children - for (i in 2 until children.size - 1) { // process all children except tag opening/closing elements - val child = children[i] - if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) continue - var elementText = child.text - if (child is PsiWhiteSpace) { - val pos = elementText.lastIndexOf('\n') - if (pos >= 0) elementText = elementText.substring(0, pos + 1) // skip whitespace before leading asterisk + val literalValue = buildString { + val children = tag.children + for (i in 2 until children.size - 1) { // process all children except tag opening/closing elements + val child = children[i] + if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) continue + var elementText = child.text + if (child is PsiWhiteSpace) { + val pos = elementText.lastIndexOf('\n') + if (pos >= 0) elementText = + elementText.substring(0, pos + 1) // skip whitespace before leading asterisk + } + appendPlainText(this, StringUtil.escapeXmlEntities(elementText)) } - appendPlainText(tmpBuilder, StringUtil.escapeXmlEntities(elementText)) } - builder.append(StringUtil.trimLeading(tmpBuilder)) + builder.append(StringUtil.trimLeading(literalValue)) } private fun generateLinkValue(tag: PsiInlineDocTag, builder: StringBuilder, plainLink: Boolean) { @@ -153,17 +157,17 @@ class UtJavaDocInfoGenerator { 0 } - val builder = StringBuilder() - for (i in tagElements.indices) { - val tagElement = tagElements[i] - if (tagElement.textOffset > offset) builder.append(' ') - offset = tagElement.textOffset + tagElement.text.length - collectElementText(builder, tagElement) - if (i < tagElements.size - 1) { - builder.append(' ') + return buildString { + for (i in tagElements.indices) { + val tagElement = tagElements[i] + if (tagElement.textOffset > offset) this.append(' ') + offset = tagElement.textOffset + tagElement.text.length + collectElementText(this, tagElement) + if (i < tagElements.size - 1) { + this.append(' ') + } } - } - return builder.toString().trim { it <= ' ' } + }.trim { it <= ' ' } } private fun generateLink( From 6ae11571049bbc19ca588994a1eb8698a07f58c7 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 2 Aug 2022 19:47:33 +0300 Subject: [PATCH 07/29] Add unit tests for summaries with custom JavaDoc tags #565 --- .../examples/SummaryTestCaseGeneratorTest.kt | 44 +++++++++++ .../controlflow/SummaryConditionsTest.kt | 51 +++++++++++++ .../SummaryExceptionClusteringExamplesTest.kt | 74 +++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt create mode 100644 utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index 6ed631a6ca..d687fb0eb7 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -11,6 +11,7 @@ import org.utbot.framework.UtSettings.checkSolverTimeoutMillis import org.utbot.framework.codegen.TestExecution import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.UtContext +import org.utbot.summary.UtSummarySettings import org.utbot.summary.comment.nextSynonyms import org.utbot.summary.summarize import kotlin.reflect.KClass @@ -56,6 +57,7 @@ open class SummaryTestCaseGeneratorTest( checkSolverTimeoutMillis = 0 checkNpeInNestedMethods = true checkNpeInNestedNotPrivateMethods = true + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = false } val utMethod = UtMethod.from(method) val testSet = executionsModel(utMethod, mockStrategy) @@ -67,6 +69,34 @@ open class SummaryTestCaseGeneratorTest( testSetWithSummarization.checkClusterInfo(clusterInfo) } + /** + * Checks summaries containing custom JavaDoc tags. + */ + inline fun checkSummariesWithCustomTags( + method: KFunction, + mockStrategy: MockStrategyApi, + coverageMatcher: CoverageMatcher, + summaryKeys: List, + methodNames: List, + displayNames: List + ) { + workaround(WorkaroundReason.HACK) { + // @todo change to the constructor parameter + checkSolverTimeoutMillis = 0 + checkNpeInNestedMethods = true + checkNpeInNestedNotPrivateMethods = true + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = true + } + val utMethod = UtMethod.from(method) + val testSet = executionsModel(utMethod, mockStrategy) + testSet.summarize(searchDirectory) + testSet.clustersInfo + + testSet.executions.checkMatchersWithCustomTagsInSummary(summaryKeys) + testSet.executions.checkMatchersWithMethodNames(methodNames) + testSet.executions.checkMatchersWithDisplayNames(displayNames) + } + /** * It removes from the String all whitespaces, tabs etc. * @@ -160,6 +190,20 @@ open class SummaryTestCaseGeneratorTest( } } + fun List.checkMatchersWithCustomTagsInSummary( + summaryTextKeys: List, + ) { + if (summaryTextKeys.isEmpty()) { + return + } + val notMatchedExecutions = this.filter { execution -> + summaryTextKeys.none { summaryKey -> + execution.summary?.toString()?.contains(summaryKey) == true + } + } + Assertions.assertTrue(notMatchedExecutions.isEmpty()) { "Not matched comments ${summaries(notMatchedExecutions)}" } + } + fun List.checkMatchersWithMethodNames( methodNames: List, ) { diff --git a/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt new file mode 100644 index 0000000000..0fa3319a99 --- /dev/null +++ b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt @@ -0,0 +1,51 @@ +package examples.controlflow + +import examples.SummaryTestCaseGeneratorTest +import org.junit.jupiter.api.Test +import org.utbot.examples.DoNotCalculate +import org.utbot.examples.controlflow.Conditions +import org.utbot.framework.plugin.api.MockStrategyApi + +class SummaryConditionsTest : SummaryTestCaseGeneratorTest( + Conditions::class +) { + @Test + fun testSimpleCondition() { + val summary1 = "@utbot.classUnderTest {@link Conditions}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Conditions#simpleCondition(boolean)}\n" + + "@utbot.executesCondition {@code (condition): False}\n" + + "@utbot.returnsFrom {@code return 0;}" + + val summary2 = "@utbot.classUnderTest {@link Conditions}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.controlflow.Conditions#simpleCondition(boolean)}\n" + + "@utbot.executesCondition {@code (condition): True}\n" + + "@utbot.returnsFrom {@code return 1;}" + + val methodName1 = "testSimpleCondition_NotCondition" + val methodName2 = "testSimpleCondition_Condition" + + val displayName1 = "condition : False -> return 0" + val displayName2 = "condition : True -> return 1" + + val summaryKeys = listOf( + summary1, + summary2 + ) + + val displayNames = listOf( + displayName1, + displayName2 + ) + + val methodNames = listOf( + methodName1, + methodName2 + ) + + val method = Conditions::simpleCondition + val mockStrategy = MockStrategyApi.NO_MOCKS + val coverage = DoNotCalculate + + checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + } +} \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt new file mode 100644 index 0000000000..66e1d88ae8 --- /dev/null +++ b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt @@ -0,0 +1,74 @@ +package examples.exceptions + +import examples.SummaryTestCaseGeneratorTest +import org.junit.jupiter.api.Test +import org.utbot.examples.DoNotCalculate +import org.utbot.examples.exceptions.ExceptionClusteringExamples +import org.utbot.framework.plugin.api.MockStrategyApi + +class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( + ExceptionClusteringExamples::class +) { + @Test + fun testDifferentExceptions() { + val summary1 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + + "@utbot.executesCondition {@code (i == 0): True}\n" + + "@utbot.throwsException {@link ArithmeticException} in: return 100 / i;" + + val summary2 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + + "@utbot.executesCondition {@code (i == 0): False},\n" + + "{@code (i == 1): True}\n" + + "@utbot.throwsException {@link MyCheckedException} after condition: {@code i == 1}" + val summary3 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + + "@utbot.executesCondition {@code (i == 0): False},\n" + + "{@code (i == 1): False},\n" + + "{@code (i == 2): True}\n" + + "@utbot.throwsException {@link IllegalArgumentException} after condition: {@code i == 2}" + val summary4 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + + "@utbot.executesCondition {@code (i == 0): False},\n" + + "{@code (i == 1): False},\n" + + "{@code (i == 2): False}\n" + + "@utbot.returnsFrom {@code return i * 2;}\n" + + val methodName1 = "testDifferentExceptions_IEqualsZero" + val methodName2 = "testDifferentExceptions_IEquals1" + val methodName3 = "testDifferentExceptions_IEquals2" + val methodName4 = "testDifferentExceptions_INotEquals2" + + val displayName1 = "return 100 / i : True -> ThrowArithmeticException" + val displayName2 = "i == 1 -> ThrowMyCheckedException" + val displayName3 = "i == 2 -> ThrowIllegalArgumentException" + val displayName4 = "i == 0 : False -> return i * 2" + + val summaryKeys = listOf( + summary1, + summary2, + summary3, + summary4 + ) + + val displayNames = listOf( + displayName1, + displayName2, + displayName3, + displayName4 + ) + + val methodNames = listOf( + methodName1, + methodName2, + methodName3, + methodName4 + ) + + val method = ExceptionClusteringExamples::differentExceptions + val mockStrategy = MockStrategyApi.NO_MOCKS + val coverage = DoNotCalculate + + checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + } +} \ No newline at end of file From 100e3df33c34f8d92dfb7656d8c1776c5de70ada Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Thu, 4 Aug 2022 01:34:47 +0300 Subject: [PATCH 08/29] Fix after rebasing --- .../examples/SummaryTestCaseGeneratorTest.kt | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index d687fb0eb7..a64dd3e2d6 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -191,17 +191,49 @@ open class SummaryTestCaseGeneratorTest( } fun List.checkMatchersWithCustomTagsInSummary( - summaryTextKeys: List, + comments: List ) { - if (summaryTextKeys.isEmpty()) { + if (comments.isEmpty()) { return } + val notMatchedExecutions = this.filter { execution -> - summaryTextKeys.none { summaryKey -> - execution.summary?.toString()?.contains(summaryKey) == true + comments.none { comment -> + execution.summary?.toString()?.contains(comment) == true + } + } + + val notMatchedComments = comments.filter { comment -> + this.none { execution -> + execution.summary?.toString()?.contains(comment) == true + } + } + + Assertions.assertTrue(notMatchedExecutions.isEmpty() && notMatchedComments.isEmpty()) { + buildString { + if (notMatchedExecutions.isNotEmpty()) { + append( + "\nThe following comments were produced by the UTBot, " + + "but were not found in the list of comments passed in the check() method:\n\n${ + commentsFromExecutions( + notMatchedExecutions + ) + }" + ) + } + + if (notMatchedComments.isNotEmpty()) { + append( + "\nThe following comments were passed in the check() method, " + + "but were not found in the list of comments produced by the UTBot:\n\n${ + comments( + notMatchedComments + ) + }" + ) + } } } - Assertions.assertTrue(notMatchedExecutions.isEmpty()) { "Not matched comments ${summaries(notMatchedExecutions)}" } } fun List.checkMatchersWithMethodNames( From 8d4063ba2d4c3ad5ce0424f302b2c14009fd5ef8 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Thu, 4 Aug 2022 02:27:02 +0300 Subject: [PATCH 09/29] Add summary tests for MinStack #565 --- .../structures/SummaryMinStackTest.kt | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt diff --git a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt new file mode 100644 index 0000000000..3744d9423d --- /dev/null +++ b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt @@ -0,0 +1,202 @@ +package examples.structures + +import examples.SummaryTestCaseGeneratorTest +import org.junit.jupiter.api.Test +import org.utbot.examples.DoNotCalculate +import org.utbot.examples.structures.MinStack +import org.utbot.framework.plugin.api.MockStrategyApi + +class SummaryMinStackTest : SummaryTestCaseGeneratorTest( + MinStack::class +) { + @Test + fun testGetMin() { + val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + + "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: return minStack[size - 1];" + + val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + + "@utbot.throwsException {@link NullPointerException} in: return minStack[size - 1];" + + val summary3 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + + "@utbot.returnsFrom {@code return minStack[size - 1];}\n" + + val methodName1 = "testGetMin_ThrowArrayIndexOutOfBoundsException" + val methodName2 = "testGetMin_ThrowNullPointerException" + val methodName3 = "testGetMin_ReturnSize1OfMinStack" + + val displayName1 = "return minStack[size - 1] : True -> ThrowArrayIndexOutOfBoundsException" + val displayName2 = "return minStack[size - 1] : True -> ThrowNullPointerException" + val displayName3 = "-> return minStack[size - 1]" + + val summaryKeys = listOf( + summary1, + summary2, + summary3 + ) + + val displayNames = listOf( + displayName1, + displayName2, + displayName3 + ) + + val methodNames = listOf( + methodName1, + methodName2, + methodName3 + ) + + val method = MinStack::getMin + val mockStrategy = MockStrategyApi.NO_MOCKS + val coverage = DoNotCalculate + + checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + } + + @Test + fun testRemoveValue() { + val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + + "@utbot.executesCondition {@code (size <= 0): True}\n" + + "@utbot.throwsException {@link RuntimeException} after condition: {@code size <= 0}" + + val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + + "@utbot.executesCondition {@code (size <= 0): False}\n" + + val methodName1 = "testRemoveValue_SizeLessOrEqualZero" + val methodName2 = "testRemoveValue_SizeGreaterThanZero" + + val displayName1 = "size <= 0 -> ThrowRuntimeException" + val displayName2 = "-> size <= 0 : False" + + val summaryKeys = listOf( + summary1, + summary2 + ) + + val displayNames = listOf( + displayName1, + displayName2 + ) + + val methodNames = listOf( + methodName1, + methodName2 + ) + + val method = MinStack::removeValue + val mockStrategy = MockStrategyApi.NO_MOCKS + val coverage = DoNotCalculate + + checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + } + + @Test + fun testAddValue() { + val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: stack[size] = value;" + + val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.throwsException {@link NullPointerException} in: stack[size] = value;" + + val summary3 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): True}\n" + + "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = value;" + + val summary4 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): True}\n" + + "@utbot.throwsException {@link NullPointerException} in: minStack[size] = value;" + + val summary5 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): False}\n" + + "@utbot.throwsException {@link NullPointerException} in: minStack[size] = Math.min(minStack[size - 1], value);" + + val summary6 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): False}\n" + + "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" + val summary7 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): False}\n" + + "@utbot.invokes {@code {@link java.lang.Math#min(long,long)}}\n" + + "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" + val summary8 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): True}\n" + val summary9 = "@utbot.classUnderTest {@link MinStack}\n" + + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + + "@utbot.executesCondition {@code (size == 0): False}\n" + + "@utbot.invokes {@code {@link java.lang.Math#min(long,long)}}\n" + + val methodName1 = "testAddValue_ThrowArrayIndexOutOfBoundsException" + val methodName2 = "testAddValue_ThrowNullPointerException" + val methodName3 = "testAddValue_ThrowArrayIndexOutOfBoundsException_1" + val methodName4 = "testAddValue_ThrowNullPointerException_1" + val methodName5 = "testAddValue_ThrowNullPointerException_2" + val methodName6 = "testAddValue_ThrowArrayIndexOutOfBoundsException_2" + val methodName7 = "testAddValue_MathMin" + val methodName8 = "testAddValue_SizeEqualsZero" + val methodName9 = "testAddValue_SizeNotEqualsZero" + + val displayName1 = "stack[size] = value -> ThrowArrayIndexOutOfBoundsException" + val displayName2 = "stack[size] = value -> ThrowNullPointerException" + val displayName3 = "minStack[size] = value -> ThrowArrayIndexOutOfBoundsException" + val displayName4 = "minStack[size] = value -> ThrowNullPointerException" + val displayName5 = "minStack[size] = Math.min(minStack[size - 1], value) -> ThrowNullPointerException" + val displayName6 = "minStack[size] = Math.min(minStack[size - 1], value) -> ThrowArrayIndexOutOfBoundsException" + val displayName7 = "minStack[size] = Math.min(minStack[size - 1], value) -> ThrowArrayIndexOutOfBoundsException" + val displayName8 = "-> size == 0 : True" + val displayName9 = "size == 0 : False -> MathMin" + + val summaryKeys = listOf( + summary1, + summary2, + summary3, + summary4, + summary5, + summary6, + summary7, + summary8, + summary9 + ) + + val displayNames = listOf( + displayName1, + displayName2, + displayName3, + displayName4, + displayName5, + displayName6, + displayName7, + displayName8, + displayName9 + ) + + val methodNames = listOf( + methodName1, + methodName2, + methodName3, + methodName4, + methodName5, + methodName6, + methodName7, + methodName8, + methodName9, + ) + + val method = MinStack::addValue + val mockStrategy = MockStrategyApi.NO_MOCKS + val coverage = DoNotCalculate + + checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + } +} \ No newline at end of file From 6d01afe2c4f5dbd9e20f8a791f573a2a3f292f45 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Thu, 4 Aug 2022 15:33:32 +0300 Subject: [PATCH 10/29] Fix broken tests --- .../test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt index db442b9604..c88d95e9e4 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt @@ -60,6 +60,7 @@ import org.utbot.framework.plugin.api.util.kClass import org.utbot.framework.plugin.api.util.withUtContext import org.utbot.framework.util.Conflict import org.utbot.framework.util.toValueTestCase +import org.utbot.summary.UtSummarySettings import org.utbot.summary.summarize import java.io.File import java.nio.file.Path @@ -96,6 +97,7 @@ abstract class UtValueTestCaseChecker( UtSettings.useAssembleModelGenerator = true UtSettings.saveRemainingStatesForConcreteExecution = false UtSettings.useFuzzing = false + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = false } // checks paramsBefore and result From d03ad7648d1e5ca0915e91f255416b209d09e1b2 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Thu, 4 Aug 2022 16:23:07 +0300 Subject: [PATCH 11/29] Add

 tag only in case when custom javadoc tags are
 not used

---
 .../framework/codegen/model/visitor/CgAbstractRenderer.kt    | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt
index 57d73a5c86..5e633c1603 100644
--- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt
+++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt
@@ -92,6 +92,7 @@ import org.utbot.framework.plugin.api.util.isArray
 import org.utbot.framework.plugin.api.util.isRefType
 import org.utbot.framework.plugin.api.util.longClassId
 import org.utbot.framework.plugin.api.util.shortClassId
+import org.utbot.summary.UtSummarySettings
 
 internal abstract class CgAbstractRenderer(val context: CgContext, val printer: CgPrinter = CgPrinterImpl()) : CgVisitor,
     CgPrinter by printer {
@@ -309,7 +310,11 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer:
     }
     override fun visit(element: CgDocPreTagStatement) {
         if (element.content.all { it.isEmpty() }) return
+        // Don't add 
 tag if custom javadoc tags are used.
+        val shouldAddPreTag = !UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS
+        if (shouldAddPreTag) println("
")
         for (stmt in element.content) stmt.accept(this)
+        if (shouldAddPreTag) println("
") } override fun visit(element: CgDocCodeStmt) { if (element.isEmpty()) return From 74c5822a6128f3eede3ee9edea2fe0f590394cd2 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 13:58:36 +0300 Subject: [PATCH 12/29] Use a full exception name instead of simple name to build inline link correctly --- .../org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index fb8078094e..91bc29f681 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -72,7 +72,7 @@ class CustomJavaDocCommentBuilder( val exceptionThrow: String? = if (thrownException == null) { traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } } else { - val exceptionName = thrownException.javaClass.simpleName + val exceptionName = thrownException.javaClass.name val reason = findExceptionReason(currentMethod, thrownException) "{@link $exceptionName} $reason" } From 7e4aaf93f769d526b99e73ba25e721beb297fb18 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 17:01:29 +0300 Subject: [PATCH 13/29] Minor refactoring --- .../javadoc/UtCustomJavaDocTagProvider.kt | 4 +++- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 17 ++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index a7fe326a30..dd3669040a 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -11,7 +11,8 @@ import com.intellij.psi.javadoc.PsiDocTagValue * Provides plugin's custom JavaDoc tags to make test summaries structured. */ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { - override fun getSupportedTags(): List = + // The tags' order is important. + override fun getSupportedTags(): List = listOf( UtCustomTag.ClassUnderTest, UtCustomTag.MethodUnderTest, @@ -24,6 +25,7 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { UtCustomTag.ThrowsException, ) + //TODO: move it to another module to avoid duplication sealed class UtCustomTag(private val name: String, private val message: String) : JavadocTagInfo { override fun getName(): String = name diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index b79ffe8134..62b852bcc4 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -28,15 +28,10 @@ class UtJavaDocInfoGenerator { */ fun addUtBotSpecificSectionsToJavaDoc(javadoc: String?, comment: PsiDocComment): String { val builder: StringBuilder = StringBuilder(javadoc) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ClassUnderTest) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.MethodUnderTest) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Invokes) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Executes) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.Iterates) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ExpectedResult) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ActualResult) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ReturnsFrom) - generateUtTagSection(builder, comment, UtCustomJavaDocTagProvider.UtCustomTag.ThrowsException) + val docTagProvider = UtCustomJavaDocTagProvider() + docTagProvider.supportedTags.forEach { + generateUtTagSection(builder, comment, it) + } return builder.toString() } @@ -50,7 +45,7 @@ class UtJavaDocInfoGenerator { ) { if (comment != null) { val tag = comment.findTagByName(utTag.name) ?: return - startHeaderSection(builder, utTag.getMessage())?.append("

") + startHeaderSection(builder, utTag.getMessage()).append("

") val sectionContent = buildString { generateValue(this, tag.dataElements) this.trim { it <= ' ' } @@ -60,7 +55,7 @@ class UtJavaDocInfoGenerator { } } - private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder? { + private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder { return builder.append(DocumentationMarkup.SECTION_HEADER_START) .append(message) .append(MESSAGE_SEPARATOR) From 92eb15d0d8bb8425e78d9b8bab1d740b75dd082b Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 17:25:18 +0300 Subject: [PATCH 14/29] Minor refactoring: avoid code duplication --- .../examples/SummaryTestCaseGeneratorTest.kt | 33 ++----------------- .../controlflow/SummaryConditionsTest.kt | 2 +- .../SummaryExceptionClusteringExamplesTest.kt | 2 +- .../structures/SummaryMinStackTest.kt | 6 ++-- 4 files changed, 8 insertions(+), 35 deletions(-) diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index a64dd3e2d6..fa2ea399bc 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -50,14 +50,15 @@ open class SummaryTestCaseGeneratorTest( summaryKeys: List, methodNames: List = listOf(), displayNames: List = listOf(), - clusterInfo: List> = listOf() + clusterInfo: List> = listOf(), + useCustomTags: Boolean = false ) { workaround(WorkaroundReason.HACK) { // @todo change to the constructor parameter checkSolverTimeoutMillis = 0 checkNpeInNestedMethods = true checkNpeInNestedNotPrivateMethods = true - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = false + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = useCustomTags } val utMethod = UtMethod.from(method) val testSet = executionsModel(utMethod, mockStrategy) @@ -69,34 +70,6 @@ open class SummaryTestCaseGeneratorTest( testSetWithSummarization.checkClusterInfo(clusterInfo) } - /** - * Checks summaries containing custom JavaDoc tags. - */ - inline fun checkSummariesWithCustomTags( - method: KFunction, - mockStrategy: MockStrategyApi, - coverageMatcher: CoverageMatcher, - summaryKeys: List, - methodNames: List, - displayNames: List - ) { - workaround(WorkaroundReason.HACK) { - // @todo change to the constructor parameter - checkSolverTimeoutMillis = 0 - checkNpeInNestedMethods = true - checkNpeInNestedNotPrivateMethods = true - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = true - } - val utMethod = UtMethod.from(method) - val testSet = executionsModel(utMethod, mockStrategy) - testSet.summarize(searchDirectory) - testSet.clustersInfo - - testSet.executions.checkMatchersWithCustomTagsInSummary(summaryKeys) - testSet.executions.checkMatchersWithMethodNames(methodNames) - testSet.executions.checkMatchersWithDisplayNames(displayNames) - } - /** * It removes from the String all whitespaces, tabs etc. * diff --git a/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt index 0fa3319a99..53c66ed7f9 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt @@ -46,6 +46,6 @@ class SummaryConditionsTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) } } \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt index 66e1d88ae8..c7ac1b6ccc 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt @@ -69,6 +69,6 @@ class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) } } \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt index 3744d9423d..5165470ba7 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt @@ -53,7 +53,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) } @Test @@ -92,7 +92,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) } @Test @@ -197,6 +197,6 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - checkSummariesWithCustomTags(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) } } \ No newline at end of file From cf9b60fb7ffb78c075195396d63a3fef3d900c89 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 18:44:21 +0300 Subject: [PATCH 15/29] Add DocCustomTagStatement and CgCustomTagStatement --- .../kotlin/org/utbot/framework/plugin/api/Api.kt | 8 ++++++++ .../framework/codegen/model/tree/CgElement.kt | 15 +++++++++++++++ .../codegen/model/visitor/CgAbstractRenderer.kt | 14 +++++++++----- .../framework/codegen/model/visitor/CgVisitor.kt | 2 ++ .../comment/CustomJavaDocCommentBuilder.kt | 4 ++-- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 143b9d5d48..7a3c1939eb 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1276,6 +1276,14 @@ class DocPreTagStatement(content: List) : DocTagStatement(content) override fun hashCode(): Int = content.hashCode() } +class DocCustomTagStatement(content: List) : DocTagStatement(content) { + override fun toString(): String = content.joinToString(separator = "") + + override fun equals(other: Any?): Boolean = + if (other is DocCustomTagStatement) this.hashCode() == other.hashCode() else false + + override fun hashCode(): Int = content.hashCode() +} open class DocClassLinkStmt(val className: String) : DocStatement() { override fun toString(): String = className diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt index ec78d73dea..19ae5c7429 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt @@ -11,6 +11,7 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.DocClassLinkStmt import org.utbot.framework.plugin.api.DocCodeStmt +import org.utbot.framework.plugin.api.DocCustomTagStatement import org.utbot.framework.plugin.api.DocMethodLinkStmt import org.utbot.framework.plugin.api.DocPreTagStatement import org.utbot.framework.plugin.api.DocRegularStmt @@ -52,6 +53,7 @@ interface CgElement { is CgMultilineComment -> visit(element) is CgDocumentationComment -> visit(element) is CgDocPreTagStatement -> visit(element) + is CgCustomTagStatement -> visit(element) is CgDocCodeStmt -> visit(element) is CgDocRegularStmt -> visit(element) is CgDocClassLinkStmt -> visit(element) @@ -335,6 +337,15 @@ class CgDocPreTagStatement(content: List) : CgDocTagStatement(co override fun hashCode(): Int = content.hashCode() } +class CgCustomTagStatement(content: List) : CgDocTagStatement(content) { + override fun equals(other: Any?): Boolean = + if (other is CgCustomTagStatement) { + this.hashCode() == other.hashCode() + } else false + + override fun hashCode(): Int = content.hashCode() +} + class CgDocCodeStmt(val stmt: String) : CgDocStatement() { override fun isEmpty(): Boolean = stmt.isEmpty() @@ -379,6 +390,10 @@ fun convertDocToCg(stmt: DocStatement): CgDocStatement { val stmts = stmt.content.map { convertDocToCg(it) } CgDocPreTagStatement(content = stmts) } + is DocCustomTagStatement -> { + val stmts = stmt.content.map { convertDocToCg(it) } + CgCustomTagStatement(content = stmts) + } is DocRegularStmt -> CgDocRegularStmt(stmt = stmt.stmt) is DocClassLinkStmt -> CgDocClassLinkStmt(className = stmt.className) is DocMethodLinkStmt -> CgDocMethodLinkStmt(methodName = stmt.methodName, stmt = stmt.className) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt index 5e633c1603..53e1e1a4ff 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt @@ -16,6 +16,7 @@ import org.utbot.framework.codegen.model.tree.CgComment import org.utbot.framework.codegen.model.tree.CgCommentedAnnotation import org.utbot.framework.codegen.model.tree.CgComparison import org.utbot.framework.codegen.model.tree.CgContinueStatement +import org.utbot.framework.codegen.model.tree.CgCustomTagStatement import org.utbot.framework.codegen.model.tree.CgDeclaration import org.utbot.framework.codegen.model.tree.CgDecrement import org.utbot.framework.codegen.model.tree.CgDoWhileLoop @@ -92,7 +93,6 @@ import org.utbot.framework.plugin.api.util.isArray import org.utbot.framework.plugin.api.util.isRefType import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.shortClassId -import org.utbot.summary.UtSummarySettings internal abstract class CgAbstractRenderer(val context: CgContext, val printer: CgPrinter = CgPrinterImpl()) : CgVisitor, CgPrinter by printer { @@ -310,12 +310,16 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer: } override fun visit(element: CgDocPreTagStatement) { if (element.content.all { it.isEmpty() }) return - // Don't add

 tag if custom javadoc tags are used.
-        val shouldAddPreTag = !UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS
-        if (shouldAddPreTag) println("
")
+        println("
")
         for (stmt in element.content) stmt.accept(this)
-        if (shouldAddPreTag) println("
") + println("
") } + + override fun visit(element: CgCustomTagStatement) { + if (element.content.all { it.isEmpty() }) return + for (stmt in element.content) stmt.accept(this) + } + override fun visit(element: CgDocCodeStmt) { if (element.isEmpty()) return diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgVisitor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgVisitor.kt index 2d341a51d1..30c269e88c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgVisitor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgVisitor.kt @@ -22,6 +22,7 @@ import org.utbot.framework.codegen.model.tree.CgDocClassLinkStmt import org.utbot.framework.codegen.model.tree.CgDocCodeStmt import org.utbot.framework.codegen.model.tree.CgDocMethodLinkStmt import org.utbot.framework.codegen.model.tree.CgDocPreTagStatement +import org.utbot.framework.codegen.model.tree.CgCustomTagStatement import org.utbot.framework.codegen.model.tree.CgDocRegularStmt import org.utbot.framework.codegen.model.tree.CgDocumentationComment import org.utbot.framework.codegen.model.tree.CgElement @@ -122,6 +123,7 @@ interface CgVisitor { // Comment statements fun visit(element: CgDocPreTagStatement): R + fun visit(element: CgCustomTagStatement): R fun visit(element: CgDocCodeStmt): R fun visit(element: CgDocRegularStmt): R fun visit(element: CgDocClassLinkStmt): R diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index 91bc29f681..a5184a0ea4 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -1,6 +1,6 @@ package org.utbot.summary.comment -import org.utbot.framework.plugin.api.DocPreTagStatement +import org.utbot.framework.plugin.api.DocCustomTagStatement import org.utbot.framework.plugin.api.DocRegularStmt import org.utbot.framework.plugin.api.DocStatement import org.utbot.framework.plugin.api.exceptionOrNull @@ -46,7 +46,7 @@ class CustomJavaDocCommentBuilder( if (comment.throwsException.isNotEmpty()) docStatementList += DocRegularStmt("@utbot.throwsException ${comment.throwsException}") - return listOf(DocPreTagStatement(docStatementList)) + return listOf(DocCustomTagStatement(docStatementList)) } private fun buildCustomJavaDocComment(currentMethod: SootMethod): CustomJavaDocComment { From 9c14eb02637f321707dc7eca0706beac25d5ab08 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 20:38:49 +0300 Subject: [PATCH 16/29] Refactored code to avoid code duplication --- .../javadoc/UtCustomJavaDocTagProvider.kt | 38 +++---------- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 2 +- .../comment/CustomJavaDocCommentBuilder.kt | 48 ++-------------- .../comment/CustomJavaDocTagProvider.kt | 56 +++++++++++++++++++ 4 files changed, 72 insertions(+), 72 deletions(-) create mode 100644 utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index dd3669040a..3c2aa9356b 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -6,30 +6,20 @@ import com.intellij.psi.PsiReference import com.intellij.psi.javadoc.CustomJavadocTagProvider import com.intellij.psi.javadoc.JavadocTagInfo import com.intellij.psi.javadoc.PsiDocTagValue +import org.utbot.summary.comment.CustomJavaDocTag +import org.utbot.summary.comment.CustomJavaDocTagProvider /** * Provides plugin's custom JavaDoc tags to make test summaries structured. */ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { - // The tags' order is important. - override fun getSupportedTags(): List = - listOf( - UtCustomTag.ClassUnderTest, - UtCustomTag.MethodUnderTest, - UtCustomTag.ExpectedResult, - UtCustomTag.ActualResult, - UtCustomTag.Executes, - UtCustomTag.Invokes, - UtCustomTag.Iterates, - UtCustomTag.ReturnsFrom, - UtCustomTag.ThrowsException, - ) - - //TODO: move it to another module to avoid duplication - sealed class UtCustomTag(private val name: String, private val message: String) : JavadocTagInfo { - override fun getName(): String = name - - fun getMessage(): String = message + override fun getSupportedTags(): List = + CustomJavaDocTagProvider().getPluginCustomTags().map { t -> UtCustomTagInfo(t) } + + class UtCustomTagInfo(private val tag: CustomJavaDocTag) : JavadocTagInfo { + override fun getName(): String = tag.name + + fun getMessage(): String = tag.message override fun isInline() = false @@ -40,15 +30,5 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { override fun isValidInContext(element: PsiElement?): Boolean { return element is PsiMethod } - - object ClassUnderTest : UtCustomTag("utbot.classUnderTest", "Class under test") - object MethodUnderTest : UtCustomTag("utbot.methodUnderTest", "Method under test") - object ExpectedResult : UtCustomTag("utbot.expectedResult", "Expected result") - object ActualResult : UtCustomTag("utbot.actualResult", "Actual result") - object Executes : UtCustomTag("utbot.executesCondition", "Executes condition") - object Invokes : UtCustomTag("utbot.invokes", "Invokes") - object Iterates : UtCustomTag("utbot.iterates", "Iterates") - object ReturnsFrom : UtCustomTag("utbot.returnsFrom", "Returns from") - object ThrowsException : UtCustomTag("utbot.throwsException", "Throws exception") } } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index 62b852bcc4..eba45ad3b5 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -41,7 +41,7 @@ class UtJavaDocInfoGenerator { private fun generateUtTagSection( builder: StringBuilder, comment: PsiDocComment?, - utTag: UtCustomJavaDocTagProvider.UtCustomTag + utTag: UtCustomJavaDocTagProvider.UtCustomTagInfo ) { if (comment != null) { val tag = comment.findTagByName(utTag.name) ?: return diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index a5184a0ea4..703a21510d 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -1,14 +1,12 @@ package org.utbot.summary.comment import org.utbot.framework.plugin.api.DocCustomTagStatement -import org.utbot.framework.plugin.api.DocRegularStmt import org.utbot.framework.plugin.api.DocStatement import org.utbot.framework.plugin.api.exceptionOrNull import org.utbot.summary.ast.JimpleToASTMap import org.utbot.summary.tag.TraceTagWithoutExecution import soot.SootMethod -//TODO: polish code class CustomJavaDocCommentBuilder( traceTag: TraceTagWithoutExecution, sootToAST: MutableMap @@ -19,33 +17,8 @@ class CustomJavaDocCommentBuilder( */ fun buildDocStatements(method: SootMethod): List { val comment: CustomJavaDocComment = buildCustomJavaDocComment(method) - val docStatementList = mutableListOf() - - docStatementList += DocRegularStmt("@utbot.classUnderTest ${comment.classUnderTest}\n") - docStatementList += DocRegularStmt("@utbot.methodUnderTest ${comment.methodUnderTest}\n") - - if (comment.expectedResult.isNotEmpty()) - docStatementList += DocRegularStmt("@utbot.expectedResult ${comment.expectedResult}\n") - if (comment.actualResult.isNotEmpty()) - docStatementList += DocRegularStmt("@utbot.actualResult ${comment.actualResult}\n") - if (comment.executesCondition.isNotEmpty()) { - val statement = - "@utbot.executesCondition ${comment.executesCondition.joinToString(separator = ",\n")}\n" - docStatementList += DocRegularStmt(statement) - } - if (comment.invokes.isNotEmpty()) { - val statement = "@utbot.invokes ${comment.invokes.joinToString(separator = ",\n")}\n" - docStatementList += DocRegularStmt(statement) - } - if (comment.iterates.isNotEmpty()) { - val statement = "@utbot.iterates ${comment.iterates.joinToString(separator = ",\n")}\n" - docStatementList += DocRegularStmt(statement) - } - if (comment.returnsFrom.isNotEmpty()) - docStatementList += DocRegularStmt("@utbot.returnsFrom ${comment.returnsFrom}\n") - if (comment.throwsException.isNotEmpty()) - docStatementList += DocRegularStmt("@utbot.throwsException ${comment.throwsException}") - + val docStatementList = + CustomJavaDocTagProvider().getPluginCustomTags().mapNotNull { it.generateDocStatement(comment) } return listOf(DocCustomTagStatement(docStatementList)) } @@ -95,20 +68,11 @@ class CustomJavaDocCommentBuilder( while (currentBlock != null) { for (statement in currentBlock.stmtTexts) { when (statement.stmtType) { - StmtType.Invoke -> { - val info = statement.description - customJavaDocComment.invokes += "{@code $info}" - } - StmtType.Condition -> { - val info = statement.description - customJavaDocComment.executesCondition += "{@code $info}" - } - StmtType.Return -> { - val info = statement.description - customJavaDocComment.returnsFrom = "{@code $info}" - } + StmtType.Invoke -> customJavaDocComment.invokes += "{@code ${statement.description}}" + StmtType.Condition -> customJavaDocComment.executesCondition += "{@code ${statement.description}}" + StmtType.Return -> customJavaDocComment.returnsFrom = "{@code ${statement.description}}" else -> { - //TODO + //TODO: do we need to handle others? } } } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt new file mode 100644 index 0000000000..7c6fcf256e --- /dev/null +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt @@ -0,0 +1,56 @@ +package org.utbot.summary.comment + +import org.utbot.framework.plugin.api.DocRegularStmt + +/** + * Provides a list of supported custom JavaDoc tags. + */ +class CustomJavaDocTagProvider { + // The tags' order is important because plugin builds final JavaDoc comment according to it. + fun getPluginCustomTags(): List = + listOf( + CustomJavaDocTag.ClassUnderTest, + CustomJavaDocTag.MethodUnderTest, + CustomJavaDocTag.ExpectedResult, + CustomJavaDocTag.ActualResult, + CustomJavaDocTag.Executes, + CustomJavaDocTag.Invokes, + CustomJavaDocTag.Iterates, + CustomJavaDocTag.ReturnsFrom, + CustomJavaDocTag.ThrowsException, + ) +} + +sealed class CustomJavaDocTag( + val name: String, + val message: String, + private val valueRetriever: (CustomJavaDocComment) -> Any +) { + object ClassUnderTest : + CustomJavaDocTag("utbot.classUnderTest", "Class under test", CustomJavaDocComment::classUnderTest) + + object MethodUnderTest : + CustomJavaDocTag("utbot.methodUnderTest", "Method under test", CustomJavaDocComment::methodUnderTest) + + object ExpectedResult : + CustomJavaDocTag("utbot.expectedResult", "Expected result", CustomJavaDocComment::expectedResult) + + object ActualResult : CustomJavaDocTag("utbot.actualResult", "Actual result", CustomJavaDocComment::actualResult) + object Executes : + CustomJavaDocTag("utbot.executesCondition", "Executes condition", CustomJavaDocComment::executesCondition) + + object Invokes : CustomJavaDocTag("utbot.invokes", "Invokes", CustomJavaDocComment::invokes) + object Iterates : CustomJavaDocTag("utbot.iterates", "Iterates", CustomJavaDocComment::iterates) + object ReturnsFrom : CustomJavaDocTag("utbot.returnsFrom", "Returns from", CustomJavaDocComment::returnsFrom) + object ThrowsException : + CustomJavaDocTag("utbot.throwsException", "Throws exception", CustomJavaDocComment::throwsException) + + fun generateDocStatement(comment: CustomJavaDocComment): DocRegularStmt? { + val value = valueRetriever.invoke(comment) + return if (value is String) { + if (value.isNotEmpty()) DocRegularStmt("@$name $value\n") else null + } else if (value is List<*>) { + if (value.isNotEmpty()) DocRegularStmt("@$name ${value.joinToString(separator = ",\n")}\n") else null + } else null + } +} \ No newline at end of file From 6dce850e9a581fdee4db0dcf04b31f4e4481299e Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 21:34:22 +0300 Subject: [PATCH 17/29] Fix tests: add full name for classes --- .../SummaryExceptionClusteringExamplesTest.kt | 6 +++--- .../structures/SummaryMinStackTest.kt | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt index c7ac1b6ccc..c543b44767 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt @@ -14,19 +14,19 @@ class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( val summary1 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): True}\n" + - "@utbot.throwsException {@link ArithmeticException} in: return 100 / i;" + "@utbot.throwsException {@link java.lang.ArithmeticException} in: return 100 / i;" val summary2 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + "{@code (i == 1): True}\n" + - "@utbot.throwsException {@link MyCheckedException} after condition: {@code i == 1}" + "@utbot.throwsException {@link org.utbot.examples.exceptions.MyCheckedException} after condition: {@code i == 1}" val summary3 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + "{@code (i == 1): False},\n" + "{@code (i == 2): True}\n" + - "@utbot.throwsException {@link IllegalArgumentException} after condition: {@code i == 2}" + "@utbot.throwsException {@link java.lang.IllegalArgumentException} after condition: {@code i == 2}" val summary4 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + diff --git a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt index 5165470ba7..ad52cf0373 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt @@ -13,11 +13,11 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( fun testGetMin() { val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + - "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: return minStack[size - 1];" + "@utbot.throwsException {@link java.lang.ArrayIndexOutOfBoundsException} in: return minStack[size - 1];" val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + - "@utbot.throwsException {@link NullPointerException} in: return minStack[size - 1];" + "@utbot.throwsException {@link java.lang.NullPointerException} in: return minStack[size - 1];" val summary3 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#getMin()}\n" + @@ -61,7 +61,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + "@utbot.executesCondition {@code (size <= 0): True}\n" + - "@utbot.throwsException {@link RuntimeException} after condition: {@code size <= 0}" + "@utbot.throwsException {@link java.lang.RuntimeException} after condition: {@code size <= 0}" val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + @@ -99,36 +99,36 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( fun testAddValue() { val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + - "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: stack[size] = value;" + "@utbot.throwsException {@link java.lang.ArrayIndexOutOfBoundsException} in: stack[size] = value;" val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + - "@utbot.throwsException {@link NullPointerException} in: stack[size] = value;" + "@utbot.throwsException {@link java.lang.NullPointerException} in: stack[size] = value;" val summary3 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): True}\n" + - "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = value;" + "@utbot.throwsException {@link java.lang.ArrayIndexOutOfBoundsException} in: minStack[size] = value;" val summary4 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): True}\n" + - "@utbot.throwsException {@link NullPointerException} in: minStack[size] = value;" + "@utbot.throwsException {@link java.lang.NullPointerException} in: minStack[size] = value;" val summary5 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): False}\n" + - "@utbot.throwsException {@link NullPointerException} in: minStack[size] = Math.min(minStack[size - 1], value);" + "@utbot.throwsException {@link java.lang.NullPointerException} in: minStack[size] = Math.min(minStack[size - 1], value);" val summary6 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): False}\n" + - "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" + "@utbot.throwsException {@link java.lang.ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" val summary7 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): False}\n" + "@utbot.invokes {@code {@link java.lang.Math#min(long,long)}}\n" + - "@utbot.throwsException {@link ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" + "@utbot.throwsException {@link java.lang.ArrayIndexOutOfBoundsException} in: minStack[size] = Math.min(minStack[size - 1], value);" val summary8 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#addValue(long)}\n" + "@utbot.executesCondition {@code (size == 0): True}\n" From 7800d33780379daf6ff234885f0fc00011ff489d Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sat, 6 Aug 2022 21:45:20 +0300 Subject: [PATCH 18/29] Add JUnit extension to control USE_CUSTOM_TAGS setting --- .../examples/CustomJavaDocTagsEnabler.kt | 19 +++++++++++++++++++ .../examples/SummaryTestCaseGeneratorTest.kt | 4 +--- .../controlflow/SummaryConditionsTest.kt | 5 ++++- .../SummaryExceptionClusteringExamplesTest.kt | 5 ++++- .../structures/SummaryMinStackTest.kt | 9 ++++++--- 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt diff --git a/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt new file mode 100644 index 0000000000..bbe8f3eeed --- /dev/null +++ b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt @@ -0,0 +1,19 @@ +package examples + +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext +import org.utbot.summary.UtSummarySettings + +class CustomJavaDocTagsEnabler(private val enable: Boolean = true) : BeforeEachCallback, AfterEachCallback { + private var previousValue = false + + override fun beforeEach(context: ExtensionContext?) { + previousValue = UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = enable + } + + override fun afterEach(context: ExtensionContext?) { + UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = previousValue + } +} \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index fa2ea399bc..fcf2acbc46 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -50,15 +50,13 @@ open class SummaryTestCaseGeneratorTest( summaryKeys: List, methodNames: List = listOf(), displayNames: List = listOf(), - clusterInfo: List> = listOf(), - useCustomTags: Boolean = false + clusterInfo: List> = listOf() ) { workaround(WorkaroundReason.HACK) { // @todo change to the constructor parameter checkSolverTimeoutMillis = 0 checkNpeInNestedMethods = true checkNpeInNestedNotPrivateMethods = true - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = useCustomTags } val utMethod = UtMethod.from(method) val testSet = executionsModel(utMethod, mockStrategy) diff --git a/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt index 53c66ed7f9..79947a0817 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/controlflow/SummaryConditionsTest.kt @@ -1,11 +1,14 @@ 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.DoNotCalculate import org.utbot.examples.controlflow.Conditions import org.utbot.framework.plugin.api.MockStrategyApi +@ExtendWith(CustomJavaDocTagsEnabler::class) class SummaryConditionsTest : SummaryTestCaseGeneratorTest( Conditions::class ) { @@ -46,6 +49,6 @@ class SummaryConditionsTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) } } \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt index c543b44767..a22cd1eadf 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt @@ -1,11 +1,14 @@ 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.DoNotCalculate import org.utbot.examples.exceptions.ExceptionClusteringExamples import org.utbot.framework.plugin.api.MockStrategyApi +@ExtendWith(CustomJavaDocTagsEnabler::class) class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( ExceptionClusteringExamples::class ) { @@ -69,6 +72,6 @@ class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) } } \ No newline at end of file diff --git a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt index ad52cf0373..0de99731de 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt @@ -1,11 +1,14 @@ package examples.structures +import examples.CustomJavaDocTagsEnabler import examples.SummaryTestCaseGeneratorTest import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.utbot.examples.DoNotCalculate import org.utbot.examples.structures.MinStack import org.utbot.framework.plugin.api.MockStrategyApi +@ExtendWith(CustomJavaDocTagsEnabler::class) class SummaryMinStackTest : SummaryTestCaseGeneratorTest( MinStack::class ) { @@ -53,7 +56,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) } @Test @@ -92,7 +95,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) } @Test @@ -197,6 +200,6 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val mockStrategy = MockStrategyApi.NO_MOCKS val coverage = DoNotCalculate - summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames, useCustomTags = true) + summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) } } \ No newline at end of file From d0039627e3780d1c8dd4b6a079e52819ba87ecde Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Sun, 7 Aug 2022 13:31:25 +0300 Subject: [PATCH 19/29] Move useCustomJavaDocTags to UtSettings, make useFuzzing true --- .../src/main/kotlin/org/utbot/framework/UtSettings.kt | 7 ++++++- .../kotlin/org/utbot/examples/UtValueTestCaseChecker.kt | 1 - .../src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt | 8 ++++---- .../src/main/kotlin/org/utbot/summary/Summarization.kt | 2 +- .../main/kotlin/org/utbot/summary/UtSummarySettings.kt | 5 ----- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt index fde2cd6cbb..f79ee02149 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt @@ -183,6 +183,11 @@ object UtSettings { var testName by getBooleanProperty(true) var testDisplayName by getBooleanProperty(true) + /** + * Generate summaries using plugin's custom JavaDoc tags. + */ + var useCustomJavaDocTags by getBooleanProperty(false) + /** * Enable the machine learning module to generate summaries for methods under test. * True by default. @@ -269,7 +274,7 @@ object UtSettings { /** * Set to true to start fuzzing if symbolic execution haven't return anything */ - var useFuzzing: Boolean by getBooleanProperty(false) + var useFuzzing: Boolean by getBooleanProperty(true) /** * Set the total attempts to improve coverage by fuzzer. diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt index c88d95e9e4..3172329ca8 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt @@ -97,7 +97,6 @@ abstract class UtValueTestCaseChecker( UtSettings.useAssembleModelGenerator = true UtSettings.saveRemainingStatesForConcreteExecution = false UtSettings.useFuzzing = false - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = false } // checks paramsBefore and result diff --git a/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt index bbe8f3eeed..347a293970 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt @@ -3,17 +3,17 @@ package examples import org.junit.jupiter.api.extension.AfterEachCallback import org.junit.jupiter.api.extension.BeforeEachCallback import org.junit.jupiter.api.extension.ExtensionContext -import org.utbot.summary.UtSummarySettings +import org.utbot.framework.UtSettings class CustomJavaDocTagsEnabler(private val enable: Boolean = true) : BeforeEachCallback, AfterEachCallback { private var previousValue = false override fun beforeEach(context: ExtensionContext?) { - previousValue = UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = enable + previousValue = UtSettings.useCustomJavaDocTags + UtSettings.useCustomJavaDocTags = enable } override fun afterEach(context: ExtensionContext?) { - UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS = previousValue + UtSettings.useCustomJavaDocTags = previousValue } } \ No newline at end of file diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt index 4f947cd0d1..316006b06d 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt @@ -157,7 +157,7 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List Date: Sun, 7 Aug 2022 21:21:18 +0300 Subject: [PATCH 20/29] Remove unused import and fix broken tests --- .../src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt | 1 - .../kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index fcf2acbc46..806f97021a 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -11,7 +11,6 @@ import org.utbot.framework.UtSettings.checkSolverTimeoutMillis import org.utbot.framework.codegen.TestExecution import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.summary.UtSummarySettings import org.utbot.summary.comment.nextSynonyms import org.utbot.summary.summarize import kotlin.reflect.KClass diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index 8e2921d22b..d291aa197b 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -154,8 +154,8 @@ open class SimpleCommentBuilder( if (exceptionNode == null) return "" reason += when { - exceptionNode is IfStmt -> "{@code ${exceptionNode.condition}}" - isLoopStatement(exceptionNode) -> "{@code ${getTextIterationDescription(exceptionNode)}" + exceptionNode is IfStmt -> exceptionNode.condition.toString() + isLoopStatement(exceptionNode) -> getTextIterationDescription(exceptionNode) exceptionNode is SwitchStmt -> textSwitchCase(step, jimpleToASTMap) else -> exceptionNode.toString() } From 321bf0de0739ab46ff69f856807c24cce9daf344 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 8 Aug 2022 10:26:33 +0300 Subject: [PATCH 21/29] Fix broken tests --- .../exceptions/SummaryExceptionClusteringExamplesTest.kt | 4 ++-- .../test/kotlin/examples/structures/SummaryMinStackTest.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt index a22cd1eadf..bc51997a1e 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/exceptions/SummaryExceptionClusteringExamplesTest.kt @@ -23,13 +23,13 @@ class SummaryExceptionClusteringExamplesTest : SummaryTestCaseGeneratorTest( "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + "{@code (i == 1): True}\n" + - "@utbot.throwsException {@link org.utbot.examples.exceptions.MyCheckedException} after condition: {@code i == 1}" + "@utbot.throwsException {@link org.utbot.examples.exceptions.MyCheckedException} after condition: i == 1" val summary3 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + "{@code (i == 1): False},\n" + "{@code (i == 2): True}\n" + - "@utbot.throwsException {@link java.lang.IllegalArgumentException} after condition: {@code i == 2}" + "@utbot.throwsException {@link java.lang.IllegalArgumentException} after condition: i == 2" val summary4 = "@utbot.classUnderTest {@link ExceptionClusteringExamples}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.exceptions.ExceptionClusteringExamples#differentExceptions(int)}\n" + "@utbot.executesCondition {@code (i == 0): False},\n" + diff --git a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt index 0de99731de..5cfca1201b 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/structures/SummaryMinStackTest.kt @@ -64,7 +64,7 @@ class SummaryMinStackTest : SummaryTestCaseGeneratorTest( val summary1 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + "@utbot.executesCondition {@code (size <= 0): True}\n" + - "@utbot.throwsException {@link java.lang.RuntimeException} after condition: {@code size <= 0}" + "@utbot.throwsException {@link java.lang.RuntimeException} after condition: size <= 0" val summary2 = "@utbot.classUnderTest {@link MinStack}\n" + "@utbot.methodUnderTest {@link org.utbot.examples.structures.MinStack#removeValue()}\n" + From a52fb201a1778707c359844910764a8492b19e12 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 8 Aug 2022 10:45:57 +0300 Subject: [PATCH 22/29] Add comments, remove unused method --- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 10 ++-- .../examples/CustomJavaDocTagsEnabler.kt | 6 +++ .../examples/SummaryTestCaseGeneratorTest.kt | 46 ------------------- .../summary/comment/SimpleCommentBuilder.kt | 2 +- 4 files changed, 14 insertions(+), 50 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index eba45ad3b5..8795a1c9a8 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -22,10 +22,14 @@ private const val MESSAGE_SEPARATOR = ":" private val logger = KotlinLogging.logger {} +/** + * Generates UtBot specific sections to include them to rendered JavaDoc comment. + * + * Methods responsible for value generation were taken from IJ platform class (they are private and couldn't be used outside). + * + * See [com.intellij.codeInsight.javadoc.JavaDocInfoGenerator]. + */ class UtJavaDocInfoGenerator { - /** - * Generates UtBot specific sections to include them to rendered JavaDoc comment. - */ fun addUtBotSpecificSectionsToJavaDoc(javadoc: String?, comment: PsiDocComment): String { val builder: StringBuilder = StringBuilder(javadoc) val docTagProvider = UtCustomJavaDocTagProvider() diff --git a/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt index 347a293970..5929caad89 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/CustomJavaDocTagsEnabler.kt @@ -5,6 +5,12 @@ import org.junit.jupiter.api.extension.BeforeEachCallback import org.junit.jupiter.api.extension.ExtensionContext import org.utbot.framework.UtSettings +/** + * Controls the value of useCustomJavaDocTags global variable. + * + * Should be used in summary tests containing custom JavaDoc tags. + * To use it, add an annotation @ExtendWith(CustomJavaDocTagsEnabler::class) under test class. + */ class CustomJavaDocTagsEnabler(private val enable: Boolean = true) : BeforeEachCallback, AfterEachCallback { private var previousValue = false diff --git a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt index 806f97021a..6ed631a6ca 100644 --- a/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt +++ b/utbot-summary-tests/src/test/kotlin/examples/SummaryTestCaseGeneratorTest.kt @@ -160,52 +160,6 @@ open class SummaryTestCaseGeneratorTest( } } - fun List.checkMatchersWithCustomTagsInSummary( - comments: List - ) { - if (comments.isEmpty()) { - return - } - - val notMatchedExecutions = this.filter { execution -> - comments.none { comment -> - execution.summary?.toString()?.contains(comment) == true - } - } - - val notMatchedComments = comments.filter { comment -> - this.none { execution -> - execution.summary?.toString()?.contains(comment) == true - } - } - - Assertions.assertTrue(notMatchedExecutions.isEmpty() && notMatchedComments.isEmpty()) { - buildString { - if (notMatchedExecutions.isNotEmpty()) { - append( - "\nThe following comments were produced by the UTBot, " + - "but were not found in the list of comments passed in the check() method:\n\n${ - commentsFromExecutions( - notMatchedExecutions - ) - }" - ) - } - - if (notMatchedComments.isNotEmpty()) { - append( - "\nThe following comments were passed in the check() method, " + - "but were not found in the list of comments produced by the UTBot:\n\n${ - comments( - notMatchedComments - ) - }" - ) - } - } - } - } - fun List.checkMatchersWithMethodNames( methodNames: List, ) { diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index d291aa197b..ddfb0f0789 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -119,7 +119,7 @@ open class SimpleCommentBuilder( return stmts } - fun findExceptionReason(currentMethod: SootMethod, thrownException: Throwable): String { + protected fun findExceptionReason(currentMethod: SootMethod, thrownException: Throwable): String { val path = traceTag.path if (path.isEmpty()) { if (thrownException is ConcreteExecutionFailureException) { From 83f4e7111c3533bbd95d631ffec47d9cf10ebc35 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 9 Aug 2022 14:34:57 +0300 Subject: [PATCH 23/29] Review fixes: fixed formatting, removed redundant types --- .../model/visitor/CgAbstractRenderer.kt | 5 +- .../javadoc/UtCustomJavaDocTagProvider.kt | 6 +- .../plugin/javadoc/UtDocumentationProvider.kt | 34 +++---- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 89 ++++++++++--------- .../comment/CustomJavaDocCommentBuilder.kt | 4 +- 5 files changed, 73 insertions(+), 65 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt index 53e1e1a4ff..a173b27d18 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt @@ -317,7 +317,10 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer: override fun visit(element: CgCustomTagStatement) { if (element.content.all { it.isEmpty() }) return - for (stmt in element.content) stmt.accept(this) + + for (stmt in element.content) { + stmt.accept(this) + } } override fun visit(element: CgDocCodeStmt) { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt index 3c2aa9356b..c82e37b027 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtCustomJavaDocTagProvider.kt @@ -14,7 +14,7 @@ import org.utbot.summary.comment.CustomJavaDocTagProvider */ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { override fun getSupportedTags(): List = - CustomJavaDocTagProvider().getPluginCustomTags().map { t -> UtCustomTagInfo(t) } + CustomJavaDocTagProvider().getPluginCustomTags().map { UtCustomTagInfo(it) } class UtCustomTagInfo(private val tag: CustomJavaDocTag) : JavadocTagInfo { override fun getName(): String = tag.name @@ -27,8 +27,6 @@ class UtCustomJavaDocTagProvider : CustomJavadocTagProvider { override fun getReference(value: PsiDocTagValue?): PsiReference? = null - override fun isValidInContext(element: PsiElement?): Boolean { - return element is PsiMethod - } + override fun isValidInContext(element: PsiElement?): Boolean = element is PsiMethod } } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt index 6ea87ff656..62d6d07663 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt @@ -5,7 +5,6 @@ import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator import com.intellij.lang.java.JavaDocumentationProvider import com.intellij.psi.PsiDocCommentBase import com.intellij.psi.PsiJavaDocumentedElement -import com.intellij.psi.javadoc.PsiDocComment /** * To render UtBot custom JavaDoc tags correctly, we need to override the way it generates HTML tags for comments. @@ -14,22 +13,23 @@ import com.intellij.psi.javadoc.PsiDocComment * It renders text, code, and links. */ class UtDocumentationProvider : JavaDocumentationProvider() { - override fun generateRenderedDoc(comment: PsiDocCommentBase): String { - var target = comment.owner - if (target == null) target = comment - val docComment: PsiDocComment? - var finalJavaDoc = "" - if (target is PsiJavaDocumentedElement) { - docComment = target.docComment - if (docComment != null) { - val baseJavaDocInfoGenerator = JavaDocInfoGenerator(target.project, target) - val baseJavaDocInfo = baseJavaDocInfoGenerator.generateRenderedDocInfo() - val utJavaDocInfoGenerator = UtJavaDocInfoGenerator() - val javaDocInfoWithUtSections = - utJavaDocInfoGenerator.addUtBotSpecificSectionsToJavaDoc(baseJavaDocInfo, docComment) - finalJavaDoc = JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoWithUtSections)!! - } + override fun generateRenderedDoc(comment: PsiDocCommentBase): String? { + val target = comment.owner ?: comment + + if (target !is PsiJavaDocumentedElement) { + return "" } - return finalJavaDoc + + val docComment = target.docComment ?: return "" + + val baseJavaDocInfoGenerator = JavaDocInfoGenerator(target.project, target) + // get JavaDoc comment rendered by the platform. + val baseJavaDocInfo = baseJavaDocInfoGenerator.generateRenderedDocInfo() + val utJavaDocInfoGenerator = UtJavaDocInfoGenerator() + // add UTBot sections with custom tags. + val javaDocInfoWithUtSections = + utJavaDocInfoGenerator.addUtBotSpecificSectionsToJavaDoc(baseJavaDocInfo, docComment) + + return JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoWithUtSections) } } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index 8795a1c9a8..ed563a833c 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -31,7 +31,12 @@ private val logger = KotlinLogging.logger {} */ class UtJavaDocInfoGenerator { fun addUtBotSpecificSectionsToJavaDoc(javadoc: String?, comment: PsiDocComment): String { - val builder: StringBuilder = StringBuilder(javadoc) + val builder = if (javadoc == null) { + StringBuilder() + } else { + StringBuilder(javadoc) + } + val docTagProvider = UtCustomJavaDocTagProvider() docTagProvider.supportedTags.forEach { generateUtTagSection(builder, comment, it) @@ -44,49 +49,54 @@ class UtJavaDocInfoGenerator { */ private fun generateUtTagSection( builder: StringBuilder, - comment: PsiDocComment?, + comment: PsiDocComment, utTag: UtCustomJavaDocTagProvider.UtCustomTagInfo ) { - if (comment != null) { - val tag = comment.findTagByName(utTag.name) ?: return - startHeaderSection(builder, utTag.getMessage()).append("

") - val sectionContent = buildString { - generateValue(this, tag.dataElements) - this.trim { it <= ' ' } - } - builder.append(sectionContent) - builder.append(DocumentationMarkup.SECTION_END) + val tag = comment.findTagByName(utTag.name) ?: return + startHeaderSection(builder, utTag.getMessage()).append("

") + val sectionContent = buildString { + generateValue(this, tag.dataElements) + trim() } + + builder.append(sectionContent) + builder.append(DocumentationMarkup.SECTION_END) } - private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder { - return builder.append(DocumentationMarkup.SECTION_HEADER_START) + private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder = + builder.append(DocumentationMarkup.SECTION_HEADER_START) .append(message) .append(MESSAGE_SEPARATOR) .append(DocumentationMarkup.SECTION_SEPARATOR) - } /** * Generates info depending on tag's value type. */ private fun generateValue(builder: StringBuilder, elements: Array) { - var offset = if (elements.isNotEmpty()) { - elements[0].textOffset + elements[0].text.length - } else 0 - - for (i in elements.indices) { - if (elements[i].textOffset > offset) builder.append(' ') - offset = elements[i].textOffset + elements[i].text.length - val element = elements[i] - if (element is PsiInlineDocTag) { - when (element.name) { - LITERAL_TAG -> generateLiteralValue(builder, element) - CODE_TAG, SYSTEM_PROPERTY_TAG -> generateCodeValue(element, builder) - LINK_TAG -> generateLinkValue(element, builder, false) - LINKPLAIN_TAG -> generateLinkValue(element, builder, true) + if (elements.isEmpty()) { + return + } + + var offset = elements[0].textOffset + elements[0].text.length + + for (element in elements) { + with(element) { + if (textOffset > offset) { + builder.append(' ') + } + + offset = textOffset + text.length + + if (element is PsiInlineDocTag) { + when (element.name) { + LITERAL_TAG -> generateLiteralValue(builder, element) + CODE_TAG, SYSTEM_PROPERTY_TAG -> generateCodeValue(element, builder) + LINK_TAG -> generateLinkValue(element, builder, false) + LINKPLAIN_TAG -> generateLinkValue(element, builder, true) + } + } else { + appendPlainText(builder, text) } - } else { - appendPlainText(builder, element.text) } } } @@ -140,11 +150,11 @@ class UtJavaDocInfoGenerator { private fun generateLinkValue(tag: PsiInlineDocTag, builder: StringBuilder, plainLink: Boolean) { val tagElements = tag.dataElements - val linkText: String = createLinkText(tagElements) + val linkText = createLinkText(tagElements) if (linkText.isNotEmpty()) { val index = JavaDocUtil.extractReference(linkText) - val referenceText = linkText.substring(0, index).trim { it <= ' ' } - val label = StringUtil.nullize(linkText.substring(index).trim { it <= ' ' }) + val referenceText = linkText.substring(0, index).trim() + val label = StringUtil.nullize(linkText.substring(index).trim()) generateLink(builder, referenceText, label, tagElements[0], plainLink) } } @@ -166,7 +176,7 @@ class UtJavaDocInfoGenerator { this.append(' ') } } - }.trim { it <= ' ' } + }.trim() } private fun generateLink( @@ -176,10 +186,8 @@ class UtJavaDocInfoGenerator { context: PsiElement, plainLink: Boolean ) { - var linkLabel = label - if (label == null) { - val manager = context.manager - linkLabel = JavaDocUtil.getLabelText(manager.project, manager, refText, context) + val linkLabel = label ?: context.manager.let { + JavaDocUtil.getLabelText(it.project, it, refText, context) } var target: PsiElement? = null @@ -196,9 +204,8 @@ class UtJavaDocInfoGenerator { } else if (target == null) { builder.append("").append(linkLabel).append("") } else { - val referenceText = JavaDocUtil.getReferenceText(target.project, target) - if (referenceText != null) { - DocumentationManagerUtil.createHyperlink(builder, target, referenceText, linkLabel, plainLink) + JavaDocUtil.getReferenceText(target.project, target)?.let { + DocumentationManagerUtil.createHyperlink(builder, target, it, linkLabel, plainLink) } } } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index 703a21510d..0f186ea373 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -16,10 +16,10 @@ class CustomJavaDocCommentBuilder( * Collects statements for final JavaDoc comment. */ fun buildDocStatements(method: SootMethod): List { - val comment: CustomJavaDocComment = buildCustomJavaDocComment(method) + val comment = buildCustomJavaDocComment(method) val docStatementList = CustomJavaDocTagProvider().getPluginCustomTags().mapNotNull { it.generateDocStatement(comment) } - return listOf(DocCustomTagStatement(docStatementList)) + return listOf(DocCustomTagStatement(docStatementList)) } private fun buildCustomJavaDocComment(currentMethod: SootMethod): CustomJavaDocComment { From abe7ca69df59c4438983b6d756ddb5b5e9ae12a2 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 15 Aug 2022 09:48:00 +0300 Subject: [PATCH 24/29] Review fixes: fixed formatting, removed useless overriding methods --- .../org/utbot/framework/plugin/api/Api.kt | 7 +--- .../framework/codegen/model/tree/CgElement.kt | 11 ++---- .../model/visitor/CgAbstractRenderer.kt | 4 +-- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 35 ++++++++++++------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 7a3c1939eb..18489e9094 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1276,13 +1276,8 @@ class DocPreTagStatement(content: List) : DocTagStatement(content) override fun hashCode(): Int = content.hashCode() } -class DocCustomTagStatement(content: List) : DocTagStatement(content) { +data class DocCustomTagStatement(val statements: List) : DocTagStatement(statements) { override fun toString(): String = content.joinToString(separator = "") - - override fun equals(other: Any?): Boolean = - if (other is DocCustomTagStatement) this.hashCode() == other.hashCode() else false - - override fun hashCode(): Int = content.hashCode() } open class DocClassLinkStmt(val className: String) : DocStatement() { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt index 19ae5c7429..7e4b8302e7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt @@ -337,14 +337,7 @@ class CgDocPreTagStatement(content: List) : CgDocTagStatement(co override fun hashCode(): Int = content.hashCode() } -class CgCustomTagStatement(content: List) : CgDocTagStatement(content) { - override fun equals(other: Any?): Boolean = - if (other is CgCustomTagStatement) { - this.hashCode() == other.hashCode() - } else false - - override fun hashCode(): Int = content.hashCode() -} +data class CgCustomTagStatement(val statements: List) : CgDocTagStatement(statements) class CgDocCodeStmt(val stmt: String) : CgDocStatement() { override fun isEmpty(): Boolean = stmt.isEmpty() @@ -392,7 +385,7 @@ fun convertDocToCg(stmt: DocStatement): CgDocStatement { } is DocCustomTagStatement -> { val stmts = stmt.content.map { convertDocToCg(it) } - CgCustomTagStatement(content = stmts) + CgCustomTagStatement(statements = stmts) } is DocRegularStmt -> CgDocRegularStmt(stmt = stmt.stmt) is DocClassLinkStmt -> CgDocClassLinkStmt(className = stmt.className) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt index a173b27d18..77b739d174 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt @@ -316,9 +316,9 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer: } override fun visit(element: CgCustomTagStatement) { - if (element.content.all { it.isEmpty() }) return + if (element.statements.all { it.isEmpty() }) return - for (stmt in element.content) { + for (stmt in element.statements) { stmt.accept(this) } } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt index ed563a833c..df6dd82010 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt @@ -19,6 +19,9 @@ private const val LITERAL_TAG = "literal" private const val CODE_TAG = "code" private const val SYSTEM_PROPERTY_TAG = "systemProperty" private const val MESSAGE_SEPARATOR = ":" +private const val PARAGRAPH_TAG = "

" +private const val CODE_TAG_START = "" +private const val CODE_TAG_END = "" private val logger = KotlinLogging.logger {} @@ -53,7 +56,7 @@ class UtJavaDocInfoGenerator { utTag: UtCustomJavaDocTagProvider.UtCustomTagInfo ) { val tag = comment.findTagByName(utTag.name) ?: return - startHeaderSection(builder, utTag.getMessage()).append("

") + startHeaderSection(builder, utTag.getMessage()).append(PARAGRAPH_TAG) val sectionContent = buildString { generateValue(this, tag.dataElements) trim() @@ -120,14 +123,16 @@ class UtJavaDocInfoGenerator { } private fun generateCodeValue(tag: PsiInlineDocTag, builder: StringBuilder) { - builder.append("") + builder.append(CODE_TAG_START) val pos = builder.length generateLiteralValue(builder, tag) - builder.append("") - if (builder[pos] == '\n') builder.insert( - pos, - ' ' - ) // line break immediately after opening tag is ignored by JEditorPane + builder.append(CODE_TAG_END) + if (builder[pos] == '\n') { + builder.insert( + pos, + ' ' + ) // line break immediately after opening tag is ignored by JEditorPane + } } private fun generateLiteralValue(builder: StringBuilder, tag: PsiDocTag) { @@ -135,12 +140,16 @@ class UtJavaDocInfoGenerator { val children = tag.children for (i in 2 until children.size - 1) { // process all children except tag opening/closing elements val child = children[i] - if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) continue + if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) { + continue + } + var elementText = child.text if (child is PsiWhiteSpace) { val pos = elementText.lastIndexOf('\n') - if (pos >= 0) elementText = - elementText.substring(0, pos + 1) // skip whitespace before leading asterisk + if (pos >= 0) { + elementText = elementText.substring(0, pos + 1) // skip whitespace before leading asterisk + } } appendPlainText(this, StringUtil.escapeXmlEntities(elementText)) } @@ -169,10 +178,12 @@ class UtJavaDocInfoGenerator { return buildString { for (i in tagElements.indices) { val tagElement = tagElements[i] - if (tagElement.textOffset > offset) this.append(' ') + if (tagElement.textOffset > offset) { + this.append(' ') + } offset = tagElement.textOffset + tagElement.text.length collectElementText(this, tagElement) - if (i < tagElements.size - 1) { + if (i < tagElements.lastIndex) { this.append(' ') } } From 475cae5cb956f1439b14b930a4a9fca99fbc589d Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Mon, 15 Aug 2022 10:32:40 +0300 Subject: [PATCH 25/29] Review fixes: extracted method, polished code --- .../comment/CustomJavaDocCommentBuilder.kt | 7 ++-- .../comment/CustomJavaDocTagProvider.kt | 20 +++++++----- .../summary/comment/SimpleCommentBuilder.kt | 32 +++++++++---------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt index 0f186ea373..5655729db0 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocCommentBuilder.kt @@ -49,6 +49,7 @@ class CustomJavaDocCommentBuilder( val reason = findExceptionReason(currentMethod, thrownException) "{@link $exceptionName} $reason" } + if (exceptionThrow != null) { customJavaDocComment.throwsException = exceptionThrow } @@ -64,9 +65,8 @@ class CustomJavaDocCommentBuilder( } // builds Invoke, Execute, Return sections - var currentBlock: SimpleSentenceBlock? = rootSentenceBlock - while (currentBlock != null) { - for (statement in currentBlock.stmtTexts) { + 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}}" @@ -76,7 +76,6 @@ class CustomJavaDocCommentBuilder( } } } - currentBlock = currentBlock.nextBlock } return customJavaDocComment diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt index 7c6fcf256e..b1db88048b 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/CustomJavaDocTagProvider.kt @@ -45,12 +45,16 @@ sealed class CustomJavaDocTag( object ThrowsException : CustomJavaDocTag("utbot.throwsException", "Throws exception", CustomJavaDocComment::throwsException) - fun generateDocStatement(comment: CustomJavaDocComment): DocRegularStmt? { - val value = valueRetriever.invoke(comment) - return if (value is String) { - if (value.isNotEmpty()) DocRegularStmt("@$name $value\n") else null - } else if (value is List<*>) { - if (value.isNotEmpty()) DocRegularStmt("@$name ${value.joinToString(separator = ",\n")}\n") else null - } else null - } + fun generateDocStatement(comment: CustomJavaDocComment): DocRegularStmt? = + when (val value = valueRetriever.invoke(comment)) { + is String -> value.takeIf { it.isNotEmpty() }?.let { + DocRegularStmt("@$name $value\n") + } + is List<*> -> value.takeIf { it.isNotEmpty() }?.let { + val valueToString = value.joinToString(separator = ",\n", postfix = "\n") + + DocRegularStmt("@$name $valueToString") + } + else -> null + } } \ No newline at end of file diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index ddfb0f0789..05fe750e87 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -42,7 +42,21 @@ open class SimpleCommentBuilder( */ open fun buildString(currentMethod: SootMethod): String { val root = SimpleSentenceBlock(stringTemplates = stringTemplates) + buildThrownExceptionInfo(root, currentMethod) + skippedIterations() + buildSentenceBlock(traceTag.rootStatementTag, root, currentMethod) + var sentence = toSentence(root) + if (sentence.isEmpty()) return genWarnNotification() + sentence = splitLongSentence(sentence) + sentence = lastCommaToDot(sentence) + return "

\n$sentence
".replace(CARRIAGE_RETURN, "") + } + + private fun buildThrownExceptionInfo( + root: SimpleSentenceBlock, + currentMethod: SootMethod + ) { val thrownException = traceTag.result.exceptionOrNull() if (thrownException == null) { root.exceptionThrow = traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } @@ -51,14 +65,6 @@ open class SimpleCommentBuilder( val reason = findExceptionReason(currentMethod, thrownException) root.exceptionThrow = "$exceptionName $reason" } - skippedIterations() - buildSentenceBlock(traceTag.rootStatementTag, root, currentMethod) - var sentence = toSentence(root) - if (sentence.isEmpty()) return genWarnNotification() - sentence = splitLongSentence(sentence) - sentence = lastCommaToDot(sentence) - - return "
\n$sentence
".replace(CARRIAGE_RETURN, "") } /** @@ -79,15 +85,7 @@ open class SimpleCommentBuilder( private fun buildSentenceBlock(currentMethod: SootMethod): SimpleSentenceBlock { val rootSentenceBlock = SimpleSentenceBlock(stringTemplates = stringTemplates) - - val thrownException = traceTag.result.exceptionOrNull() - if (thrownException == null) { - rootSentenceBlock.exceptionThrow = traceTag.result.exceptionOrNull()?.let { it::class.qualifiedName } - } else { - val exceptionName = thrownException.javaClass.simpleName - val reason = findExceptionReason(currentMethod, thrownException) - rootSentenceBlock.exceptionThrow = "$exceptionName $reason" - } + buildThrownExceptionInfo(rootSentenceBlock, currentMethod) skippedIterations() buildSentenceBlock(traceTag.rootStatementTag, rootSentenceBlock, currentMethod) return rootSentenceBlock From 99b06ad5a5fce5abcbebc94fcd104d1b75955ec3 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Wed, 17 Aug 2022 14:37:38 +0300 Subject: [PATCH 26/29] fix after rebasing --- .../src/main/kotlin/org/utbot/summary/Summarization.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt index 316006b06d..85fdf0b3fe 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt @@ -5,7 +5,6 @@ import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.UtClusterInfo import org.utbot.framework.plugin.api.UtSymbolicExecution import org.utbot.framework.plugin.api.UtExecutionCluster -import org.utbot.framework.plugin.api.UtExecutionCreator import org.utbot.framework.plugin.api.UtMethodTestSet import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter import org.utbot.summary.SummarySentenceConstants.NEW_LINE @@ -29,7 +28,6 @@ import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.UtFuzzedExecution import org.utbot.summary.fuzzer.names.MethodBasedNameSuggester import org.utbot.summary.fuzzer.names.ModelBasedNameSuggester -import org.utbot.summary.UtSummarySettings.USE_CUSTOM_JAVADOC_TAGS import org.utbot.summary.comment.CustomJavaDocCommentBuilder import soot.SootMethod From 21a7035d51f35d904666f6cada14e55bf1978ce1 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 23 Aug 2022 12:11:50 +0300 Subject: [PATCH 27/29] fix after rebasing --- .../test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt | 3 ++- .../kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt | 2 +- .../org/utbot/summary/comment/SimpleCommentBuilderTest.kt | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt index 3172329ca8..a72f2b446b 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/UtValueTestCaseChecker.kt @@ -31,6 +31,7 @@ import org.utbot.framework.coverage.toAtLeast import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.DocClassLinkStmt import org.utbot.framework.plugin.api.DocCodeStmt +import org.utbot.framework.plugin.api.DocCustomTagStatement import org.utbot.framework.plugin.api.DocMethodLinkStmt import org.utbot.framework.plugin.api.DocPreTagStatement import org.utbot.framework.plugin.api.DocRegularStmt @@ -60,7 +61,6 @@ import org.utbot.framework.plugin.api.util.kClass import org.utbot.framework.plugin.api.util.withUtContext import org.utbot.framework.util.Conflict import org.utbot.framework.util.toValueTestCase -import org.utbot.summary.UtSummarySettings import org.utbot.summary.summarize import java.io.File import java.nio.file.Path @@ -2747,6 +2747,7 @@ private fun flattenDocStatements(summary: List): List flatten.add(s) is DocCodeStmt -> flatten.add(s) is DocRegularStmt -> flatten.add(s) + is DocCustomTagStatement -> flatten.add(s) } } return flatten diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt index 05fe750e87..3a57924058 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/comment/SimpleCommentBuilder.kt @@ -352,7 +352,7 @@ open class SimpleCommentBuilder( * In case when an enclosing class in nested, we need to replace '$' with '.' * to render the reference. */ - protected fun getMethodReference(className: String, methodName: String, methodParameterTypes: List): String { + fun getMethodReference(className: String, methodName: String, methodParameterTypes: List): String { val prettyClassName: String = className.replace("$", ".") return if (methodParameterTypes.isEmpty()) { diff --git a/utbot-summary/src/test/kotlin/org/utbot/summary/comment/SimpleCommentBuilderTest.kt b/utbot-summary/src/test/kotlin/org/utbot/summary/comment/SimpleCommentBuilderTest.kt index 39b995ccad..ba1d82e02b 100644 --- a/utbot-summary/src/test/kotlin/org/utbot/summary/comment/SimpleCommentBuilderTest.kt +++ b/utbot-summary/src/test/kotlin/org/utbot/summary/comment/SimpleCommentBuilderTest.kt @@ -67,7 +67,7 @@ class SimpleCommentBuilderTest { @Test fun `builds inline link for method`() { val commentBuilder = SimpleCommentBuilder(traceTag, sootToAst) - val methodReference = commentBuilder.invokeDescription("org.utbot.ClassName", "methodName", listOf()) + val methodReference = commentBuilder.getMethodReference("org.utbot.ClassName", "methodName", listOf()) val expectedMethodReference = "{@link org.utbot.ClassName#methodName()}" assertEquals(methodReference, expectedMethodReference) } @@ -76,7 +76,7 @@ class SimpleCommentBuilderTest { fun `builds inline link for method in nested class`() { val commentBuilder = SimpleCommentBuilder(traceTag, sootToAst) val methodReference = - commentBuilder.invokeDescription("org.utbot.ClassName\$NestedClassName", "methodName", listOf()) + commentBuilder.getMethodReference("org.utbot.ClassName\$NestedClassName", "methodName", listOf()) val expectedMethodReference = "{@link org.utbot.ClassName.NestedClassName#methodName()}" assertEquals(methodReference, expectedMethodReference) } From 4951b6f0d103fd6a318861fc7b6a25c13e0b7e4a Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 23 Aug 2022 17:17:35 +0300 Subject: [PATCH 28/29] review fixes --- .../framework/codegen/model/tree/CgElement.kt | 3 +++ .../main/kotlin/org/utbot/summary/Summarization.kt | 14 ++++++++------ .../summary/comment/CustomJavaDocCommentBuilder.kt | 5 ++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt index 7e4b8302e7..4c84ce2a8c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt @@ -337,6 +337,9 @@ class CgDocPreTagStatement(content: List) : CgDocTagStatement(co override fun hashCode(): Int = content.hashCode() } +/** + * Represents a type for statements containing custom JavaDoc tags. + */ data class CgCustomTagStatement(val statements: List) : CgDocTagStatement(statements) class CgDocCodeStmt(val stmt: String) : CgDocStatement() { diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt index 85fdf0b3fe..133fa77ec6 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt @@ -155,12 +155,14 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List @@ -72,7 +75,7 @@ class CustomJavaDocCommentBuilder( StmtType.Condition -> customJavaDocComment.executesCondition += "{@code ${statement.description}}" StmtType.Return -> customJavaDocComment.returnsFrom = "{@code ${statement.description}}" else -> { - //TODO: do we need to handle others? + //TODO: see [issue-773](https://github.com/UnitTestBot/UTBotJava/issues/773) } } } From bd616a98e25e945a922f0b1482f62bb1d6d8cf60 Mon Sep 17 00:00:00 2001 From: Zarina Kurbatova Date: Tue, 23 Aug 2022 22:32:12 +0300 Subject: [PATCH 29/29] fix rendering after updating to idea 2022.1. now we don't need to generate comment content with HTML tags, we need only replace custom tags' names with their messages to make it look nice --- .../plugin/javadoc/UtDocumentationProvider.kt | 39 +-- .../plugin/javadoc/UtJavaDocInfoGenerator.kt | 223 ------------------ 2 files changed, 25 insertions(+), 237 deletions(-) delete mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt index 62d6d07663..e8b9be9757 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtDocumentationProvider.kt @@ -1,16 +1,14 @@ package org.utbot.intellij.plugin.javadoc import com.intellij.codeInsight.javadoc.JavaDocExternalFilter -import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator +import com.intellij.codeInsight.javadoc.JavaDocInfoGeneratorFactory import com.intellij.lang.java.JavaDocumentationProvider import com.intellij.psi.PsiDocCommentBase import com.intellij.psi.PsiJavaDocumentedElement /** - * To render UtBot custom JavaDoc tags correctly, we need to override the way it generates HTML tags for comments. - * We get JavaDoc info generated by IJ platform and include sections related to UTBot, - * each section relates to the specific JavaDoc tag. - * It renders text, code, and links. + * To render UtBot custom JavaDoc tags messages, we need to override basic behaviour of [JavaDocumentationProvider]. + * The IJ platform knows only custom tag names, so we need to add their messages in rendered comments to make it look nice. */ class UtDocumentationProvider : JavaDocumentationProvider() { override fun generateRenderedDoc(comment: PsiDocCommentBase): String? { @@ -20,16 +18,29 @@ class UtDocumentationProvider : JavaDocumentationProvider() { return "" } - val docComment = target.docComment ?: return "" + val baseJavaDocInfoGenerator = JavaDocInfoGeneratorFactory.getBuilder(target.getProject()) + .setPsiElement(target) + .setIsGenerationForRenderedDoc(true) + .create() - val baseJavaDocInfoGenerator = JavaDocInfoGenerator(target.project, target) - // get JavaDoc comment rendered by the platform. - val baseJavaDocInfo = baseJavaDocInfoGenerator.generateRenderedDocInfo() - val utJavaDocInfoGenerator = UtJavaDocInfoGenerator() - // add UTBot sections with custom tags. - val javaDocInfoWithUtSections = - utJavaDocInfoGenerator.addUtBotSpecificSectionsToJavaDoc(baseJavaDocInfo, docComment) + val finalDocContent = replaceTagNamesWithMessages(baseJavaDocInfoGenerator.generateRenderedDocInfo()) - return JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoWithUtSections) + return JavaDocExternalFilter.filterInternalDocInfo(finalDocContent) } + + /** + * Replaces names of plugin's custom JavaDoc tags with their messages in the comment generated by the IJ platform. + * Example: utbot.MethodUnderTest -> Method under test. + */ + private fun replaceTagNamesWithMessages(comment: String?) = + comment?.let { + val docTagProvider = UtCustomJavaDocTagProvider() + docTagProvider.supportedTags.fold(it) { result, tag -> + if (result.contains(tag.name)) { + result.replace(tag.name, "${tag.getMessage()}:") + } else { + result + } + } + } ?: "" } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt deleted file mode 100644 index df6dd82010..0000000000 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/javadoc/UtJavaDocInfoGenerator.kt +++ /dev/null @@ -1,223 +0,0 @@ -package org.utbot.intellij.plugin.javadoc - -import com.intellij.codeInsight.documentation.DocumentationManagerUtil -import com.intellij.codeInsight.javadoc.JavaDocUtil -import com.intellij.lang.documentation.DocumentationMarkup -import com.intellij.openapi.project.DumbService -import com.intellij.openapi.project.IndexNotReadyException -import com.intellij.openapi.util.text.StringUtil -import com.intellij.psi.* -import com.intellij.psi.javadoc.PsiDocComment -import com.intellij.psi.javadoc.PsiDocTag -import com.intellij.psi.javadoc.PsiDocToken -import com.intellij.psi.javadoc.PsiInlineDocTag -import mu.KotlinLogging - -private const val LINK_TAG = "link" -private const val LINKPLAIN_TAG = "linkplain" -private const val LITERAL_TAG = "literal" -private const val CODE_TAG = "code" -private const val SYSTEM_PROPERTY_TAG = "systemProperty" -private const val MESSAGE_SEPARATOR = ":" -private const val PARAGRAPH_TAG = "

" -private const val CODE_TAG_START = "" -private const val CODE_TAG_END = "" - -private val logger = KotlinLogging.logger {} - -/** - * Generates UtBot specific sections to include them to rendered JavaDoc comment. - * - * Methods responsible for value generation were taken from IJ platform class (they are private and couldn't be used outside). - * - * See [com.intellij.codeInsight.javadoc.JavaDocInfoGenerator]. - */ -class UtJavaDocInfoGenerator { - fun addUtBotSpecificSectionsToJavaDoc(javadoc: String?, comment: PsiDocComment): String { - val builder = if (javadoc == null) { - StringBuilder() - } else { - StringBuilder(javadoc) - } - - val docTagProvider = UtCustomJavaDocTagProvider() - docTagProvider.supportedTags.forEach { - generateUtTagSection(builder, comment, it) - } - return builder.toString() - } - - /** - * Searches for UtBot tag in the comment and generates a related section for it. - */ - private fun generateUtTagSection( - builder: StringBuilder, - comment: PsiDocComment, - utTag: UtCustomJavaDocTagProvider.UtCustomTagInfo - ) { - val tag = comment.findTagByName(utTag.name) ?: return - startHeaderSection(builder, utTag.getMessage()).append(PARAGRAPH_TAG) - val sectionContent = buildString { - generateValue(this, tag.dataElements) - trim() - } - - builder.append(sectionContent) - builder.append(DocumentationMarkup.SECTION_END) - } - - private fun startHeaderSection(builder: StringBuilder, message: String): StringBuilder = - builder.append(DocumentationMarkup.SECTION_HEADER_START) - .append(message) - .append(MESSAGE_SEPARATOR) - .append(DocumentationMarkup.SECTION_SEPARATOR) - - /** - * Generates info depending on tag's value type. - */ - private fun generateValue(builder: StringBuilder, elements: Array) { - if (elements.isEmpty()) { - return - } - - var offset = elements[0].textOffset + elements[0].text.length - - for (element in elements) { - with(element) { - if (textOffset > offset) { - builder.append(' ') - } - - offset = textOffset + text.length - - if (element is PsiInlineDocTag) { - when (element.name) { - LITERAL_TAG -> generateLiteralValue(builder, element) - CODE_TAG, SYSTEM_PROPERTY_TAG -> generateCodeValue(element, builder) - LINK_TAG -> generateLinkValue(element, builder, false) - LINKPLAIN_TAG -> generateLinkValue(element, builder, true) - } - } else { - appendPlainText(builder, text) - } - } - } - } - - private fun appendPlainText(builder: StringBuilder, text: String) { - builder.append(StringUtil.replaceUnicodeEscapeSequences(text)) - } - - private fun collectElementText(builder: StringBuilder, element: PsiElement) { - element.accept(object : PsiRecursiveElementWalkingVisitor() { - override fun visitElement(element: PsiElement) { - super.visitElement(element) - if (element is PsiWhiteSpace || - element is PsiJavaToken || - element is PsiDocToken && element.tokenType !== JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS - ) { - builder.append(element.text) - } - } - }) - } - - private fun generateCodeValue(tag: PsiInlineDocTag, builder: StringBuilder) { - builder.append(CODE_TAG_START) - val pos = builder.length - generateLiteralValue(builder, tag) - builder.append(CODE_TAG_END) - if (builder[pos] == '\n') { - builder.insert( - pos, - ' ' - ) // line break immediately after opening tag is ignored by JEditorPane - } - } - - private fun generateLiteralValue(builder: StringBuilder, tag: PsiDocTag) { - val literalValue = buildString { - val children = tag.children - for (i in 2 until children.size - 1) { // process all children except tag opening/closing elements - val child = children[i] - if (child is PsiDocToken && child.tokenType === JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) { - continue - } - - var elementText = child.text - if (child is PsiWhiteSpace) { - val pos = elementText.lastIndexOf('\n') - if (pos >= 0) { - elementText = elementText.substring(0, pos + 1) // skip whitespace before leading asterisk - } - } - appendPlainText(this, StringUtil.escapeXmlEntities(elementText)) - } - } - builder.append(StringUtil.trimLeading(literalValue)) - } - - private fun generateLinkValue(tag: PsiInlineDocTag, builder: StringBuilder, plainLink: Boolean) { - val tagElements = tag.dataElements - val linkText = createLinkText(tagElements) - if (linkText.isNotEmpty()) { - val index = JavaDocUtil.extractReference(linkText) - val referenceText = linkText.substring(0, index).trim() - val label = StringUtil.nullize(linkText.substring(index).trim()) - generateLink(builder, referenceText, label, tagElements[0], plainLink) - } - } - - private fun createLinkText(tagElements: Array): String { - var offset = if (tagElements.isNotEmpty()) { - tagElements[0].textOffset + tagElements[0].text.length - } else { - 0 - } - - return buildString { - for (i in tagElements.indices) { - val tagElement = tagElements[i] - if (tagElement.textOffset > offset) { - this.append(' ') - } - offset = tagElement.textOffset + tagElement.text.length - collectElementText(this, tagElement) - if (i < tagElements.lastIndex) { - this.append(' ') - } - } - }.trim() - } - - private fun generateLink( - builder: StringBuilder, - refText: String?, - label: String?, - context: PsiElement, - plainLink: Boolean - ) { - val linkLabel = label ?: context.manager.let { - JavaDocUtil.getLabelText(it.project, it, refText, context) - } - - var target: PsiElement? = null - try { - if (refText != null) { - target = JavaDocUtil.findReferenceTarget(context.manager, refText, context) - } - } catch (e: IndexNotReadyException) { - logger.info(e) { "Failed to find a reference while generating JavaDoc comment. Details: ${e.message}" } - } - - if (target == null && DumbService.isDumb(context.project)) { - builder.append(linkLabel) - } else if (target == null) { - builder.append("").append(linkLabel).append("") - } else { - JavaDocUtil.getReferenceText(target.project, target)?.let { - DocumentationManagerUtil.createHyperlink(builder, target, it, linkLabel, plainLink) - } - } - } -} \ No newline at end of file