1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @summary Basic test of package-info in named module and duplicate
27 *          package-info in unnamed module
28 * @modules java.desktop
29 *          jdk.compiler
30 *          jdk.xml.dom
31 * @build jdk.xml.dom/org.w3c.dom.css.Fake
32 *        jdk.xml.dom/org.w3c.dom.css.FakePackage
33 * @compile/module=jdk.xml.dom org/w3c/dom/css/package-info.java
34 * @compile package-info.java PackageInfoTest.java
35 * @run testng p.PackageInfoTest
36 */
37
38package p;
39
40import java.io.IOException;
41import java.io.UncheckedIOException;
42import java.lang.annotation.Annotation;
43import java.net.URL;
44import java.net.URLClassLoader;
45import java.nio.file.Files;
46import java.nio.file.Path;
47import java.nio.file.Paths;
48import java.util.ArrayList;
49import java.util.Arrays;
50import java.util.List;
51
52import org.testng.annotations.DataProvider;
53import org.testng.annotations.Test;
54import org.w3c.dom.css.CSSRule;
55
56import javax.tools.JavaCompiler;
57import javax.tools.JavaFileObject;
58import javax.tools.StandardJavaFileManager;
59import javax.tools.ToolProvider;
60
61import static org.testng.Assert.*;
62
63public class PackageInfoTest {
64    @DataProvider(name = "jdkClasses")
65    public Object[][] jdkClasses() {
66        return new Object[][] {
67            { java.awt.Button.class,             null },
68            { java.lang.Object.class,            null },
69            { org.w3c.dom.css.CSSRule.class,     null },
70            { loadClass("org.w3c.dom.css.Fake"), loadClass("org.w3c.dom.css.FakePackage") },
71        };
72    }
73
74    @Test(dataProvider = "jdkClasses")
75    public void testPackageInfo(Class<?> type, Class<? extends Annotation> annType) {
76        Package pkg = type.getPackage();
77        assertTrue(pkg.isSealed());
78        assertTrue(annType == null || pkg.getDeclaredAnnotations().length != 0);
79        if (annType != null) {
80            assertTrue(pkg.isAnnotationPresent(annType));
81        }
82    }
83
84    private Class<?> loadClass(String name) {
85        return Class.forName(CSSRule.class.getModule(), name);
86    }
87
88    @DataProvider(name = "classpathClasses")
89    public Object[][] cpClasses() throws IOException, ClassNotFoundException {
90        // these classes will be loaded from classpath in unnamed module
91        return new Object[][]{
92                { p.PackageInfoTest.class, Deprecated.class }
93        };
94    }
95
96    @Test(dataProvider = "classpathClasses")
97    public void testClassPathPackage(Class<?> type, Class<? extends Annotation> annType) {
98        Package pkg = type.getPackage();
99        assertTrue(pkg.isSealed() == false);
100        assertTrue(pkg.isAnnotationPresent(annType));
101    }
102
103    static final String[] otherClasses = new String[] {
104            "p/package-info.class",
105            "p/Duplicate.class",
106            "p/Bar.class"
107    };
108
109    @Test
110    public void testDuplicatePackage() throws Exception {
111        // a custom class loader loading another package p annotated with @Duplicate
112        Path classes = Paths.get(System.getProperty("test.classes", "."), "tmp");
113        Files.createDirectories(classes);
114        URLClassLoader loader = new URLClassLoader(new URL[] { classes.toUri().toURL() });
115
116        // clean up before compiling classes
117        Arrays.stream(otherClasses)
118                .forEach(c -> {
119                    try {
120                        Files.deleteIfExists(classes.resolve(c));
121                    } catch (IOException e) {
122                        throw new UncheckedIOException(e);
123                    }
124                });
125
126        Path src = Paths.get(System.getProperty("test.src", "."), "src", "p");
127        compile(classes,
128                src.resolve("package-info.java"),
129                src.resolve("Duplicate.java"),
130                src.resolve("Bar.java"));
131
132        // verify if classes are present
133        Arrays.stream(otherClasses)
134              .forEach(c -> {
135                  if (Files.notExists(classes.resolve(c))) {
136                      throw new RuntimeException(c + " not exist");
137                  }
138        });
139
140        Class<?> c = Class.forName("p.Bar", true, loader);
141        assertTrue(c.getClassLoader() == loader);
142        assertTrue(this.getClass().getClassLoader() != loader);
143
144        // package p defined by the custom class loader
145        Package pkg = c.getPackage();
146        assertTrue(pkg.getName().equals("p"));
147        assertTrue(pkg.isSealed() == false);
148
149        // package p defined by the application class loader
150        Package p = this.getClass().getPackage();
151        assertTrue(p.getName().equals("p"));
152        assertTrue(p != pkg);
153
154        Arrays.stream(pkg.getDeclaredAnnotations())
155              .forEach(ann -> System.out.format("%s @%s%n", pkg.getName(), ann));
156
157        Arrays.stream(p.getDeclaredAnnotations())
158              .forEach(ann -> System.out.format("%s @%s%n", p.getName(), ann));
159
160        // local package p defined by loader
161        Class<? extends Annotation> ann =
162            (Class<? extends Annotation>)Class.forName("p.Duplicate", false, loader);
163        assertTrue(pkg.isAnnotationPresent(ann));
164    }
165
166    private void compile(Path destDir, Path... files) throws IOException {
167        compile(null, destDir, files);
168    }
169
170    private void compile(String option, Path destDir, Path... files)
171            throws IOException
172    {
173        System.err.println("compile...");
174        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
175        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
176            Iterable<? extends JavaFileObject> fileObjects =
177                fm.getJavaFileObjectsFromPaths(Arrays.asList(files));
178
179            List<String> options = new ArrayList<>();
180            if (option != null) {
181                options.add(option);
182            }
183            if (destDir != null) {
184                options.add("-d");
185                options.add(destDir.toString());
186            }
187            options.add("-cp");
188            options.add(System.getProperty("test.classes", "."));
189
190            JavaCompiler.CompilationTask task =
191                compiler.getTask(null, fm, null, options, null, fileObjects);
192            if (!task.call())
193                throw new AssertionError("compilation failed");
194        }
195    }
196
197}
198