1 package com.github.javaparser.modules;
2 
3 import com.github.javaparser.*;
4 import com.github.javaparser.ast.CompilationUnit;
5 import com.github.javaparser.ast.expr.IntegerLiteralExpr;
6 import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
7 import com.github.javaparser.ast.expr.Name;
8 import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
9 import com.github.javaparser.ast.modules.*;
10 import com.github.javaparser.printer.ConcreteSyntaxModel;
11 import org.junit.jupiter.api.Test;
12 
13 import static com.github.javaparser.GeneratedJavaParserConstants.IDENTIFIER;
14 import static com.github.javaparser.ParserConfiguration.LanguageLevel.JAVA_9;
15 import static com.github.javaparser.Providers.provider;
16 import static com.github.javaparser.StaticJavaParser.parseName;
17 import static com.github.javaparser.utils.TestUtils.assertEqualsNoEol;
18 import static com.github.javaparser.utils.Utils.EOL;
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.junit.jupiter.api.Assertions.*;
21 
22 class ModuleDeclarationTest {
23     public static final JavaParser javaParser = new JavaParser(new ParserConfiguration().setLanguageLevel(JAVA_9));
24 
parse(String code)25     private CompilationUnit parse(String code) {
26         ParseResult<CompilationUnit> result = javaParser.parse(ParseStart.COMPILATION_UNIT, provider(code));
27         if(!result.isSuccessful()){
28             System.err.println(result);
29         }
30         return result.getResult().get();
31     }
32 
33     @Test
moduleInfoKeywordsAreSeenAsIdentifiers()34     void moduleInfoKeywordsAreSeenAsIdentifiers() {
35         CompilationUnit cu = parse("class module { }");
36         JavaToken moduleToken = cu.getClassByName("module").get().getName().getTokenRange().get().getBegin();
37         assertEquals(IDENTIFIER, moduleToken.getKind());
38     }
39 
40     @Test
issue988RequireTransitiveShouldRequireAModuleCalledTransitive()41     void issue988RequireTransitiveShouldRequireAModuleCalledTransitive() {
42         CompilationUnit cu = parse("module X { requires transitive; }");
43         ModuleRequiresDirective requiresTransitive = (ModuleRequiresDirective) cu.getModule().get().getDirectives().get(0);
44         assertEquals("transitive", requiresTransitive.getNameAsString());
45         assertEquals(IDENTIFIER, requiresTransitive.getName().getTokenRange().get().getBegin().getKind());
46     }
47 
48     @Test
jlsExample1()49     void jlsExample1() {
50         CompilationUnit cu = parse(
51                 "@Foo(1) @Foo(2) @Bar " +
52                         "module M.N {" +
53                         "  requires A.B;" +
54                         "  requires transitive C.D;" +
55                         "  requires static E.F;" +
56                         "  requires transitive static G.H;" +
57                         "" +
58                         "  exports P.Q;" +
59                         "  exports R.S to T1.U1, T2.U2;" +
60                         "" +
61                         "  opens P.Q;" +
62                         "  opens R.S to T1.U1, T2.U2;" +
63                         "" +
64                         "  uses V.W;" +
65                         "  provides X.Y with Z1.Z2, Z3.Z4;" +
66                         "}");
67 
68         ModuleDeclaration module = cu.getModule().get();
69         assertEquals("M.N", module.getNameAsString());
70         assertFalse(module.isOpen());
71         assertThat(module.getAnnotations()).containsExactly(
72                 new SingleMemberAnnotationExpr(new Name("Foo"), new IntegerLiteralExpr("1")),
73                 new SingleMemberAnnotationExpr(new Name("Foo"), new IntegerLiteralExpr("2")),
74                 new MarkerAnnotationExpr(new Name("Bar")));
75 
76         ModuleRequiresDirective moduleRequiresStmt = module.getDirectives().get(0).asModuleRequiresStmt();
77         assertThat(moduleRequiresStmt.getNameAsString()).isEqualTo("A.B");
78         assertThat(moduleRequiresStmt.getModifiers()).isEmpty();
79 
80         ModuleExportsDirective moduleExportsStmt = module.getDirectives().get(5).asModuleExportsStmt();
81         assertThat(moduleExportsStmt.getNameAsString()).isEqualTo("R.S");
82         assertThat(moduleExportsStmt.getModuleNames()).containsExactly(parseName("T1.U1"), parseName("T2.U2"));
83 
84         ModuleOpensDirective moduleOpensStmt = module.getDirectives().get(7).asModuleOpensStmt();
85         assertThat(moduleOpensStmt.getNameAsString()).isEqualTo("R.S");
86         assertThat(moduleOpensStmt.getModuleNames()).containsExactly(parseName("T1.U1"), parseName("T2.U2"));
87 
88         ModuleUsesDirective moduleUsesStmt = module.getDirectives().get(8).asModuleUsesStmt();
89         assertThat(moduleUsesStmt.getNameAsString()).isEqualTo("V.W");
90 
91         ModuleProvidesDirective moduleProvidesStmt = module.getDirectives().get(9).asModuleProvidesStmt();
92         assertThat(moduleProvidesStmt.getNameAsString()).isEqualTo("X.Y");
93         assertThat(moduleProvidesStmt.getWith()).containsExactly(
94                 parseName("Z1.Z2"),
95                 parseName("Z3.Z4"));
96 
97     }
98 
99     @Test
jlsExample2HasAnOpenModule()100     void jlsExample2HasAnOpenModule() {
101         CompilationUnit cu = parse("open module M.N {}");
102 
103         ModuleDeclaration module = cu.getModule().get();
104         assertEquals("M.N", module.getNameAsString());
105         assertTrue(module.isOpen());
106     }
107 
108     @Test
testPrettyPrinting()109     void testPrettyPrinting() {
110         CompilationUnit cu = parse(
111                 "@Foo(1) @Foo(2) @Bar " +
112                         "module M.N {" +
113                         "  requires A.B;" +
114                         "  requires transitive C.D;" +
115                         "  requires static E.F;" +
116                         "  requires static transitive G.H;" +
117                         "" +
118                         "  exports P.Q;" +
119                         "  exports R.S to T1.U1, T2.U2;" +
120                         "" +
121                         "  opens P.Q;" +
122                         "  opens R.S to T1.U1, T2.U2;" +
123                         "" +
124                         "  uses V.W;" +
125                         "  provides X.Y with Z1.Z2, Z3.Z4;" +
126                         "}");
127 
128         assertEquals(
129                 "@Foo(1)" + EOL +
130                         "@Foo(2)" + EOL +
131                         "@Bar" + EOL +
132                         "module M.N {" + EOL +
133                         "    requires A.B;" + EOL +
134                         "    requires transitive C.D;" + EOL +
135                         "    requires static E.F;" + EOL +
136                         "    requires static transitive G.H;" + EOL +
137                         "    exports P.Q;" + EOL +
138                         "    exports R.S to T1.U1, T2.U2;" + EOL +
139                         "    opens P.Q;" + EOL +
140                         "    opens R.S to T1.U1, T2.U2;" + EOL +
141                         "    uses V.W;" + EOL +
142                         "    provides X.Y with Z1.Z2, Z3.Z4;" + EOL +
143                         "}" + EOL, cu.toString());
144 
145     }
146 
147     @Test
testCsmPrinting()148     void testCsmPrinting() {
149         CompilationUnit cu = parse(
150                 "@Foo(1) @Foo(2) @Bar " +
151                         "open module M.N {" +
152                         "  requires A.B;" +
153                         "  requires transitive C.D;" +
154                         "  requires static E.F;" +
155                         "  requires transitive static G.H;" +
156                         "" +
157                         "  exports P.Q;" +
158                         "  exports R.S to T1.U1, T2.U2;" +
159                         "" +
160                         "  opens P.Q;" +
161                         "  opens R.S to T1.U1, T2.U2;" +
162                         "" +
163                         "  uses V.W;" +
164                         "  provides X.Y with Z1.Z2, Z3.Z4;" +
165                         "}");
166 
167         assertEquals(
168                 "@Foo(1)" + EOL +
169                         "@Foo(2)" + EOL +
170                         "@Bar" + EOL +
171                         "open module M.N {" + EOL +
172                         "    requires A.B;" + EOL +
173                         "    requires transitive C.D;" + EOL +
174                         "    requires static E.F;" + EOL +
175                         "    requires transitive static G.H;" + EOL +
176                         "    exports P.Q;" + EOL +
177                         "    exports R.S to T1.U1, T2.U2;" + EOL +
178                         "    opens P.Q;" + EOL +
179                         "    opens R.S to T1.U1, T2.U2;" + EOL +
180                         "    uses V.W;" + EOL +
181                         "    provides X.Y with Z1.Z2, Z3.Z4;" + EOL +
182                         "}" + EOL, ConcreteSyntaxModel.genericPrettyPrint(cu));
183 
184     }
185 
186     @Test
fluentInterface()187     void fluentInterface() {
188         ModuleDeclaration moduleDeclaration = new CompilationUnit()
189                 .setModule("com.laamella.base")
190                 .addSingleMemberAnnotation(SuppressWarnings.class, "\"module\"")
191                 .addDirective("requires transitive java.desktop;")
192                 .addDirective("exports com.laamella.base.entity.channel;")
193                 .addDirective("exports com.laamella.base.entity.channel.internal to com.laamella.core;")
194                 .addDirective("uses com.laamella.base.util.internal.FactoryDelegate;");
195 
196         moduleDeclaration.getDirectives()
197                 .addLast(new ModuleExportsDirective()
198                         .setName("foo.bar")
199                         .addModuleName("other.foo")
200                         .addModuleName("other.bar")
201                 );
202 
203         moduleDeclaration
204                 .addDirective(new ModuleExportsDirective()
205                         .setName("foo.bar.x")
206                         .addModuleName("other.foo")
207                         .addModuleName("other.bar")
208                 );
209 
210         assertEqualsNoEol("@SuppressWarnings(\"module\")\n" +
211                 "module com.laamella.base {\n" +
212                 "    requires transitive java.desktop;\n" +
213                 "    exports com.laamella.base.entity.channel;\n" +
214                 "    exports com.laamella.base.entity.channel.internal to com.laamella.core;\n" +
215                 "    uses com.laamella.base.util.internal.FactoryDelegate;\n" +
216                 "    exports foo.bar to other.foo, other.bar;\n" +
217                 "    exports foo.bar.x to other.foo, other.bar;\n" +
218                 "}\n", moduleDeclaration.toString());
219     }
220 }
221