Add tests for module directives

This commit is contained in:
Clément Fournier
2022-04-01 21:03:04 +02:00
parent bc19d2cc40
commit b7c3e47591
4 changed files with 146 additions and 24 deletions

View File

@ -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"));
}
}

View File

@ -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<ASTModuleDeclaration> {
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<ASTModuleOpensDirective> {
it::getPackageName shouldBe "a.package_"
it.targetModules.toList() shouldBe listOf(modName("a.module_"))
}
}
"opens a to a.module_, another;" should parseAs {
child<ASTModuleOpensDirective> {
it::getPackageName shouldBe "a"
it.targetModules.toList() shouldBe listOf(
modName("a.module_"),
modName("another"),
)
}
}
"opens a;" should parseAs {
child<ASTModuleOpensDirective> {
it::getPackageName shouldBe "a"
it.targetModules.toList().shouldBeEmpty()
}
}
}
}
parserTest("exports decl") {
inContext(ModuleDirectiveParsingContext) {
"exports a.package_ to a.module_;" should parseAs {
child<ASTModuleExportsDirective> {
it::getPackageName shouldBe "a.package_"
it.targetModules.toList() shouldBe listOf(modName("a.module_"))
}
}
"exports a to a.module_, another;" should parseAs {
child<ASTModuleExportsDirective> {
it::getPackageName shouldBe "a"
it.targetModules.toList() shouldBe listOf(
modName("a.module_"),
modName("another"),
)
}
}
"exports a;" should parseAs {
child<ASTModuleExportsDirective> {
it::getPackageName shouldBe "a"
it.targetModules.toList().shouldBeEmpty()
}
}
}
}
parserTest("Test uses") {
inContext(ModuleDirectiveParsingContext) {
"uses a.package_;" should parseAs {
child<ASTModuleUsesDirective> {
it::getPackageName shouldBe "a.package_"
}
}
}
}
parserTest("Test provides") {
inContext(ModuleDirectiveParsingContext) {
enableProcessing()
"provides an.Itf with imp1.Impl;" should parseAs {
child<ASTModuleProvidesDirective> {
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<Node, *>.modName(name: String, assertions: NodeSpec<ASTModuleName> = EmptyAssertions) =
child<ASTModuleName> {
it::getName shouldBe name
assertions(this)
}

View File

@ -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<String>

View File

@ -87,6 +87,27 @@ object ExpressionParsingCtx : NodeParsingCtx<ASTExpression>("expression") {
.firstOrThrow()
}
object RootParsingCtx : NodeParsingCtx<ASTCompilationUnit>("compilation unit") {
override fun getTemplate(construct: String, ctx: ParserTestCtx): String =
construct
override fun retrieveNode(acu: ASTCompilationUnit): ASTCompilationUnit = acu
}
object ModuleDirectiveParsingContext : NodeParsingCtx<ASTModuleDirective>("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<ASTStatement>("statement") {
override fun getTemplate(construct: String, ctx: ParserTestCtx): String =
@ -101,6 +122,9 @@ object StatementParsingCtx : NodeParsingCtx<ASTStatement>("statement") {
object TypeBodyParsingCtx : NodeParsingCtx<ASTBodyDeclaration>("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) {