diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.java deleted file mode 100644 index 38f4487927..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.java.BaseParserTest; - -public class ASTModuleDeclarationTest extends BaseParserTest { - - @Test - public void testAnnotatable() { - ASTCompilationUnit root = java9.parse("@A @B module foo { } "); - ASTModuleDeclaration mod = root.getModuleDeclaration(); - assertTrue(mod.isAnnotationPresent("A")); - assertTrue(mod.isAnnotationPresent("B")); - } - -} diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.kt new file mode 100644 index 0000000000..9549e4b824 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclarationTest.kt @@ -0,0 +1,120 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast + +import com.github.oowekyala.treeutils.matchers.TreeNodeWrapper +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.shouldBe +import net.sourceforge.pmd.lang.ast.Node +import net.sourceforge.pmd.lang.ast.test.NodeSpec +import net.sourceforge.pmd.lang.ast.test.shouldBe +import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.since +import net.sourceforge.pmd.lang.java.ast.JavaVersion.J9 +import net.sourceforge.pmd.lang.java.symbols.JClassSymbol + +/** + * @author Clément Fournier + * @since 7.0.0 + */ +class ASTModuleDeclarationTest : ParserTestSpec({ + + parserTest("Test annotations on module", javaVersions = since(J9)) { + val root: ASTCompilationUnit = parser.withProcessing(true).parse("@A @a.B module foo { } ") + root.moduleDeclaration.shouldMatchNode { + it.getAnnotation("A") shouldBe annotation("A") + it.getAnnotation("a.B") shouldBe annotation("B") + modName("foo") + } + } + + parserTest("opens decl") { + + inContext(ModuleDirectiveParsingContext) { + "opens a.package_ to a.module_;" should parseAs { + child { + it::getPackageName shouldBe "a.package_" + it.targetModules.toList() shouldBe listOf(modName("a.module_")) + } + } + "opens a to a.module_, another;" should parseAs { + child { + it::getPackageName shouldBe "a" + it.targetModules.toList() shouldBe listOf( + modName("a.module_"), + modName("another"), + ) + } + } + "opens a;" should parseAs { + child { + it::getPackageName shouldBe "a" + it.targetModules.toList().shouldBeEmpty() + } + } + } + } + + parserTest("exports decl") { + + inContext(ModuleDirectiveParsingContext) { + "exports a.package_ to a.module_;" should parseAs { + child { + it::getPackageName shouldBe "a.package_" + it.targetModules.toList() shouldBe listOf(modName("a.module_")) + } + } + "exports a to a.module_, another;" should parseAs { + child { + it::getPackageName shouldBe "a" + it.targetModules.toList() shouldBe listOf( + modName("a.module_"), + modName("another"), + ) + } + } + "exports a;" should parseAs { + child { + it::getPackageName shouldBe "a" + it.targetModules.toList().shouldBeEmpty() + } + } + } + } + + parserTest("Test uses") { + + inContext(ModuleDirectiveParsingContext) { + "uses a.package_;" should parseAs { + child { + it::getPackageName shouldBe "a.package_" + } + } + } + } + parserTest("Test provides") { + + inContext(ModuleDirectiveParsingContext) { + enableProcessing() + "provides an.Itf with imp1.Impl;" should parseAs { + child { + it::getProvidedInterface shouldBe classType("Itf") + it.implementations.toList() shouldBe listOf( + classType("Impl") { + val sym = it.referencedSym as JClassSymbol + sym.canonicalName shouldBe "imp1.Impl" + } + ) + } + } + } + } + +}) + +fun TreeNodeWrapper.modName(name: String, assertions: NodeSpec = EmptyAssertions) = + child { + it::getName shouldBe name + assertions(this) + } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt index 953b5edf97..baced81a93 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt @@ -211,7 +211,8 @@ open class ParserTestCtx(val javaVersion: JavaVersion = JavaVersion.Latest, parser = parser.withProcessing(true).logTypeInference(verbose, to) } - var fullSource: String? = null + /** Populated after an [asIfIn] call, used by [TypeBodyParsingCtx]. */ + internal var fullSource: String? = null /** Imports to add to the top of the parsing contexts. */ internal val imports: List diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/NodeParsingCtx.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/NodeParsingCtx.kt index 0d16a7762c..4f1c72d546 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/NodeParsingCtx.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/NodeParsingCtx.kt @@ -87,6 +87,27 @@ object ExpressionParsingCtx : NodeParsingCtx("expression") { .firstOrThrow() } +object RootParsingCtx : NodeParsingCtx("compilation unit") { + + override fun getTemplate(construct: String, ctx: ParserTestCtx): String = + construct + + override fun retrieveNode(acu: ASTCompilationUnit): ASTCompilationUnit = acu +} + +object ModuleDirectiveParsingContext : NodeParsingCtx("module directive") { + + override fun getTemplate(construct: String, ctx: ParserTestCtx): String = + """ + module test.module { + $construct + } + """.trimIndent() + + override fun retrieveNode(acu: ASTCompilationUnit): ASTModuleDirective = + acu.descendants(ASTModuleDirective::class.java).firstOrThrow() +} + object StatementParsingCtx : NodeParsingCtx("statement") { override fun getTemplate(construct: String, ctx: ParserTestCtx): String = @@ -101,6 +122,9 @@ object StatementParsingCtx : NodeParsingCtx("statement") { object TypeBodyParsingCtx : NodeParsingCtx("body declaration") { + /** + * Note: this code allows calling [ParserTestCtx.asIfIn] + */ override fun getTemplate(construct: String, ctx: ParserTestCtx): String { val source = ctx.fullSource return if (source != null) {