Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 45
Introduce custom JavaDoc tags #565#585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
e88bd6543c4cf0760594f050550fca86976d77e7396ae1157100e3df8d4063b6d01afed03ad7674c58227e4aaf992eb15dcf9b60f9c14eb06dce8507800d33d003962f8e6764321bf0da52fb2083f4e71abe7ca6475cae599b06ad21a70354951b6fbd616a9File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
amandelpie marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /** | ||
| * Enable the machine learning module to generate summaries for methods under test. | ||
| * True by default. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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,11 @@ class CgDocPreTagStatement(content: List<CgDocStatement>) : CgDocTagStatement(co | ||
| override fun hashCode(): Int = content.hashCode() | ||
| } | ||
| /** | ||
| * Represents a type for statements containing custom JavaDoc tags. | ||
| */ | ||
| data class CgCustomTagStatement(val statements: List<CgDocStatement>) : CgDocTagStatement(statements) | ||
onewhl marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| class CgDocCodeStmt(val stmt: String) : CgDocStatement() { | ||
amandelpie marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| override fun isEmpty(): Boolean = stmt.isEmpty() | ||
| @@ -379,6 +386,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(statements = stmts) | ||
| } | ||
| is DocRegularStmt -> CgDocRegularStmt(stmt = stmt.stmt) | ||
| is DocClassLinkStmt -> CgDocClassLinkStmt(className = stmt.className) | ||
| is DocMethodLinkStmt -> CgDocMethodLinkStmt(methodName = stmt.methodName, stmt = stmt.className) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| @@ -309,11 +310,19 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer: | ||
| } | ||
| override fun visit(element: CgDocPreTagStatement) { | ||
| if (element.content.all { it.isEmpty() }) return | ||
| println("<pre>") | ||
onewhl marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| for (stmt in element.content) stmt.accept(this) | ||
| println("</pre>") | ||
| } | ||
| override fun visit(element: CgCustomTagStatement) { | ||
| if (element.statements.all { it.isEmpty() }) return | ||
| for (stmt in element.statements) { | ||
| stmt.accept(this) | ||
| } | ||
| } | ||
| override fun visit(element: CgDocCodeStmt) { | ||
| if (element.isEmpty()) return | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| 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 | ||
| 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 { | ||
| override fun getSupportedTags(): List<UtCustomTagInfo> = | ||
| CustomJavaDocTagProvider().getPluginCustomTags().map { UtCustomTagInfo(it) } | ||
| class UtCustomTagInfo(private val tag: CustomJavaDocTag) : JavadocTagInfo { | ||
| override fun getName(): String = tag.name | ||
| fun getMessage(): String = tag.message | ||
| override fun isInline() = false | ||
| override fun checkTagValue(value: PsiDocTagValue?): String? = null | ||
| override fun getReference(value: PsiDocTagValue?): PsiReference? = null | ||
| override fun isValidInContext(element: PsiElement?): Boolean = element is PsiMethod | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package org.utbot.intellij.plugin.javadoc | ||
| import com.intellij.codeInsight.javadoc.JavaDocExternalFilter | ||
| 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 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? { | ||
| val target = comment.owner ?: comment | ||
| if (target !is PsiJavaDocumentedElement) { | ||
| return "" | ||
| } | ||
| val baseJavaDocInfoGenerator = JavaDocInfoGeneratorFactory.getBuilder(target.getProject()) | ||
| .setPsiElement(target) | ||
| .setIsGenerationForRenderedDoc(true) | ||
| .create() | ||
| val finalDocContent = replaceTagNamesWithMessages(baseJavaDocInfoGenerator.generateRenderedDocInfo()) | ||
| 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 | ||
| } | ||
| } | ||
| } ?: "" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| 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.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 | ||
| override fun beforeEach(context: ExtensionContext?) { | ||
| previousValue = UtSettings.useCustomJavaDocTags | ||
| UtSettings.useCustomJavaDocTags = enable | ||
| } | ||
| override fun afterEach(context: ExtensionContext?) { | ||
| UtSettings.useCustomJavaDocTags = previousValue | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| 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 | ||
| ) { | ||
| @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 | ||
| summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| 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 | ||
| ) { | ||
| @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 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 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: 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 | ||
| summaryCheck(method, mockStrategy, coverage, summaryKeys, methodNames, displayNames) | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.