Java tutorial
/* * Copyright Red Hat Inc. and/or its affiliates and other contributors * as indicated by the authors tag. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. * * This particular file is subject to the "Classpath" exception as provided in the * LICENSE file that accompanied this code. * * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License, * along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package com.redhat.ceylon.compiler.java.test.cmr; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; import com.redhat.ceylon.cmr.api.DependencyResolver; import com.redhat.ceylon.cmr.api.MavenArtifactContext; import com.redhat.ceylon.cmr.api.ModuleInfo; import com.redhat.ceylon.cmr.api.RepositoryManager; import com.redhat.ceylon.cmr.ceylon.CeylonUtils; import com.redhat.ceylon.cmr.ceylon.CeylonUtils.CeylonRepoManagerBuilder; import com.redhat.ceylon.cmr.maven.MavenDependencyResolver; import com.redhat.ceylon.common.FileUtil; import com.redhat.ceylon.common.ModuleSpec; import com.redhat.ceylon.common.Versions; import com.redhat.ceylon.common.config.Repositories; import com.redhat.ceylon.compiler.java.test.CompilerError; import com.redhat.ceylon.compiler.java.test.CompilerTests; import com.redhat.ceylon.compiler.java.test.ErrorCollector; import com.redhat.ceylon.compiler.java.test.RunSingleThreaded; import com.redhat.ceylon.compiler.java.tools.CeyloncTaskImpl; import com.redhat.ceylon.compiler.java.tools.LanguageCompiler; import com.redhat.ceylon.compiler.java.util.Util; import com.redhat.ceylon.compiler.typechecker.context.Context; import com.redhat.ceylon.javax.tools.Diagnostic; import com.redhat.ceylon.javax.tools.DiagnosticListener; import com.redhat.ceylon.javax.tools.FileObject; import com.redhat.ceylon.javax.tools.JavaCompiler; import com.redhat.ceylon.javax.tools.JavaCompiler.CompilationTask; import com.redhat.ceylon.javax.tools.JavaFileObject; import com.redhat.ceylon.javax.tools.StandardJavaFileManager; import com.redhat.ceylon.javax.tools.ToolProvider; import com.redhat.ceylon.langtools.source.util.TaskEvent; import com.redhat.ceylon.langtools.source.util.TaskListener; import com.redhat.ceylon.model.cmr.JDKUtils; import com.redhat.ceylon.model.loader.OsgiUtil; import com.redhat.ceylon.model.typechecker.model.Module; import com.redhat.ceylon.model.typechecker.model.ModuleImport; import com.redhat.ceylon.model.typechecker.model.Modules; @RunSingleThreaded public class CMRTests extends CompilerTests { // // Modules @Test public void testMdlByName() throws IOException { List<String> options = new LinkedList<String>(); options.add("-src"); options.add(getPackagePath() + "/modules/byName"); options.addAll(defaultOptions); CeyloncTaskImpl task = getCompilerTask(options, null, Arrays.asList("default", "mod")); Boolean ret = task.call(); assertTrue(ret); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("def/Foo.class"); assertNotNull(moduleClass); ZipEntry moduleClassDir = car.getEntry("def/"); assertNotNull(moduleClassDir); assertTrue(moduleClassDir.isDirectory()); car.close(); carFile = getModuleArchive("mod", "1"); assertTrue(carFile.exists()); car = new JarFile(carFile); moduleClass = car.getEntry("mod/$module_.class"); assertNotNull(moduleClass); moduleClassDir = car.getEntry("mod/"); assertNotNull(moduleClassDir); assertTrue(moduleClassDir.isDirectory()); car.close(); } @Test public void testMdlEndsWithJava() throws IOException { List<String> options = new LinkedList<String>(); options.add("-src"); options.add(dir); options.addAll(defaultOptions); CeyloncTaskImpl task = getCompilerTask(options, null, Arrays.asList("com.redhat.ceylon.compiler.java.test.cmr.modules.java")); Boolean ret = task.call(); assertTrue(ret); } @Test public void testMdlModuleDefault() throws IOException { compile("modules/def/CeylonClass.ceylon"); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/def/CeylonClass.class"); assertNotNull(moduleClass); car.close(); } @Test public void testMdlModuleDefaultJavaFile() throws IOException { compile("modules/def/JavaClass.java"); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/def/JavaClass.class"); assertNotNull(moduleClass); car.close(); } @Test public void testMdlModuleDefaultIncremental() throws IOException { compile("modules/def/A.ceylon"); compile("modules/def/RequiresA.ceylon"); } @Test public void testMdlModuleIncremental() throws IOException { compile("modules/incremental/A.ceylon", "modules/incremental/BUsesA.ceylon", "modules/incremental/UsesB.ceylon"); compile("modules/incremental/A.ceylon", "modules/incremental/UsesB.ceylon"); } @Test public void testMdlModuleDefaultIncrementalNoPackage() throws IOException { List<String> options = new LinkedList<String>(); options.add("-src"); options.add(getPackagePath() + "/modules/def"); options.addAll(defaultOptions); CeyloncTaskImpl task = getCompilerTask(options, null, Collections.<String>emptyList(), "modules/def/A.ceylon"); Boolean ret = task.call(); assertTrue(ret); task = getCompilerTask(options, null, Collections.<String>emptyList(), "modules/def/RequiresA.ceylon"); ret = task.call(); assertTrue(ret); } @Test public void testMdlModuleOnlyInOutputRepo() throws IOException { File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertFalse(carFile.exists()); File carFileInCache = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6", cacheDir); if (carFileInCache.exists()) carFileInCache.delete(); compile("modules/single/module.ceylon"); // make sure it was created in the output repo assertTrue(carFile.exists()); // make sure it wasn't created in the cache repo assertFalse(carFileInCache.exists()); } @Test public void testMdlModuleNotLoadedFromHomeRepo() throws IOException { File carFile = getModuleArchive("a", "1.0"); assertFalse(carFile.exists()); // clean up the home repo if required String homeRepo = FileUtil.getUserDir().getCanonicalPath(); File carFileInHomeRepo = getModuleArchive("a", "1.0", homeRepo); if (carFileInHomeRepo.exists()) carFileInHomeRepo.delete(); // put a broken one in the home repo compileModuleFromSourceFolder("a", "home_repo/a_broken", homeRepo); assertTrue(carFileInHomeRepo.exists()); // the good one in the default output repo compileModuleFromSourceFolder("a", "home_repo/a_working", null); assertTrue(carFile.exists()); // now compile the dependent module compileModuleFromSourceFolder("b", "home_repo/b", null); // make sure it was created in the output repo assertTrue(carFile.exists()); } @Test public void testMdlModuleNotLoadedFromCache() throws IOException { File carFile = getModuleArchive("b", "1.0"); assertFalse(carFile.exists()); // clean up the cache repo if required File carFileInHomeRepo = getModuleArchive("a", "1.0", cacheDir); if (carFileInHomeRepo.exists()) carFileInHomeRepo.delete(); // clean up the working repo if required String workingRepo = destDir + "-working"; File carFileInWorkingRepo = getModuleArchive("a", "1.0", workingRepo); if (carFileInWorkingRepo.exists()) carFileInWorkingRepo.delete(); assertFalse(carFileInWorkingRepo.exists()); // put a broken one in the cache repo compileModuleFromSourceFolder("a", "home_repo/a_broken", cacheDir); assertTrue(carFileInHomeRepo.exists()); // the good one in a local repo compileModuleFromSourceFolder("a", "home_repo/a_working", workingRepo); assertTrue(carFileInWorkingRepo.exists()); // now compile the dependent module by using that repo compileModuleFromSourceFolder("b", "home_repo/b", null, workingRepo); // make sure it was created in the output repo assertTrue(carFile.exists()); } private void compileModuleFromSourceFolder(String module, String srcFolder, String outFolder, String... repos) { List<String> options = new LinkedList<String>(); options.add("-src"); options.add(getPackagePath() + "/modules/" + srcFolder); if (outFolder != null) { options.add("-out"); options.add(outFolder); } else { options.addAll(defaultOptions); } for (String repo : repos) { options.add("-rep"); options.add(repo); } CeyloncTaskImpl task = getCompilerTask(options, null, Arrays.asList(module)); Boolean ret = task.call(); assertTrue(ret); } @Test public void testMdlWithCeylonImport() throws IOException { compile("modules/ceylon_import/module.ceylon", "modules/ceylon_import/ImportCeylonLanguage.ceylon"); } @Test public void testMdlWithCommonPrefix() throws IOException { compile("modules/depend/prefix/module.ceylon"); // This is heisenbug https://github.com/ceylon/ceylon-compiler/issues/460 and for some // reason it only happens _sometimes_, hence the repeats compile("modules/depend/prefix_suffix/module.ceylon"); compile("modules/depend/prefix_suffix/module.ceylon"); compile("modules/depend/prefix_suffix/module.ceylon"); compile("modules/depend/prefix_suffix/module.ceylon"); compile("modules/depend/prefix_suffix/module.ceylon"); } @Test public void testMdlModuleFromCompiledModule() throws IOException { compile("modules/single/module.ceylon"); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); // just to be sure ZipEntry bogusEntry = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/BOGUS"); assertNull(bogusEntry); ZipEntry moduleClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/$module_.class"); assertNotNull(moduleClass); car.close(); compile("modules/single/subpackage/Subpackage.ceylon"); // MUST reopen it car = new JarFile(carFile); ZipEntry subpackageClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/subpackage/Subpackage.class"); assertNotNull(subpackageClass); car.close(); } @Ignore("See https://github.com/ceylon/ceylon/issues/6027") @Test public void testMdlCarWithInvalidSHA1() throws IOException { compile("modules/single/module.ceylon"); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); // just to be sure ZipEntry moduleClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/$module_.class"); assertNotNull(moduleClass); car.close(); // now let's break the SHA1 File shaFile = getArchiveName("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6", destDir, "car.sha1"); Writer w = new FileWriter(shaFile); w.write("fubar"); w.flush(); w.close(); // now try to compile the subpackage with a broken SHA1 String carName = "/com/redhat/ceylon/compiler/java/test/cmr/modules/single/6.6.6/com.redhat.ceylon.compiler.java.test.cmr.modules.single-6.6.6.car"; carName = carName.replace('/', File.separatorChar); assertErrors("modules/single/subpackage/Subpackage", new CompilerError(-1, "Module car " + carName + " obtained from repository " + (new File(destDir).getAbsolutePath()) + " has an invalid SHA1 signature: you need to remove it and rebuild the archive, since it may be corrupted.")); } @Test public void testMdlCompilerGeneratesModuleForValidUnits() throws IOException { CeyloncTaskImpl compilerTask = getCompilerTask("modules/single/module.ceylon", "modules/single/Correct.ceylon", "modules/single/Invalid.ceylon"); Boolean success = compilerTask.call(); assertFalse(success); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/$module_.class"); assertNotNull(moduleClass); ZipEntry correctClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/Correct.class"); assertNotNull(correctClass); ZipEntry invalidClass = car .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/Invalid.class"); assertNull(invalidClass); car.close(); } @Test public void testMdlInterdepModule() { // first compile it all from source compile("modules/interdep/a/module.ceylon", "modules/interdep/a/package.ceylon", "modules/interdep/a/b.ceylon", "modules/interdep/a/A.ceylon", "modules/interdep/b/module.ceylon", "modules/interdep/b/package.ceylon", "modules/interdep/b/a.ceylon", "modules/interdep/b/B.ceylon"); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.interdep.a", "6.6.6"); assertTrue(carFile.exists()); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.interdep.b", "6.6.6"); assertTrue(carFile.exists()); // then try to compile only one module (the other being loaded from its car) compile("modules/interdep/a/module.ceylon", "modules/interdep/a/b.ceylon", "modules/interdep/a/A.ceylon"); } @Test public void testMdlDependentModule() { // Compile only the first module compile("modules/depend/a/module.ceylon", "modules/depend/a/package.ceylon", "modules/depend/a/A.ceylon"); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.a", "6.6.6"); assertTrue(carFile.exists()); // then try to compile only one module (the other being loaded from its car) compile("modules/depend/b/module.ceylon", "modules/depend/b/package.ceylon", "modules/depend/b/a.ceylon", "modules/depend/b/aWildcard.ceylon", "modules/depend/b/B.ceylon"); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.b", "6.6.6"); assertTrue(carFile.exists()); // and then the last one (the other 2 being loaded from their cars) that uses the first one transitively compile("modules/depend/c/module.ceylon", "modules/depend/c/a.ceylon", "modules/depend/c/b.ceylon"); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.c", "6.6.6"); assertTrue(carFile.exists()); } @Test public void testMdlImplicitDependentModule() { // Compile only the first module compile("modules/implicit/a/module.ceylon", "modules/implicit/a/package.ceylon", "modules/implicit/a/A.ceylon", "modules/implicit/b/module.ceylon", "modules/implicit/b/package.ceylon", "modules/implicit/b/B.ceylon", "modules/implicit/b/B2.ceylon", "modules/implicit/c/module.ceylon", "modules/implicit/c/package.ceylon", "modules/implicit/c/c.ceylon"); // Dependencies: // // c.ceylon--> B2.ceylon // | // '-> B.ceylon --> A.ceylon // Successfull tests : compile("modules/implicit/c/c.ceylon"); compile("modules/implicit/b/B.ceylon", "modules/implicit/c/c.ceylon"); compile("modules/implicit/b/B2.ceylon", "modules/implicit/c/c.ceylon"); // Failing tests : Boolean success1 = getCompilerTask("modules/implicit/c/c.ceylon", "modules/implicit/b/B.ceylon").call(); // => B.ceylon : package not found in dependent modules: com.redhat.ceylon.compiler.java.test.cmr.module.implicit.a Boolean success2 = getCompilerTask("modules/implicit/c/c.ceylon", "modules/implicit/b/B2.ceylon").call(); // => c.ceylon : TypeVisitor caused an exception visiting Import node: com.sun.tools.javac.code.Symbol$CompletionFailure: class file for com.redhat.ceylon.compiler.test.cmr.module.implicit.a.A not found at unknown Assert.assertTrue(success1 && success2); } private void copy(File source, File dest) throws IOException { InputStream inputStream = new FileInputStream(source); OutputStream outputStream = new FileOutputStream(dest); byte[] buffer = new byte[4096]; int read; while ((read = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, read); } inputStream.close(); outputStream.close(); } @Test public void testMdlSuppressObsoleteClasses() throws IOException { File sourceFile = new File(getPackagePath(), "modules/single/SuppressClass.ceylon"); copy(new File(getPackagePath(), "modules/single/SuppressClass_1.ceylon"), sourceFile); CeyloncTaskImpl compilerTask = getCompilerTask("modules/single/module.ceylon", "modules/single/SuppressClass.ceylon"); Boolean success = compilerTask.call(); assertTrue(success); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertTrue(carFile.exists()); ZipFile car = new ZipFile(carFile); ZipEntry oneClass = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/One.class"); assertNotNull(oneClass); ZipEntry twoClass = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/Two.class"); assertNotNull(twoClass); car.close(); copy(new File(getPackagePath(), "modules/single/SuppressClass_2.ceylon"), sourceFile); compilerTask = getCompilerTask("modules/single/module.ceylon", "modules/single/SuppressClass.ceylon"); success = compilerTask.call(); assertTrue(success); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); assertTrue(carFile.exists()); car = new ZipFile(carFile); oneClass = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/One.class"); assertNotNull(oneClass); twoClass = car.getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/Two.class"); assertNull(twoClass); car.close(); sourceFile.delete(); } @Test public void testMdlMultipleRepos() { cleanCars("build/ceylon-cars-a"); cleanCars("build/ceylon-cars-b"); cleanCars("build/ceylon-cars-c"); // Compile the first module in its own repo File repoA = new File("build/ceylon-cars-a"); repoA.mkdirs(); Boolean result = getCompilerTask(Arrays.asList("-out", repoA.getPath()), "modules/depend/a/module.ceylon", "modules/depend/a/package.ceylon", "modules/depend/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.a", "6.6.6", repoA.getPath()); assertTrue(carFile.exists()); // make another repo for the second module File repoB = new File("build/ceylon-cars-b"); repoB.mkdirs(); // then try to compile only one module (the other being loaded from its car) result = getCompilerTask(Arrays.asList("-out", repoB.getPath(), "-rep", repoA.getPath()), "modules/depend/b/module.ceylon", "modules/depend/b/package.ceylon", "modules/depend/b/a.ceylon", "modules/depend/b/B.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.b", "6.6.6", repoB.getPath()); assertTrue(carFile.exists()); // make another repo for the third module File repoC = new File("build/ceylon-cars-c"); repoC.mkdirs(); // then try to compile only one module (the others being loaded from their car) result = getCompilerTask( Arrays.asList("-out", repoC.getPath(), "-rep", repoA.getPath(), "-rep", repoB.getPath()), "modules/depend/c/module.ceylon", "modules/depend/c/a.ceylon", "modules/depend/c/b.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.depend.c", "6.6.6", repoC.getPath()); assertTrue(carFile.exists()); } @Test public void testMdlJarDependency() throws IOException { // compile our java class File classesOutputFolder = new File(destDir + "-jar-classes"); cleanCars(classesOutputFolder.getPath()); classesOutputFolder.mkdirs(); File jarOutputFolder = new File(destDir + "-jar"); cleanCars(jarOutputFolder.getPath()); jarOutputFolder.mkdirs(); compileJavaModule(jarOutputFolder, classesOutputFolder, moduleName + ".modules.jarDependency.java", "1.0", moduleName.replace('.', '/') + "/modules/jarDependency/java/JavaDependency.java"); // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", jarOutputFolder.getPath()), (DiagnosticListener<? super FileObject>) null, "modules/jarDependency/ceylon/module.ceylon", "modules/jarDependency/ceylon/Foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); } private void compileJavaModule(File jarOutputFolder, File classesOutputFolder, String moduleName, String moduleVersion, String... sourceFileNames) throws IOException { compileJavaModule(jarOutputFolder, classesOutputFolder, moduleName, moduleVersion, new File(dir), new File[0], sourceFileNames); } private void compileJavaModule(File jarOutputFolder, File classesOutputFolder, String moduleName, String moduleVersion, File sourceFolder, File[] extraClassPath, String... sourceFileNames) throws IOException { JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); assertNotNull("Missing Java compiler, this test is probably being run with a JRE instead of a JDK!", javaCompiler); StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null); Set<String> sourceDirectories = new HashSet<String>(); File[] javaSourceFiles = new File[sourceFileNames.length]; for (int i = 0; i < javaSourceFiles.length; i++) { javaSourceFiles[i] = new File(sourceFolder, sourceFileNames[i]); String sfn = sourceFileNames[i].replace(File.separatorChar, '/'); int p = sfn.lastIndexOf('/'); String sourceDir = sfn.substring(0, p); sourceDirectories.add(sourceDir); } Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(javaSourceFiles); StringBuilder cp = new StringBuilder(); for (int i = 0; i < extraClassPath.length; i++) { if (i > 0) cp.append(File.pathSeparator); cp.append(extraClassPath[i]); } CompilationTask task = javaCompiler.getTask(null, null, null, Arrays.asList("-d", classesOutputFolder.getPath(), "-cp", cp.toString(), "-sourcepath", sourceFolder.getPath()), null, compilationUnits); assertEquals(Boolean.TRUE, task.call()); File jarFolder = new File(jarOutputFolder, moduleName.replace('.', File.separatorChar) + File.separatorChar + moduleVersion); jarFolder.mkdirs(); File jarFile = new File(jarFolder, moduleName + "-" + moduleVersion + ".jar"); // now jar it up JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(jarFile)); for (String sourceFileName : sourceFileNames) { String classFileName = sourceFileName.substring(0, sourceFileName.length() - 5) + ".class"; ZipEntry entry = new ZipEntry(classFileName); outputStream.putNextEntry(entry); File classFile = new File(classesOutputFolder, classFileName); FileInputStream inputStream = new FileInputStream(classFile); Util.copy(inputStream, outputStream); inputStream.close(); outputStream.flush(); } outputStream.close(); for (String sourceDir : sourceDirectories) { File module = null; String sourceName = "module.properties"; File properties = new File(sourceFolder, sourceDir + File.separator + sourceName); if (properties.exists()) { module = properties; } else { sourceName = "module.xml"; properties = new File(sourceFolder, sourceDir + File.separator + sourceName); if (properties.exists()) { module = properties; } } if (module != null) { File moduleFile = new File(sourceFolder, sourceDir + File.separator + sourceName); FileInputStream inputStream = new FileInputStream(moduleFile); FileOutputStream moduleOutputStream = new FileOutputStream(new File(jarFolder, sourceName)); Util.copy(inputStream, moduleOutputStream); inputStream.close(); moduleOutputStream.flush(); moduleOutputStream.close(); } } } @Test public void testMdlAetherDependencyDefault() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether", "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aetherdefault/module.ceylon", "modules/aetherdefault/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); // We're assuming a standard Maven configuration here! File camelJar = new File(System.getProperty("user.home"), ".m2/repository/org/apache/camel/camel-core/2.9.2/camel-core-2.9.2.jar"); assertTrue(camelJar.exists()); } @Test public void testMdlImplicitAetherDependencyDefault() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir, "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aetherdefault/module.ceylon", "modules/aetherdefault/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); // We're assuming a standard Maven configuration here! File camelJar = new File(System.getProperty("user.home"), ".m2/repository/org/apache/camel/camel-core/2.9.2/camel-core-2.9.2.jar"); assertTrue(camelJar.exists()); } @Test public void testMdlAetherIgnoreRecursiveDependencies() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether", "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aetherIgnoreDependencies/module.ceylon", "modules/aetherIgnoreDependencies/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); // We're assuming a standard Maven configuration here! File camelJar = new File(System.getProperty("user.home"), ".m2/repository/org/apache/camel/camel-core/2.9.4/camel-core-2.9.4.jar"); assertTrue(camelJar.exists()); File camelJettyJar = new File(System.getProperty("user.home"), ".m2/repository/org/apache/camel/camel-jetty/2.9.4/camel-jetty-2.9.4.jar"); assertTrue(camelJettyJar.exists()); } @Test public void testMdlAetherDependencyCustom() throws IOException { // Try to compile the ceylon module File settingsFile = new File(getPackagePath(), "modules/aethercustom/settings.xml"); CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether:" + settingsFile.getAbsolutePath(), "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aethercustom/module.ceylon", "modules/aethercustom/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); File restletJar = new File("build/test-cars/cmr-repository", "org/restlet/org.restlet/1.1.10/org.restlet-1.1.10.jar"); assertTrue(restletJar.exists()); } @Test public void testMdlAetherDependencyCustomRelative() throws IOException { // Try to compile the ceylon module File settingsFile = new File(getPackagePath(), "modules/aethercustom/settings.xml"); CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether:" + settingsFile, "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aethercustom/module.ceylon", "modules/aethercustom/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); File restletJar = new File("build/test-cars/cmr-repository", "org/restlet/org.restlet/1.1.10/org.restlet-1.1.10.jar"); assertTrue(restletJar.exists()); } @Test public void testMdlAetherMissingDependencies() throws IOException { CompilerError[] expectedErrors = new CompilerError[] { new CompilerError(6, "Error while loading the org.apache.camel:camel-jetty/2.9.4 module:\n" + " Declaration 'org.apache.camel.component.http.HttpComponent' could not be found in module 'org.apache.camel:camel-jetty' or its imported modules"), new CompilerError(10, "argument must be assignable to parameter 'arg1' of 'addComponent' in 'DefaultCamelContext': 'JettyHttpComponent' is not assignable to 'Component?': Error while loading the org.apache.camel:camel-jetty/2.9.4 module:\n" + " Declaration 'org.apache.camel.component.http.HttpComponent' could not be found in module 'org.apache.camel:camel-jetty' or its imported modules"), }; ErrorCollector collector = new ErrorCollector(); // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether"/*, "-verbose:cmr"*/), collector, "modules/bug1100/module.ceylon", "modules/bug1100/test.ceylon"); assertEquals("Compilation failed", Boolean.FALSE, ceylonTask.call()); TreeSet<CompilerError> actualErrors = collector.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, expectedErrors); } @Test public void testMdlAetherMissingDependenciesOverride() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether", "-overrides", getPackagePath() + "/modules/bug1100/overrides.xml"/*, "-verbose:cmr"*/), "modules/bug1100/module.ceylon", "modules/bug1100/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); } @Test public void testMdlDependenciesNoOverride() throws IOException { CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir/*, "-verbose:cmr"*/), "modules/overrides/module.ceylon", "modules/overrides/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); } @Test public void testMdlDependenciesOverrideRemoveDep() throws IOException { CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-overrides", getPackagePath() + "/modules/overrides/overridesRemoveJavaBase.xml"/*, "-verbose:cmr"*/), "modules/overrides/module.ceylon", "modules/overrides/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); } @Test public void testMdlAetherMissingDependencies2() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether"/*, "-verbose:cmr"*/), "modules/bug1104/module.ceylon", "modules/bug1104/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); } @Test public void testMdlCeylonAetherDuplicateImports() throws IOException { // Try to compile the ceylon module ErrorCollector collector = new ErrorCollector(); CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir, "-verbose:cmr"), collector, "modules/ceylonAetherDuplicateImports/module.ceylon", "modules/ceylonAetherDuplicateImports/foo.ceylon"); assertEquals(Boolean.FALSE, ceylonTask.call()); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(23, "duplicate module import: 'org.apache.httpcomponents.httpclient'"), new CompilerError(25, "duplicate module import: 'org.apache.httpcomponents:httpclient'")); } @Test public void testMdlCeylonAetherDependencyConflict() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir, "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/ceylonAetherConflict2/module.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); ErrorCollector collector = new ErrorCollector(); ceylonTask = getCompilerTask(Arrays.asList("-out", destDir, "-verbose:cmr"), collector, "modules/ceylonAetherConflict/module.ceylon", "modules/ceylonAetherConflict/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); compareErrors(collector.get(Diagnostic.Kind.WARNING), new CompilerError(Diagnostic.Kind.WARNING, null, 21, "source code imports two different versions of similar modules 'org.apache.httpcomponents.httpclient/4.3.2' and 'org.apache.httpcomponents:httpclient/4.3.3'"), new CompilerError(Diagnostic.Kind.WARNING, null, 21, "module (transitively) imports conflicting versions of similar dependencies 'org.apache.httpcomponents.httpclient/4.3.2' (via import path 'com.redhat.ceylon.compiler.java.test.cmr.modules.ceylonAetherConflict -> org.apache.httpcomponents.httpclient') and 'org.apache.httpcomponents:httpclient/4.3.3' (via import path 'com.redhat.ceylon.compiler.java.test.cmr.modules.ceylonAetherConflict -> com.redhat.ceylon.compiler.java.test.cmr.modules.ceylonAetherConflict2')") ); } @Ignore("It takes ages to download about 200 jars") @Test public void testMdlApacheSpark() throws Throwable { // initially run both without offline, then it's much faster CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir, "-offline"/*, "-verbose:cmr"*/), "modules/apachespark/module.ceylon", "modules/apachespark/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); runInJBossModules("run", "com.redhat.ceylon.compiler.java.test.cmr.modules.apachespark/1", Arrays.<String>asList("--flat-classpath", "--offline", "--maven-overrides", getPackagePath() + "/modules/apachespark/overrides.xml")); } @Test(expected = AssertionError.class) public void testMdlDependenciesFromMavenFail() throws Throwable { Assume.assumeTrue("Runs on JDK8", JDKUtils.jdk == JDKUtils.JDK.JDK8); CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir/*, "-verbose:cmr"*/), "modules/sparkframework/module.ceylon", "modules/sparkframework/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); runInJBossModules("run", "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework/1"); } @Test public void testMdlDependenciesFromMavenAutoExport() throws Throwable { Assume.assumeTrue("Runs on JDK8", JDKUtils.jdk == JDKUtils.JDK.JDK8); CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir/*, "-verbose:cmr"*/), "modules/sparkframework/module.ceylon", "modules/sparkframework/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); runInJBossModules("run", "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework/1", Arrays.asList("--auto-export-maven-dependencies")); } @Test public void testMdlDependenciesFromMavenFlatClasspath() throws Throwable { Assume.assumeTrue("Runs on JDK8", JDKUtils.jdk == JDKUtils.JDK.JDK8); CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir/*, "-verbose:cmr"*/), "modules/sparkframework/module.ceylon", "modules/sparkframework/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); // flat classpath via API runInJBossModules("run", "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework/1", Arrays.asList( "--flat-classpath", "--overrides", getPackagePath() + "/modules/sparkframework/overrides-log.xml")); // and via main without aether runInMainApi(destDir, new ModuleSpec("com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework", "1"), "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework.run_", Arrays.<String>asList(), false); // and via main with aether runInMainApi(destDir, new ModuleSpec("com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework", "1"), Arrays.asList( new ModuleSpec("com.redhat.ceylon.module-resolver-aether", Versions.CEYLON_VERSION_NUMBER)), "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework.run_", Arrays.<String>asList(), false); } @Test public void testMdlDependenciesFromMavenWithOverrides() throws Throwable { Assume.assumeTrue("Runs on JDK8", JDKUtils.jdk == JDKUtils.JDK.JDK8); CeyloncTaskImpl ceylonTask = getCompilerTask(Arrays.asList("-out", destDir/*, "-verbose:cmr"*/), "modules/sparkframework/module.ceylon", "modules/sparkframework/test.ceylon"); assertEquals("Compilation failed", Boolean.TRUE, ceylonTask.call()); runInJBossModules("run", "com.redhat.ceylon.compiler.java.test.cmr.modules.sparkframework/1", Arrays.asList("--overrides", getPackagePath() + "/modules/sparkframework/overrides-fix.xml")); } @Test public void testMdlSourceArchive() throws IOException { File sourceArchiveFile = getSourceArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); sourceArchiveFile.delete(); assertFalse(sourceArchiveFile.exists()); // compile one file compile("modules/single/module.ceylon"); // make sure it was created assertTrue(sourceArchiveFile.exists()); JarFile sourceArchive = new JarFile(sourceArchiveFile); assertEquals(2, countEntries(sourceArchive)); ZipEntry moduleClass = sourceArchive .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/module.ceylon"); assertNotNull(moduleClass); ZipEntry moduleClassDir = sourceArchive .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/"); assertNotNull(moduleClassDir); sourceArchive.close(); // now compile another file compile("modules/single/subpackage/Subpackage.ceylon"); // MUST reopen it sourceArchive = new JarFile(sourceArchiveFile); assertEquals(4, countEntries(sourceArchive)); ZipEntry subpackageClass = sourceArchive .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/subpackage/Subpackage.ceylon"); assertNotNull(subpackageClass); ZipEntry subpackageClassDir = sourceArchive .getEntry("com/redhat/ceylon/compiler/java/test/cmr/modules/single/subpackage/"); assertNotNull(subpackageClassDir); sourceArchive.close(); } @Test public void testMdlMultipleVersionsOnSameCompilation() { // Compile module A/1 Boolean result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a1"), "modules/multiversion/a1/a/module.ceylon", "modules/multiversion/a1/a/package.ceylon", "modules/multiversion/a1/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); ErrorCollector collector = new ErrorCollector(); // Compile module A/2 with B importing A/1 result = getCompilerTask( Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a2" + File.pathSeparator + getPackagePath() + "/modules/multiversion/b"), collector, "modules/multiversion/a2/a/module.ceylon", "modules/multiversion/a2/a/package.ceylon", "modules/multiversion/a2/a/A.ceylon", "modules/multiversion/b/b/module.ceylon", "modules/multiversion/b/b/B.ceylon").call(); Assert.assertEquals(Boolean.FALSE, result); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(20, "source code imports two different versions of module 'a': version '1' and version '2'")); } @Test public void testMdlMultipleVersionsDuringImport() { // Compile module A/1 Boolean result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a1"), "modules/multiversion/a1/a/module.ceylon", "modules/multiversion/a1/a/package.ceylon", "modules/multiversion/a1/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module A/2 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a2"), "modules/multiversion/a2/a/module.ceylon", "modules/multiversion/a2/a/package.ceylon", "modules/multiversion/a2/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); ErrorCollector collector = new ErrorCollector(); // Compile module cImportsATwice which imports both A/1 and A/2 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/c"), collector, "modules/multiversion/c/cImportsATwice/module.ceylon", "modules/multiversion/c/cImportsATwice/C.ceylon").call(); Assert.assertEquals(Boolean.FALSE, result); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(20, "module (transitively) imports conflicting versions of dependency 'a': version '1' (via import path 'cImportsATwice -> a') and version '2' (via import path 'cImportsATwice -> a')"), new CompilerError(20, "source code imports two different versions of module 'a': version '1' and version '2'"), new CompilerError(22, "duplicate module import: 'a'")); } @Test public void testMdlMultipleVersionsDuringDependencyImport() { // Compile module A/1 Boolean result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a1"), "modules/multiversion/a1/a/module.ceylon", "modules/multiversion/a1/a/package.ceylon", "modules/multiversion/a1/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module A/2 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a2"), "modules/multiversion/a2/a/module.ceylon", "modules/multiversion/a2/a/package.ceylon", "modules/multiversion/a2/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module B/1 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/b"), "modules/multiversion/b/b/module.ceylon", "modules/multiversion/b/b/package.ceylon", "modules/multiversion/b/b/B.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module cImportsABIndirectlyOK which imports both A/1 and A/2 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/c"), "modules/multiversion/c/cImportsABIndirectlyOK/module.ceylon", "modules/multiversion/c/cImportsABIndirectlyOK/C.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); } @Test public void testMdlMultipleVersionsDuringImplicitImport() { // Compile module A/1 Boolean result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a1"), "modules/multiversion/a1/a/module.ceylon", "modules/multiversion/a1/a/package.ceylon", "modules/multiversion/a1/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module A/2 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/a2"), "modules/multiversion/a2/a/module.ceylon", "modules/multiversion/a2/a/package.ceylon", "modules/multiversion/a2/a/A.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module bExportsA1/1 result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/b"), "modules/multiversion/b/bExportsA1/module.ceylon", "modules/multiversion/b/bExportsA1/package.ceylon", "modules/multiversion/b/bExportsA1/B.ceylon") .call(); Assert.assertEquals(Boolean.TRUE, result); // Compile module cImportsABIndirectlyFail which imports both A/1 and A/2 ErrorCollector collector = new ErrorCollector(); result = getCompilerTask(Arrays.asList("-src", getPackagePath() + "/modules/multiversion/c"), collector, "modules/multiversion/c/cImportsABIndirectlyFail/module.ceylon", "modules/multiversion/c/cImportsABIndirectlyFail/C.ceylon").call(); Assert.assertEquals(Boolean.FALSE, result); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(20, "module (transitively) imports conflicting versions of dependency 'a': version '1' (via import path 'cImportsABIndirectlyFail -> bExportsA1') and version '2' (via import path 'cImportsABIndirectlyFail -> a')"), new CompilerError(20, "source code imports two different versions of module 'a': version '1' and version '2'")); } private int countEntries(JarFile jar) { int count = 0; Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { count++; entries.nextElement(); } return count; } @Test public void testMdlSha1Signatures() throws IOException { File sourceArchiveFile = getSourceArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); File sourceArchiveSignatureFile = new File(sourceArchiveFile.getPath() + ".sha1"); File moduleArchiveFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.single", "6.6.6"); File moduleArchiveSignatureFile = new File(moduleArchiveFile.getPath() + ".sha1"); // cleanup sourceArchiveFile.delete(); sourceArchiveSignatureFile.delete(); moduleArchiveFile.delete(); moduleArchiveSignatureFile.delete(); // safety check assertFalse(sourceArchiveFile.exists()); assertFalse(sourceArchiveSignatureFile.exists()); assertFalse(moduleArchiveFile.exists()); assertFalse(moduleArchiveSignatureFile.exists()); // compile one file compile("modules/single/module.ceylon"); // make sure everything was created assertTrue(sourceArchiveFile.exists()); assertTrue(sourceArchiveSignatureFile.exists()); assertTrue(moduleArchiveFile.exists()); assertTrue(moduleArchiveSignatureFile.exists()); // check the signatures vaguely checkSha1(sourceArchiveSignatureFile); checkSha1(moduleArchiveSignatureFile); } private void checkSha1(File signatureFile) throws IOException { Assert.assertEquals(40, signatureFile.length()); FileInputStream reader = new FileInputStream(signatureFile); byte[] bytes = new byte[40]; Assert.assertEquals(40, reader.read(bytes)); reader.close(); char[] sha1 = new String(bytes, "ASCII").toCharArray(); for (int i = 0; i < sha1.length; i++) { char c = sha1[i]; Assert.assertTrue((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } } @Test public void testMdlJdkBaseModule() throws IOException { compile("modules/jdk/appletBroken/Foo.ceylon"); } @Test public void testMdlUsesJavaWithoutImportingIt() throws IOException { assertErrors("modules/jdk/usesJavaWithoutImportingIt/Foo", new CompilerError(20, "package not found in imported modules: 'java.lang' (add module import to module descriptor of 'com.redhat.ceylon.compiler.java.test.cmr.modules.jdk.usesJavaWithoutImportingIt')"), new CompilerError(23, "function or value does not exist: 'nanoTime'")); } @Test public void testMdlDefaultUsesJavaWithoutImportingIt() throws IOException { List<String> options = new LinkedList<String>(); options.add("-src"); options.add(getPackagePath() + "/modules/jdk/defaultUsesJavaWithoutImportingIt"); options.addAll(defaultOptions); assertErrors("modules/jdk/defaultUsesJavaWithoutImportingIt/Foo", new CompilerError(20, "package not found in imported modules: 'java.lang' (define a module and add module import to its module descriptor)"), new CompilerError(23, "function or value does not exist: 'nanoTime'")); } @Test public void testMdlLegacyImport() { // Compile a module that imports a legacy module that has a shared import of another legacy module compile("modules/legacyimport/module.ceylon", "modules/legacyimport/package.ceylon", "modules/legacyimport/A.ceylon"); File carFile = getModuleArchive("com.redhat.ceylon.compiler.java.test.cmr.modules.legacyimport", "6.6.6"); assertTrue(carFile.exists()); } @Test public void testMdlBug1062IncompatibleMissingImport() throws IOException { // compile our java class File classesOutputFolder = new File(destDir + "-jar-classes"); cleanCars(classesOutputFolder.getPath()); classesOutputFolder.mkdirs(); File jarOutputFolder = new File(destDir + "-jar"); cleanCars(jarOutputFolder.getPath()); jarOutputFolder.mkdirs(); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "1", new File(getPackagePath(), "modules/bug1062/javaA1-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "2", new File(getPackagePath(), "modules/bug1062/javaA2-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaB", "1", new File(getPackagePath(), "modules/bug1062/javaB-nomodule-src"), new File[] { new File(jarOutputFolder, "bug1062/javaA/1/bug1062.javaA-1.jar") }, "bug1062/javaB/JavaB.java"); assertErrors("modules/bug1062/ceylon/test", Arrays.asList("-rep", jarOutputFolder.getPath()), null, new CompilerError(5, "could not determine type of method or attribute reference: 'method' of 'JavaB': Error while loading the bug1062.javaB/1 module:\n" + " Declaration 'bug1062.javaA.JavaA' could not be found in module 'bug1062.javaB' or its imported modules but was found in the non-imported module 'bug1062.javaA'"), new CompilerError(5, "parameter type could not be determined: 'arg0' of 'method' in 'JavaB': Error while loading the bug1062.javaB/1 module:\n" + " Declaration 'bug1062.javaA.JavaA' could not be found in module 'bug1062.javaB' or its imported modules but was found in the non-imported module 'bug1062.javaA'")); } @Test public void testMdlBug1062IncompatibleNonSharedImport() throws IOException { // compile our java class File classesOutputFolder = new File(destDir + "-jar-classes"); cleanCars(classesOutputFolder.getPath()); classesOutputFolder.mkdirs(); File jarOutputFolder = new File(destDir + "-jar"); cleanCars(jarOutputFolder.getPath()); jarOutputFolder.mkdirs(); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "1", new File(getPackagePath() + "/modules/bug1062/javaA1-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "2", new File(getPackagePath() + "/modules/bug1062/javaA2-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaB", "1", new File(getPackagePath() + "/modules/bug1062/javaB-module-src"), new File[] { new File(jarOutputFolder, "bug1062/javaA/1/bug1062.javaA-1.jar") }, "bug1062/javaB/JavaB.java"); // ceylon module imports JavaA/2 and JavaB/1 // JavaB/1 imports JavaA/1 assertErrors("modules/bug1062/ceylon/test", Arrays.asList("-rep", jarOutputFolder.getPath(), "-cp", getClassPathAsPath()), null, new CompilerError(5, "could not determine type of method or attribute reference: 'method' of 'JavaB': Error while loading the bug1062.javaB/1 module:\n" + " Declaration 'bug1062.javaA.JavaA' could not be found in module 'bug1062.javaB' or its imported modules but was found in the non-imported module 'bug1062.javaA'"), new CompilerError(5, "parameter type could not be determined: 'arg0' of 'method' in 'JavaB': Error while loading the bug1062.javaB/1 module:\n" + " Declaration 'bug1062.javaA.JavaA' could not be found in module 'bug1062.javaB' or its imported modules but was found in the non-imported module 'bug1062.javaA'")); } @Test public void testMdlBug1062IncompatibleSharedImport() throws IOException { // compile our java class File classesOutputFolder = new File(destDir + "-jar-classes"); cleanCars(classesOutputFolder.getPath()); classesOutputFolder.mkdirs(); File jarOutputFolder = new File(destDir + "-jar"); cleanCars(jarOutputFolder.getPath()); jarOutputFolder.mkdirs(); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "1", new File(getPackagePath() + "/modules/bug1062/javaA1-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaA", "2", new File(getPackagePath() + "/modules/bug1062/javaA2-src"), new File[0], "bug1062/javaA/JavaA.java"); compileJavaModule(jarOutputFolder, classesOutputFolder, "bug1062.javaB", "1", new File(getPackagePath() + "/modules/bug1062/javaB-module-export-src"), new File[] { new File(jarOutputFolder, "bug1062/javaA/1/bug1062.javaA-1.jar") }, "bug1062/javaB/JavaB.java"); // ceylon module imports JavaA/2 and JavaB/1 // JavaB/1 shared imports JavaA/1 assertErrors("modules/bug1062/ceylon/test", Arrays.asList("-rep", jarOutputFolder.getPath()), null, new CompilerError(2, "module (transitively) imports conflicting versions of dependency 'bug1062.javaA': version '1' (via import path 'com.redhat.ceylon.compiler.java.test.cmr.modules.bug1062.ceylon -> bug1062.javaB') and version '2' (via import path 'com.redhat.ceylon.compiler.java.test.cmr.modules.bug1062.ceylon -> bug1062.javaA')"), new CompilerError(2, "source code imports two different versions of module 'bug1062.javaA': version '1' and version '2'")); } @Test public void testMdlDefaultImportsInexistantPackage() throws IOException { // we do it twice to make sure existing class files do not confuse it for (int i = 0; i < 2; i++) { assertErrors( new String[] { "modules/defaultImportsInexistantPackage/file.ceylon", "modules/defaultImportsInexistantPackage/isModule/module.ceylon", "modules/defaultImportsInexistantPackage/isModule/package.ceylon", "modules/defaultImportsInexistantPackage/isModule/foo.ceylon", }, defaultOptions, null, new CompilerError(1, "package not found in imported modules: 'doesnotExist' (define a module and add module import to its module descriptor)"), new CompilerError(2, "package not found in imported modules: 'com.redhat.ceylon.compiler.java.test.cmr.modules.defaultImportsInexistantPackage.isModule' (define a module and add module import to its module descriptor)")); } } @Test public void testMdlProducesOsgiManifest() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleName, moduleVersion); Attributes attr = manifest.getMainAttributes(); assertEquals("2", attr.get(OsgiUtil.OsgiManifest.Bundle_ManifestVersion)); assertEquals(moduleName, attr.get(OsgiUtil.OsgiManifest.Bundle_SymbolicName)); String bundleVersion = (String) attr.get(OsgiUtil.OsgiManifest.Bundle_Version); int qualifierIndex = bundleVersion.lastIndexOf('.'); String bundleVersionWithoutQualifier = qualifierIndex > 0 ? bundleVersion.substring(0, qualifierIndex) : bundleVersion; assertEquals(moduleVersion, bundleVersionWithoutQualifier); } @Test public void testMdlDefaultHasNoOsgiManifest() throws IOException { compile("modules/def/CeylonClass.ceylon"); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); try (JarFile car = new JarFile(carFile)) { ZipEntry manifest = car.getEntry(OsgiUtil.OsgiManifest.MANIFEST_FILE_NAME); try (InputStream input = car.getInputStream(manifest)) { Manifest m = new Manifest(input); Assert.assertTrue(OsgiUtil.DefaultModuleManifest.isDefaultModule(m)); } } } @Test public void testMdlOsgiManifestDisabled() throws IOException { ErrorCollector c = new ErrorCollector(); List<String> options = new ArrayList<String>(defaultOptions.size() + 1); options.addAll(defaultOptions); options.add("-noosgi"); assertCompilesOk(c, getCompilerTask(options, c, "modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon").call2()); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a"; final String moduleVersion = "1.1.0"; File carFile = getModuleArchive(moduleName, moduleVersion); JarFile car = new JarFile(carFile); ZipEntry manifest = car.getEntry(OsgiUtil.OsgiManifest.MANIFEST_FILE_NAME); assertNull(manifest); car.close(); } @Test public void testMdlOsgiManifestRequiresCeylonLanguageBundle() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); final Manifest manifest = getManifest("com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a", "1.1.0"); assertEquals( "ceylon.language;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport" + ",com.redhat.ceylon.dist;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport", manifest.getMainAttributes().get(OsgiUtil.OsgiManifest.Require_Bundle)); } @Test public void testMdlOsgiManifestExportsSharedPackages() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon", "modules/osgi/a/b/package.ceylon", "modules/osgi/a/b/B.ceylon", "modules/osgi/a/c/package.ceylon", "modules/osgi/a/c/C.ceylon"); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleName, moduleVersion); assertNotNull(manifest); Attributes attr = manifest.getMainAttributes(); String attribute = (String) attr.get(OsgiUtil.OsgiManifest.Export_Package); String[] exportPackage = attribute.split(","); assertEquals(2, exportPackage.length); assertThat(Arrays.asList(exportPackage), CoreMatchers.hasItems( "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a;version=" + moduleVersion, "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a.c;version=" + moduleVersion)); assertThat(Arrays.asList(exportPackage), CoreMatchers.not(CoreMatchers .hasItem("com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a.b;version=" + moduleVersion))); } @Test public void testMdlOsgiManifestRequresImportedModules() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); compile("modules/osgi/b/module.ceylon", "modules/osgi/b/package.ceylon", "modules/osgi/b/B.ceylon"); final String moduleBName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.b"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleBName, moduleVersion); final String[] requireBundle = ((String) manifest.getMainAttributes() .get(OsgiUtil.OsgiManifest.Require_Bundle)).split(","); assertEquals(3, requireBundle.length); assertThat(Arrays.asList(requireBundle), CoreMatchers.hasItems( "ceylon.language;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport", "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a;bundle-version=1.1.0", "com.redhat.ceylon.dist;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport")); } @Test public void testMdlOsgiManifestFiltersProvidedBundles() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); ArrayList<String> options = new ArrayList<>(defaultOptions); options.addAll(Arrays.asList("-osgi-provided-bundles", "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a , ceylon.language")); compilesWithoutWarnings(options, "modules/osgi/b/module.ceylon", "modules/osgi/b/package.ceylon", "modules/osgi/b/B.ceylon"); final String moduleBName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.b"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleBName, moduleVersion); final String[] requireBundle = ((String) manifest.getMainAttributes() .get(OsgiUtil.OsgiManifest.Require_Bundle)).split(","); assertEquals(1, requireBundle.length); assertThat(Arrays.asList(requireBundle), CoreMatchers.hasItems("com.redhat.ceylon.dist;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport")); } @Test public void testMdlOsgiManifestFiltersProvidedBundle() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); ArrayList<String> options = new ArrayList<>(defaultOptions); options.addAll( Arrays.asList("-osgi-provided-bundles", "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a")); compilesWithoutWarnings(options, "modules/osgi/b/module.ceylon", "modules/osgi/b/package.ceylon", "modules/osgi/b/B.ceylon"); final String moduleBName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.b"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleBName, moduleVersion); final String[] requireBundle = ((String) manifest.getMainAttributes() .get(OsgiUtil.OsgiManifest.Require_Bundle)).split(","); assertEquals(2, requireBundle.length); assertThat(Arrays.asList(requireBundle), CoreMatchers.hasItems( "ceylon.language;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport", "com.redhat.ceylon.dist;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport")); } @Test public void testMdlOsgiManifestReexportsSharedImportedModules() throws IOException { compile("modules/osgi/a/module.ceylon", "modules/osgi/a/package.ceylon", "modules/osgi/a/A.ceylon"); compile("modules/osgi/c/module.ceylon", "modules/osgi/c/package.ceylon", "modules/osgi/c/C.ceylon"); final String moduleCName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.c"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleCName, moduleVersion); final String[] requireBundle = ((String) manifest.getMainAttributes() .get(OsgiUtil.OsgiManifest.Require_Bundle)).split(","); assertEquals(3, requireBundle.length); assertThat(Arrays.asList(requireBundle), CoreMatchers.hasItems( "ceylon.language;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport", "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.a;bundle-version=1.1.0;visibility:=reexport", "com.redhat.ceylon.dist;bundle-version=" + Versions.CEYLON_VERSION_NUMBER + ";visibility:=reexport")); } @Test public void testMdlOsgiManifestWithJavaImportRequiresJavaSECapability() throws IOException { compile("modules/osgi/java/module.ceylon", "modules/osgi/java/package.ceylon", "modules/osgi/java/foo.ceylon"); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.osgi.java"; final String moduleVersion = "1.1.0"; final Manifest manifest = getManifest(moduleName, moduleVersion); assertEquals("osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version>=1.7))\"", manifest.getMainAttributes().get(OsgiUtil.OsgiManifest.Require_Capability)); } private Manifest getManifest(String moduleName, String moduleVersion) throws IOException { File carFile = getModuleArchive(moduleName, moduleVersion); Manifest manifest = null; try (JarFile car = new JarFile(carFile)) { manifest = car.getManifest(); } assertNotNull(manifest); return manifest; } @Test public void testMdlPomManifest() throws IOException { compile("modules/pom/a/module.ceylon", "modules/pom/b/module.ceylon"); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.pom.b"; final String moduleVersion = "1"; File carFile = getModuleArchive(moduleName, moduleVersion); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry pomFile = car .getEntry("META-INF/maven/com.redhat.ceylon.compiler.java.test.cmr.modules.pom/b/pom.xml"); assertNotNull(pomFile); String pomContents = read(car, pomFile); assertEquals("<?xml version=\"1.0\" ?>\n" + "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n" + " <modelVersion>4.0.0</modelVersion>\n" + " <groupId>com.redhat.ceylon.compiler.java.test.cmr.modules.pom</groupId>\n" + " <artifactId>b</artifactId>\n" + " <version>1</version>\n" + " <name>com.redhat.ceylon.compiler.java.test.cmr.modules.pom.b</name>\n" + " <dependencies>\n" + " <dependency>\n" + " <groupId>com.redhat.ceylon.compiler.java.test.cmr.modules.pom</groupId>\n" + " <artifactId>a</artifactId>\n" + " <version>1</version>\n" + " </dependency>\n" + " </dependencies>\n" + "</project>\n", pomContents); ZipEntry propertiesFile = car .getEntry("META-INF/maven/com.redhat.ceylon.compiler.java.test.cmr.modules.pom/b/pom.properties"); assertNotNull(propertiesFile); String propertiesContents = read(car, propertiesFile); // remove the date comment propertiesContents = propertiesContents.replaceFirst("^(#Generated by Ceylon\n)#[^\n]+\n", "$1"); assertEquals( "#Generated by Ceylon\n" + "version=1\n" + "groupId=com.redhat.ceylon.compiler.java.test.cmr.modules.pom\n" + "artifactId=b\n", propertiesContents); car.close(); } @Test public void testMdlNoPomManifest() throws IOException { ErrorCollector c = new ErrorCollector(); assertCompilesOk(c, getCompilerTask(Arrays.asList("-nopom", "-out", destDir), c, "modules/pom/a/module.ceylon", "modules/pom/b/module.ceylon").call2()); final String moduleName = "com.redhat.ceylon.compiler.java.test.cmr.modules.pom.b"; final String moduleVersion = "1"; File carFile = getModuleArchive(moduleName, moduleVersion); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry pomFile = car .getEntry("META-INF/maven/com.redhat.ceylon.compiler.java.test.cmr.modules.pom/b/pom.xml"); assertNull(pomFile); ZipEntry propertiesFile = car .getEntry("META-INF/maven/com.redhat.ceylon.compiler.java.test.cmr.modules.pom/b/pom.properties"); assertNull(propertiesFile); car.close(); } private String read(JarFile car, ZipEntry entry) throws IOException { try (InputStream is = car.getInputStream(entry); Reader r = new InputStreamReader(is); BufferedReader br = new BufferedReader(r)) { StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null) sb.append(line).append("\n"); return sb.toString(); } } private void setupBinaryModulesForOverridesCeylonModuleTests() { Boolean result = null; for (String version : Arrays.asList("v1", "v2")) { // Compile modules and generate archives result = getCompilerTask( Arrays.asList("-src", getPackagePath() + "modules/overridesCeylonModule/" + version), "modules/overridesCeylonModule/" + version + "/a/module.ceylon", "modules/overridesCeylonModule/" + version + "/b/module.ceylon", "modules/overridesCeylonModule/" + version + "/b/hidden/package.ceylon", "modules/overridesCeylonModule/" + version + "/b/shared/package.ceylon", "modules/overridesCeylonModule/" + version + "/c/module.ceylon", "modules/overridesCeylonModule/" + version + "/c/hidden/package.ceylon", "modules/overridesCeylonModule/" + version + "/c/shared/package.ceylon").call(); Assert.assertEquals(Boolean.TRUE, result); } } private static class ModulesRetriever implements TaskListener { private com.redhat.ceylon.langtools.tools.javac.util.Context context = null; HashMap<String, Module> modules = null; public ModulesRetriever(com.redhat.ceylon.langtools.tools.javac.util.Context context) { this.context = context; } @Override public void started(TaskEvent e) { } @Override public void finished(TaskEvent e) { if (e.getKind() == TaskEvent.Kind.ENTER) { if (modules == null) { modules = new HashMap<>(); Context ceylonContext = LanguageCompiler.getCeylonContextInstance(context); assert (ceylonContext != null); Modules modules = ceylonContext.getModules(); assert (modules != null); for (Module m : modules.getListOfModules()) { String name = m.getNameAsString(); if (name.equals("a") || name.equals("b") || name.equals("c")) { this.modules.put(name, m); } } } } } } @Test public void testOverridesCeylonModuleInSourceImport() { setupBinaryModulesForOverridesCeylonModuleTests(); ErrorCollector collector = new ErrorCollector(); CeyloncTaskImpl compilerTask = getCompilerTask( Arrays.asList("-continue", "-src", getPackagePath() + "/modules", "-overrides", getPackagePath() + "modules/overridesCeylonModule/overrides-a-version.xml"), collector, "modules/overridesCeylonModule/module.ceylon"); ModulesRetriever modulesRetriever = new ModulesRetriever(compilerTask.getContext()); compilerTask.setTaskListener(modulesRetriever); Boolean result = compilerTask.call(); Assert.assertEquals(Boolean.FALSE, result); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(2, "the module import should not be overridden, since it is explicitly imported by a project source module")); assert (modulesRetriever.modules != null); Module a = modulesRetriever.modules.get("a"); Module b = modulesRetriever.modules.get("b"); Module c = modulesRetriever.modules.get("c"); assert (a != null); assert (b != null); assert (c != null); assertEquals("The version override should not be applied to modules imported in source code", "2", a.getVersion()); assertEquals("The version override should not be applied to modules imported in source code", "2", b.getVersion()); assertEquals("The version override should not be applied to modules imported in source code", "2", c.getVersion()); } @Test public void testOverridesCeylonModuleVersionProducesJavaModule() { setupBinaryModulesForOverridesCeylonModuleTests(); ErrorCollector collector = new ErrorCollector(); CeyloncTaskImpl compilerTask = getCompilerTask( Arrays.asList("-src", getPackagePath() + "/modules", "-overrides", getPackagePath() + "modules/overridesCeylonModule/overrides-b-version.xml"), collector, "modules/overridesCeylonModule/module.ceylon"); ModulesRetriever modulesRetriever = new ModulesRetriever(compilerTask.getContext()); compilerTask.setTaskListener(modulesRetriever); Boolean result = compilerTask.call(); Assert.assertEquals(Boolean.TRUE, result); assert (modulesRetriever.modules != null); Module b = modulesRetriever.modules.get("b"); assert (b != null); assertEquals("The Ceylon module 'b' is now seen as a Java module when a version override is applied", false, b.isJava()); } @Test public void testOverridesCeylonModuleVersionAlterdPackageSharing() { setupBinaryModulesForOverridesCeylonModuleTests(); ErrorCollector collector = new ErrorCollector(); CeyloncTaskImpl compilerTask = getCompilerTask( Arrays.asList("-src", getPackagePath() + "/modules", "-overrides", getPackagePath() + "modules/overridesCeylonModule/overrides-b-version.xml"), collector, "modules/overridesCeylonModule/module.ceylon", "modules/overridesCeylonModule/testImportHiddenPackage.ceylon"); ModulesRetriever modulesRetriever = new ModulesRetriever(compilerTask.getContext()); compilerTask.setTaskListener(modulesRetriever); Boolean result = compilerTask.call(); Assert.assertEquals(Boolean.FALSE, result); compareErrors(collector.get(Diagnostic.Kind.ERROR), new CompilerError(2, "imported package is not shared: 'b.hidden'")); } private ModuleImport getModuleImport(Module m, String name) { for (ModuleImport i : m.getImports()) { if (i.getModule().getNameAsString().equals(name)) { return i; } } return null; } @Test public void testOverridesCeylonModuleShareImport() { setupBinaryModulesForOverridesCeylonModuleTests(); ErrorCollector collector = new ErrorCollector(); CeyloncTaskImpl compilerTask = getCompilerTask( Arrays.asList("-src", getPackagePath() + "/modules", "-overrides", getPackagePath() + "modules/overridesCeylonModule/overrides-share-c-import.xml"), collector, "modules/overridesCeylonModule/module.ceylon"); ModulesRetriever modulesRetriever = new ModulesRetriever(compilerTask.getContext()); compilerTask.setTaskListener(modulesRetriever); Boolean result = compilerTask.call(); Assert.assertEquals(Boolean.TRUE, result); Module a = modulesRetriever.modules.get("a"); assert (a != null); ModuleImport cImport = getModuleImport(a, "c"); assert (cImport != null); assertEquals("The 'c' module import should be seen as 'exported' after applying the overrides file", true, cImport.isExport()); } @Test public void testCacheFolderCreation() throws IOException { // move our user cache folder File userCacheRepo = Repositories.get().getCacheRepoDir(); File tmpCacheRepo = null; boolean moved = false; if (userCacheRepo.exists()) { // let's move it System.out.println("Moving user cache repo away"); tmpCacheRepo = File.createTempFile("cache-", "-moved-out-for-CMRTests", userCacheRepo.getParentFile()); tmpCacheRepo.delete(); assert (userCacheRepo.renameTo(tmpCacheRepo)); moved = true; } try { String cachePath = getCachePath(); cleanCars(cacheDir); File cacheFolder = new File(cachePath); // cleared assert (!cacheFolder.exists()); // clear or moved assert (!userCacheRepo.exists()); compile("modules/legacyimport/A.ceylon"); // created assert (cacheFolder.exists()); // still not there assert (!userCacheRepo.exists()); } finally { if (moved) { System.out.println("Moving user cache repo back"); Assert.assertTrue("Moving back your cache repo has failed: it is now at " + tmpCacheRepo + " so if you want to keep it at " + userCacheRepo + " you need to move it manually. Sorry.", tmpCacheRepo.renameTo(userCacheRepo)); } } } @Test public void testMdlNullVersion() throws IOException { assertErrors("modules/nullVersion/module", new CompilerError(21, "missing module version"), new CompilerError(21, "cannot find module artifact null-null(.car|.jar)\n \t- dependency tree: com.redhat.ceylon.compiler.java.test.cmr.modules.nullVersion/1 -> null/null")); } @Test public void testMavenFileResolver() throws ZipException, IOException { CeylonRepoManagerBuilder builder = CeylonUtils.repoManager(); RepositoryManager repository = builder.buildManager(); String groupId = "javax.el"; String artifactId = "javax.el-api"; String version = "3.0.0"; String coord = groupId + ":" + artifactId; File artifact = repository.getArtifact(MavenArtifactContext.NAMESPACE, coord, version); Assert.assertNotNull(artifact); try (ZipFile zf = new ZipFile(artifact)) { String descriptorPath = String.format("META-INF/maven/%s/%s/pom.xml", groupId, artifactId); ZipEntry entry = zf.getEntry(descriptorPath); Assert.assertNotNull(entry); try (InputStream is = zf.getInputStream(entry)) { DependencyResolver resolver = new MavenDependencyResolver(); ModuleInfo info = resolver.resolveFromInputStream(is, coord, version, null); Assert.assertNotNull(info); // FIXME: find one with dependencies System.err.println(info.getDependencies()); } } } @Test public void testNamespaceImports() throws IOException { // Try to compile the ceylon module CeyloncTaskImpl ceylonTask = getCompilerTask( Arrays.asList("-out", destDir, "-rep", "aether", "-verbose:cmr"), (DiagnosticListener<? super FileObject>) null, "modules/aetherdefault/module.ceylon", "modules/namespaces/foo.ceylon"); assertEquals(Boolean.TRUE, ceylonTask.call()); } }