ModuleDeclarationTest.java
/*
* Copyright (C) 2007-2010 J��lio Vilmar Gesser.
* Copyright (C) 2011, 2013-2024 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.modules;
import static com.github.javaparser.GeneratedJavaParserConstants.IDENTIFIER;
import static com.github.javaparser.ParserConfiguration.LanguageLevel.JAVA_9;
import static com.github.javaparser.Providers.provider;
import static com.github.javaparser.StaticJavaParser.parseName;
import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.IntegerLiteralExpr;
import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import com.github.javaparser.ast.modules.*;
import com.github.javaparser.printer.ConcreteSyntaxModel;
import com.github.javaparser.utils.LineSeparator;
import org.junit.jupiter.api.Test;
class ModuleDeclarationTest {
public static final JavaParser javaParser = new JavaParser(new ParserConfiguration().setLanguageLevel(JAVA_9));
private CompilationUnit parse(String code) {
ParseResult<CompilationUnit> result = javaParser.parse(ParseStart.COMPILATION_UNIT, provider(code));
if (!result.isSuccessful()) {
System.err.println(result);
}
return result.getResult().get();
}
@Test
void moduleInfoKeywordsAreSeenAsIdentifiers() {
CompilationUnit cu = parse("class module { }");
JavaToken moduleToken = cu.getClassByName("module")
.get()
.getName()
.getTokenRange()
.get()
.getBegin();
assertEquals(IDENTIFIER, moduleToken.getKind());
}
@Test
void issue988RequireTransitiveShouldRequireAModuleCalledTransitive() {
CompilationUnit cu = parse("module X { requires transitive; }");
ModuleRequiresDirective requiresTransitive =
(ModuleRequiresDirective) cu.getModule().get().getDirectives().get(0);
assertEquals("transitive", requiresTransitive.getNameAsString());
assertEquals(
IDENTIFIER,
requiresTransitive.getName().getTokenRange().get().getBegin().getKind());
}
@Test
void jlsExample1() {
CompilationUnit cu = parse("@Foo(1) @Foo(2) @Bar " + "module M.N {"
+ " requires A.B;"
+ " requires transitive C.D;"
+ " requires static E.F;"
+ " requires transitive static G.H;"
+ ""
+ " exports P.Q;"
+ " exports R.S to T1.U1, T2.U2;"
+ ""
+ " opens P.Q;"
+ " opens R.S to T1.U1, T2.U2;"
+ ""
+ " uses V.W;"
+ " provides X.Y with Z1.Z2, Z3.Z4;"
+ "}");
ModuleDeclaration module = cu.getModule().get();
assertEquals("M.N", module.getNameAsString());
assertFalse(module.isOpen());
assertThat(module.getAnnotations())
.containsExactly(
new SingleMemberAnnotationExpr(new Name("Foo"), new IntegerLiteralExpr("1")),
new SingleMemberAnnotationExpr(new Name("Foo"), new IntegerLiteralExpr("2")),
new MarkerAnnotationExpr(new Name("Bar")));
ModuleRequiresDirective moduleRequiresStmt =
module.getDirectives().get(0).asModuleRequiresStmt();
assertThat(moduleRequiresStmt.getNameAsString()).isEqualTo("A.B");
assertThat(moduleRequiresStmt.getModifiers()).isEmpty();
ModuleExportsDirective moduleExportsStmt = module.getDirectives().get(5).asModuleExportsStmt();
assertThat(moduleExportsStmt.getNameAsString()).isEqualTo("R.S");
assertThat(moduleExportsStmt.getModuleNames()).containsExactly(parseName("T1.U1"), parseName("T2.U2"));
ModuleOpensDirective moduleOpensStmt = module.getDirectives().get(7).asModuleOpensStmt();
assertThat(moduleOpensStmt.getNameAsString()).isEqualTo("R.S");
assertThat(moduleOpensStmt.getModuleNames()).containsExactly(parseName("T1.U1"), parseName("T2.U2"));
ModuleUsesDirective moduleUsesStmt = module.getDirectives().get(8).asModuleUsesStmt();
assertThat(moduleUsesStmt.getNameAsString()).isEqualTo("V.W");
ModuleProvidesDirective moduleProvidesStmt =
module.getDirectives().get(9).asModuleProvidesStmt();
assertThat(moduleProvidesStmt.getNameAsString()).isEqualTo("X.Y");
assertThat(moduleProvidesStmt.getWith()).containsExactly(parseName("Z1.Z2"), parseName("Z3.Z4"));
}
@Test
void jlsExample2HasAnOpenModule() {
CompilationUnit cu = parse("open module M.N {}");
ModuleDeclaration module = cu.getModule().get();
assertEquals("M.N", module.getNameAsString());
assertTrue(module.isOpen());
}
@Test
void testPrettyPrinting() {
CompilationUnit cu = parse("@Foo(1) @Foo(2) @Bar " + "module M.N {"
+ " requires A.B;"
+ " requires transitive C.D;"
+ " requires static E.F;"
+ " requires static transitive G.H;"
+ ""
+ " exports P.Q;"
+ " exports R.S to T1.U1, T2.U2;"
+ ""
+ " opens P.Q;"
+ " opens R.S to T1.U1, T2.U2;"
+ ""
+ " uses V.W;"
+ " provides X.Y with Z1.Z2, Z3.Z4;"
+ "}");
assertEquals(
"@Foo(1)" + LineSeparator.SYSTEM + "@Foo(2)"
+ LineSeparator.SYSTEM + "@Bar"
+ LineSeparator.SYSTEM + "module M.N {"
+ LineSeparator.SYSTEM + " requires A.B;"
+ LineSeparator.SYSTEM + " requires transitive C.D;"
+ LineSeparator.SYSTEM + " requires static E.F;"
+ LineSeparator.SYSTEM + " requires static transitive G.H;"
+ LineSeparator.SYSTEM + " exports P.Q;"
+ LineSeparator.SYSTEM + " exports R.S to T1.U1, T2.U2;"
+ LineSeparator.SYSTEM + " opens P.Q;"
+ LineSeparator.SYSTEM + " opens R.S to T1.U1, T2.U2;"
+ LineSeparator.SYSTEM + " uses V.W;"
+ LineSeparator.SYSTEM + " provides X.Y with Z1.Z2, Z3.Z4;"
+ LineSeparator.SYSTEM + "}"
+ LineSeparator.SYSTEM,
cu.toString());
}
@Test
void testCsmPrinting() {
CompilationUnit cu = parse("@Foo(1) @Foo(2) @Bar " + "open module M.N {"
+ " requires A.B;"
+ " requires transitive C.D;"
+ " requires static E.F;"
+ " requires transitive static G.H;"
+ ""
+ " exports P.Q;"
+ " exports R.S to T1.U1, T2.U2;"
+ ""
+ " opens P.Q;"
+ " opens R.S to T1.U1, T2.U2;"
+ ""
+ " uses V.W;"
+ " provides X.Y with Z1.Z2, Z3.Z4;"
+ "}");
assertEquals(
"@Foo(1)" + LineSeparator.SYSTEM + "@Foo(2)"
+ LineSeparator.SYSTEM + "@Bar"
+ LineSeparator.SYSTEM + "open module M.N {"
+ LineSeparator.SYSTEM + " requires A.B;"
+ LineSeparator.SYSTEM + " requires transitive C.D;"
+ LineSeparator.SYSTEM + " requires static E.F;"
+ LineSeparator.SYSTEM + " requires transitive static G.H;"
+ LineSeparator.SYSTEM + " exports P.Q;"
+ LineSeparator.SYSTEM + " exports R.S to T1.U1, T2.U2;"
+ LineSeparator.SYSTEM + " opens P.Q;"
+ LineSeparator.SYSTEM + " opens R.S to T1.U1, T2.U2;"
+ LineSeparator.SYSTEM + " uses V.W;"
+ LineSeparator.SYSTEM + " provides X.Y with Z1.Z2, Z3.Z4;"
+ LineSeparator.SYSTEM + "}"
+ LineSeparator.SYSTEM,
ConcreteSyntaxModel.genericPrettyPrint(cu));
}
@Test
void fluentInterface() {
ModuleDeclaration moduleDeclaration = new CompilationUnit()
.setModule("com.laamella.base")
.addSingleMemberAnnotation(SuppressWarnings.class, "\"module\"")
.addDirective("requires transitive java.desktop;")
.addDirective("exports com.laamella.base.entity.channel;")
.addDirective("exports com.laamella.base.entity.channel.internal to com.laamella.core;")
.addDirective("uses com.laamella.base.util.internal.FactoryDelegate;");
moduleDeclaration
.getDirectives()
.addLast(new ModuleExportsDirective()
.setName("foo.bar")
.addModuleName("other.foo")
.addModuleName("other.bar"));
moduleDeclaration.addDirective(new ModuleExportsDirective()
.setName("foo.bar.x")
.addModuleName("other.foo")
.addModuleName("other.bar"));
assertEqualsStringIgnoringEol(
"@SuppressWarnings(\"module\")\n" + "module com.laamella.base {\n"
+ " requires transitive java.desktop;\n"
+ " exports com.laamella.base.entity.channel;\n"
+ " exports com.laamella.base.entity.channel.internal to com.laamella.core;\n"
+ " uses com.laamella.base.util.internal.FactoryDelegate;\n"
+ " exports foo.bar to other.foo, other.bar;\n"
+ " exports foo.bar.x to other.foo, other.bar;\n"
+ "}\n",
moduleDeclaration.toString());
}
@Test
void testModifierRequire() {
ModuleDeclaration moduleDeclaration =
new CompilationUnit().setModule("com.laamella.base").addDirective("requires transitive java.desktop;");
ModuleRequiresDirective moduleRequiresStmt =
moduleDeclaration.getDirectives().get(0).asModuleRequiresStmt();
assertTrue(moduleRequiresStmt.isTransitive());
}
@Test
void testModifierStatic() {
ModuleDeclaration moduleDeclaration =
new CompilationUnit().setModule("com.laamella.base").addDirective("requires static java.desktop;");
ModuleRequiresDirective moduleRequiresStmt =
moduleDeclaration.getDirectives().get(0).asModuleRequiresStmt();
assertTrue(moduleRequiresStmt.isStatic());
}
}