/* * 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.recovery; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.TreeSet; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import javax.tools.Diagnostic; import javax.tools.Diagnostic.Kind; import javax.tools.DiagnosticCollector; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import ceylon.language.Anything; import ceylon.language.Callable; import com.redhat.ceylon.compiler.java.language.AbstractCallable; import com.redhat.ceylon.compiler.java.language.UnresolvedCompilationError; import com.redhat.ceylon.compiler.java.metadata.CompileTimeError; 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.tools.CeyloncTaskImpl; public class RecoveryTests extends CompilerTests { protected void compileAndRunWithUnresolvedCompilationError( String ceylon, String main, String expectedError, int... sequence) { compileIgnoringCeylonErrors(ceylon); runWithUnresolvedCompilationError(main, expectedError, sequence); } protected void runWithUnresolvedCompilationError(String main, String expectedError, int... sequence) { final ArrayList<ceylon.language.Integer> sb= new ArrayList<ceylon.language.Integer>(); Callable<Anything> c = new AbstractCallable<Anything>(Anything.$TypeDescriptor$, null, null, (short)-1) { public Anything $call$(java.lang.Object arg0) { sb.add((ceylon.language.Integer)arg0); return null; } }; try { run(main, new Class[]{Callable.class}, new Object[]{c}, getDestModuleWithArtifact(main)); Assert.fail("Expected execution to throw " + UnresolvedCompilationError.class.getName()); } catch (RuntimeException e) { Throwable e2 = e; while (e2.getCause() != null) { e2 = e2.getCause(); } if (e2 instanceof UnresolvedCompilationError) { Assert.assertEquals(expectedError, e2.getMessage()); } else { throw e; } } ArrayList<ceylon.language.Integer> expect = new ArrayList<ceylon.language.Integer>(); for (int ii : sequence) { expect.add(ceylon.language.Integer.instance(ii)); } Assert.assertEquals("Sequences differ", expect, sb); } protected void run(String main, int... sequence) { final ArrayList<ceylon.language.Integer> sb= new ArrayList<ceylon.language.Integer>(); Callable<Anything> c = new AbstractCallable<Anything>(Anything.$TypeDescriptor$, null, null, (short)-1) { public Anything $call$(java.lang.Object arg0) { sb.add((ceylon.language.Integer)arg0); return null; } }; run(main, new Class[]{Callable.class}, new Object[]{c}, getDestModuleWithArtifact(main)); ArrayList<ceylon.language.Integer> expect = new ArrayList<ceylon.language.Integer>(); for (int ii : sequence) { expect.add(ceylon.language.Integer.instance(ii)); } Assert.assertEquals("Sequences differ", expect, sb); } private ErrorCollector compileIgnoringCeylonErrors(String... ceylon) { ErrorCollector c = new ErrorCollector(); getCompilerTask(defaultOptions, c, ceylon).call2(); Assert.assertTrue("Expected only ceylon errors: " + c.getAssertionFailureMessage(), 0 == c.getNumBackendErrors()); return c; } private void checkClassHasCompileTimeErrorAnnotation(String brokenClass) { synchronized(RUN_LOCK){ try { URLClassLoader classLoader = getClassLoader(brokenClass, getDestModuleWithArtifact(brokenClass)); try { Class<?> c = Class.forName(brokenClass, false, classLoader); Assert.assertTrue("class lacks @CompileTimeError", c.isAnnotationPresent((CompileTimeError.class))); } finally { classLoader.close(); } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } } @Test public void testRcvBrokenClass(){ compile(2, "BrokenClass.ceylon"); } @Test public void testRcvBrokenMethod(){ compile(3, "BrokenMethod.ceylon"); } @Test public void testRcvBrokenAttribute(){ compile(10, "BrokenAttribute.ceylon"); } @Test public void testRcvClassWithBrokenMembers(){ compile(30, "ClassWithBrokenMembers.ceylon"); } @Test public void testRcvDuplicateDeclarations(){ // this is https://github.com/ceylon/ceylon-compiler/issues/250 compile(1, "DuplicateDeclaration1.ceylon", "DuplicateDeclaration2.ceylon"); } @Test public void testRcvM3Features(){ compile(1, "M3Features.ceylon"); } @Test public void testRcvIndirectUser(){ compile(1, "BrokenIndirectUser.ceylon"); } @Test public void testRcvDeclarationRecoveryAnnotationConstructor(){ compile(1, "declaration/DeclarationRecoveryAnnotationConstructor.ceylon"); // TODO assert we didn't generate anything } @Test public void testRcvDeclarationRecoveryAnnotationConstructorArgument(){ compile(1, "declaration/DeclarationRecoveryAnnotationConstructorArgument.ceylon"); // TODO assert we didn't generate anything } @Test public void testRcvDeclarationRecoveryClassExtends(){ // c.f. ExpressionRecoveryClassExtends: Error with the extended type is // a declaration error, error with the arguments is an expression error compile(1, "declaration/DeclarationRecoveryClassExtends.ceylon"); // TODO assert we didn't generate anything } @Test public void testRcvDeclarationRecoveryMissingRefinedMembers(){ compile(1, "declaration/DeclarationRecoveryMissingRefinedMembers"); } @Test public void testRcvDeclarationRecoveryObjectWithCtor(){ compile(1, "declaration/ObjectWithCtor.ceylon"); } private void testDeclarationRecovery( String prerequisites, String test, ExpectedError expectedErrors) { // compile the interface compile("declaration/"+prerequisites+".ceylon"); // compiler the broken class compileIgnoringErrors( expectedErrors, "declaration/"+test+".ceylon"); // compile and run the usage of the broken class compileAndRun( "com.redhat.ceylon.compiler.java.test.recovery.declaration."+Character.toLowerCase(test.charAt(0)) + test.substring(1)+"Usage", "declaration/"+test+"Usage.ceylon"); } @Test public void testRcvDeclarationMissingFunctionBody(){ compile(1, "declaration/MissingFunctionBody.ceylon"); } @Test public void testRcvDeclarationMissingConstructorBody(){ compile(1, "declaration/MissingConstructorBody.ceylon"); compileAndRunWithUnresolvedCompilationError( "declaration/MissingConstructorBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.declaration.MissingConstructorBody", "constructor delegates to constructor with a compiler error: init"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.declaration.MissingConstructorBody"); } @Test public void testRcvDeclarationClassPlAndCtors1(){ compileAndRunWithUnresolvedCompilationError( "declaration/ClassPlAndCtors1.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.declaration.classPlAndCtors1", "class with parameters may not declare constructors: class 'ClassPlAndCtors1' has a parameter list and a constructor"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.declaration.ClassPlAndCtors1"); } @Test public void testRcvDeclarationClassPlAndCtors2(){ compileAndRunWithUnresolvedCompilationError( "declaration/ClassPlAndCtors2.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.declaration.classPlAndCtors2", "no matching parameter declared by 'ClassPlAndCtors2': 'ClassPlAndCtors2' has 0 parameters"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.declaration.ClassPlAndCtors2"); } @Test public void testRcvDeclarationClassPlAndCtors3(){ compileAndRunWithUnresolvedCompilationError( "declaration/ClassPlAndCtors3.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.declaration.classPlAndCtors3", "class with parameters may not declare constructors: class 'ClassPlAndCtors3' has a parameter list and a constructor"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.declaration.ClassPlAndCtors3"); } @Test public void testRcvDeclarationClassPlAndCtors4(){ compileAndRunWithUnresolvedCompilationError( "declaration/ClassPlAndCtors4.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.declaration.classPlAndCtors4", "class with parameters may not declare constructors: class 'ClassPlAndCtors4' has a parameter list and a constructor"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.declaration.ClassPlAndCtors4"); } @Test public void testMissingActualAttributes() { testDeclarationRecovery("FormalAttributes", "MissingActualAttributes", new ExpectedError() { @Override public boolean expected(CompilerError e) { return e.message != null && e.message.matches("formal member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' not implemented in class hierarchy"); } }); } @Test public void testMissingActualMethods() { testDeclarationRecovery("FormalMethods", "MissingActualMethods", new ExpectedError() { @Override public boolean expected(CompilerError e) { return e.message != null && e.message.matches("formal member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' not implemented in class hierarchy"); } }); } @Test @Ignore public void testMissingActualClasses() { testDeclarationRecovery("FormalClasses", "MissingActualClasses", new ExpectedError() { @Override public boolean expected(CompilerError e) { return e.message != null && e.message.matches("formal member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' not implemented in class hierarchy"); } }); } @Test @Ignore public void testBrokenActualMethodParameters() { testDeclarationRecovery("FormalMethods", "BrokenActualMethodParameters", new ExpectedError() { @Override public boolean expected(CompilerError e) { String m = e.message; return m != null && (m.matches("formal member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' not implemented in class hierarchy") ||m.matches("member does not have the same number of parameters as the member it refines: '[a-zA-Z0-9_]+' declared by '[a-zA-Z0-9_]+' refining '[a-zA-Z0-9_]+' declared by '[a-zA-Z0-9_]+'") ||m.matches("member must have the same number of parameter lists as refined member: 'tpMethodAUnary' in 'FormalMethods'") ||m.matches("missing parameter list in function declaration") ||m.matches("type of parameter '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' declared by '[a-zA-Z0-9_]+' is different to type of corresponding parameter '[a-zA-Z0-9_]+' of refined member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+': '[a-zA-Z0-9_()]+' is not exactly '[a-zA-Z0-9_()]+'") ||m.matches("member must have the same number of parameter lists as refined member: '[a-zA-Z0-9_]+' in '[a-zA-Z0-9_]+'")); } }); } @Test @Ignore public void testBrokenActualClassParameters() { testDeclarationRecovery("FormalClasses", "BrokenActualClassParameters", new ExpectedError() { @Override public boolean expected(CompilerError e) { return e.message != null && e.message.matches("formal member '[a-zA-Z0-9_]+' of '[a-zA-Z0-9_]+' not implemented in class hierarchy"); } }); } @Test public void testRcvExpressionRecoveryClassDp(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassDp.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassDp", "function or value does not exist: 'asdfClassDp'"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassDp"); } @Test public void testRcvExpressionRecoveryClassExtends(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassExtends.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassExtends", "no matching parameter declared by 'Basic': 'Basic' has 0 parameters"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassExtends"); } @Test @Ignore("#1960") public void testRcvExpressionRecoveryClassExtendsMissingParens(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassExtendsMissingParens.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassExtendsMissingParens", "missing instantiation arguments"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassExtendsMissingParens"); } @Test public void testRcvExpressionRecoveryClassInitValueInit() { compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassInitValueInit.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueInit", "function or value does not exist: 'asdfClassInitValueInit'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueInit"); } @Test public void testRcvExpressionRecoveryClassInitVariableValueInit(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassInitVariableValueInit.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitVariableValueInit", "function or value does not exist: 'asdfClassInitVariableValueInit'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitVariableValueInit"); } @Test public void testRcvExpressionRecoveryClassInitValueSpecifier(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassInitValueSpecifier.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueSpecifier", "function or value does not exist: 'asdfClassInitValueSpecifier'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueSpecifier"); } @Test public void testRcvExpressionRecoveryClassInitValueSpecifierDeferred(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassInitValueSpecifierDeferred.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueSpecifierDeferred", "function or value does not exist: 'asdfClassInitValueSpecifierDeferred'", 1, 2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitValueSpecifierDeferred"); } @Test public void testRcvExpressionRecoveryClassInitIf(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassInitIf.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitIf", "function or value does not exist: 'asdfClassInitIf'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassInitIf"); } @Test public void testRcvExpressionRecoveryClassMethodDp(){ compileIgnoringCeylonErrors( "expression/ExpressionRecoveryClassMethodDp.ceylon"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodDp_throw", "function or value does not exist: 'asdfClassMethodDp'", 1, 2); run("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodDp_nothrow", 1, 2, 5, 10); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodDp_throw2", "function or value does not exist: 'asdfClassMethodDp'", 1, 2, 3); run("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodDp_nothrow2", 1, 2, 3, 5, 10); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassMethodDp"); } @Test public void testRcvExpressionRecoveryClassMethodBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassMethodBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodBody_main", "function or value does not exist: 'asdfClassMethodBody'", 1, 2, 3); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassMethodBody"); } @Test public void testRcvExpressionRecoveryClassMethodSpecifier(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassMethodSpecifier.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodSpecifier_main", "function or value does not exist: 'asdfClassMethodSpecifier'", 1, 2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassMethodSpecifier"); } @Test public void testRcvExpressionRecoveryClassMethodSpecifierDeferred(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassMethodSpecifierDeferred.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassMethodSpecifierDeferred_main", "function or value does not exist: 'asdfClassMethodSpecifierDeferred'", // in the deferred case we throw when an instance is initialized // rather than when the method is called. 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassMethodSpecifierDeferred"); } @Test public void testRcvExpressionRecoveryClassAttributeBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassAttributeBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassAttributeBody_main", "function or value does not exist: 'asdfClassAttributeBody'", 1, 2, 3); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassAttributeBody"); } @Test public void testRcvExpressionRecoveryClassSetterBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryClassSetterBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryClassSetterBody_main", "unknown type", 1, 2, 3, 4, 5); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryClassSetterBody"); } @Test public void testRcvExpressionRecoveryInterfaceMethodDp(){ compileIgnoringCeylonErrors( "expression/ExpressionRecoveryInterfaceMethodDp.ceylon"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodDp_throw", "function or value does not exist: 'asdfInterfaceMethodDp'", 1, 2); run("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodDp_nothrow", 1, 2, 5, 10); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodDp_throw2", "function or value does not exist: 'asdfInterfaceMethodDp'", 1, 2, 3); run("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodDp_nothrow2", 1, 2, 3, 5, 10); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryInterfaceMethodDp"); } @Test public void testRcvExpressionRecoveryInterfaceMethodBody(){ compileIgnoringCeylonErrors( "expression/ExpressionRecoveryInterfaceMethodBody.ceylon"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodBody_main", "function or value does not exist: 'asdfInterfaceMethodBody'", 1, 2, 3); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceMethodBody_main2", "function or value does not exist: 'asdfInterfaceMethodBody'", 1, 2, 3); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryInterfaceMethodBody"); } @Test public void testRcvExpressionRecoveryInterfaceAttributeBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryInterfaceAttributeBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceAttributeBody_main", "function or value does not exist: 'asdfInterfaceAttributeBody'", 1, 2, 3); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryInterfaceAttributeBody"); } @Test public void testRcvExpressionRecoveryInterfaceSetterBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryInterfaceSetterBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryInterfaceSetterBody_main", "unknown type", 1, 2, 3, 4, 5); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.ExpressionRecoveryInterfaceSetterBody"); } @Test public void testRcvExpressionRecoveryFunctionDp(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryFunctionDp.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionDp", "function or value does not exist: 'asdfFunctionDp'"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionDp_"); } @Test public void testRcvExpressionRecoveryFunctionBody(){ compileIgnoringCeylonErrors( "expression/ExpressionRecoveryFunctionBody.ceylon"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionBody", "function or value does not exist: 'asdfFunctionBody'", 1); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionBodyMpl_main", "function or value does not exist: 'asdfFunctionBodyMpl'", 1,2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionBody_"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionBodyMpl_"); } @Test public void testRcvExpressionRecoveryFunctionSpecifier(){ compileIgnoringCeylonErrors( "expression/ExpressionRecoveryFunctionSpecifier.ceylon"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionSpecifier", "function or value does not exist: 'asdfFunctionSpecifier'"); runWithUnresolvedCompilationError( "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionSpecifierMpl_main", "function or value does not exist: 'asdfFunctionSpecifierMpl'"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionSpecifier_"); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryFunctionSpecifierMpl_"); } @Test public void testRcvExpressionRecoveryValueBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryValueBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueBody_main", "function or value does not exist: 'asdfValueBody'", 1,2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueBody_"); } @Test public void testRcvExpressionRecoveryValueSpecifier(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryValueSpecifier.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueSpecifier_main", "function or value does not exist: 'asdfValueSpecifier'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueSpecifier_"); } @Test public void testRcvExpressionRecoveryValueInit(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryValueInit.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueInit_main", "function or value does not exist: 'asdfValueInit'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryValueInit_"); } @Test public void testRcvExpressionRecoveryVariableValueInit(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryVariableValueInit.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryVariableValueInit_main", "function or value does not exist: 'asdfVariableValueInit'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryVariableValueInit_"); } @Test public void testRcvExpressionRecoverySetterBody(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoverySetterBody.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoverySetterBody_main", "function or value does not exist: 'asdfSetterBody'", 1, 2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoverySetterBody_"); } @Test public void testRcvExpressionRecoverySetterSpecifier(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoverySetterSpecifier.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoverySetterSpecifier_main", "function or value does not exist: 'asdfSetterSpecifier'", 1,2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoverySetterSpecifier_"); } @Test public void testRcvExpressionRecoveryIf(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryIf.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryIf", "function or value does not exist: 'asdfIf'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryIf_"); } @Test public void testRcvExpressionRecoveryElseIf(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryElseIf.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryElseIf", "function or value does not exist: 'asdfElseIf'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryElseIf_"); } @Test public void testRcvExpressionRecoveryIfBlock(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryIfBlock.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryIfBlock", "function or value does not exist: 'asdfIfBlock'", 1, 2); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryIfBlock_"); } @Test public void testRcvExpressionRecoveryForClause(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryForClause.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryForClause", "function or value does not exist: 'asdfForClause'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryForClause_"); } @Test public void testRcvExpressionRecoveryAssertVariable(){ compileAndRunWithUnresolvedCompilationError( "expression/ExpressionRecoveryAssertVariable.ceylon", "com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryAssertVariable", "function or value does not exist: 'baz'", 1); checkClassHasCompileTimeErrorAnnotation("com.redhat.ceylon.compiler.java.test.recovery.expression.expressionRecoveryAssertVariable_"); } private void compile(int expectedErrors, String... ceylon){ DiagnosticCollector<JavaFileObject> errorCollector = new DiagnosticCollector<JavaFileObject>(); // Stef: can't seem to be able to get this cast right no matter what I try @SuppressWarnings({ "unchecked", "rawtypes" }) Boolean success = getCompilerTask(defaultOptions, (DiagnosticListener)errorCollector , ceylon).call(); Assert.assertEquals(expectedErrors, getErrorCount(errorCollector)); Assert.assertFalse(success); } private int getErrorCount(DiagnosticCollector<JavaFileObject> errorCollector) { int errors = 0; for(Diagnostic<? extends JavaFileObject> diagnostic : errorCollector.getDiagnostics()){ if(diagnostic.getKind() == Kind.ERROR) errors++; if(diagnostic.getSource() != null){ System.err.println("("+diagnostic.getKind()+") "+diagnostic.getSource().getName() +"["+diagnostic.getLineNumber()+","+diagnostic.getColumnNumber()+"]: " +diagnostic.getMessage(Locale.getDefault())); }else{ System.err.println("("+diagnostic.getKind()+"): " +diagnostic.getMessage(Locale.getDefault())); } } return errors; } @Test public void testDuplicateInDefault() throws IOException { String subPath = "modules/duplicateInDefault"; String srcPath = getPackagePath()+subPath; List<String> options = new LinkedList<String>(); options.add("-src"); options.add(srcPath); options.addAll(defaultOptions); options.add("-continue"); ErrorCollector c = new ErrorCollector(); CeyloncTaskImpl task = getCompilerTask(options, c, Arrays.asList("okmodule"), subPath + "/dupdeclerr1.ceylon", subPath + "/dupdeclerr2.ceylon", subPath + "/someok.ceylon"); Boolean ret = task.call(); assertFalse(ret); TreeSet<CompilerError> actualErrors = c.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, // new CompilerError(21, "cannot find module artifact notfound-1(.car|.jar)\n \t- dependency tree: okmodule/1.0.0 -> notfound/1"), new CompilerError(20, "duplicate declaration name: 'run'")); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("foobar_.class"); assertNotNull(moduleClass); car.close(); carFile = getModuleArchive("okmodule", "1.0.0"); assertTrue(carFile.exists()); car = new JarFile(carFile); moduleClass = car.getEntry("okmodule/$module_.class"); assertNotNull(moduleClass); car.close(); } @Test public void testMissingImport() throws IOException { String subPath = "modules/missingImport"; String srcPath = getPackagePath()+subPath; List<String> options = new LinkedList<String>(); options.add("-src"); options.add(srcPath); options.addAll(defaultOptions); options.add("-continue"); ErrorCollector c = new ErrorCollector(); CeyloncTaskImpl task = getCompilerTask(options, c, Arrays.asList("okmodule"), subPath + "/someok.ceylon"); Boolean ret = task.call(); assertFalse(ret); TreeSet<CompilerError> actualErrors = c.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, new CompilerError(21, "cannot find module artifact notfound-1(.car|.jar)\n \t- dependency tree: okmodule/1.0.0 -> notfound/1")); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("foobar_.class"); assertNotNull(moduleClass); car.close(); carFile = getModuleArchive("okmodule", "1.0.0"); assertFalse(carFile.exists()); } @Test public void testSyntaxErrorInModule() throws IOException { String subPath = "modules/syntaxErrorInModule"; String srcPath = getPackagePath()+subPath; List<String> options = new LinkedList<String>(); options.add("-src"); options.add(srcPath); options.addAll(defaultOptions); options.add("-continue"); ErrorCollector c = new ErrorCollector(); CeyloncTaskImpl task = getCompilerTask(options, c, Arrays.asList("okmodule"), subPath + "/someok.ceylon"); Boolean ret = task.call(); assertFalse(ret); TreeSet<CompilerError> actualErrors = c.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, new CompilerError(-1, "incorrect syntax: no viable alternative at token end of file"), new CompilerError(20, "incorrect syntax: mismatched token 'ERROR' expecting initial-lowercase identifier"), new CompilerError(20, "incorrect syntax: no viable alternative at token '\"1.0.0\"'"), new CompilerError(20, "incorrect syntax: no viable alternative at token 'okmodule'") // this one is gone for some reason // new CompilerError(21, "incorrect syntax: no viable alternative at token '}'") ); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("foobar_.class"); assertNotNull(moduleClass); car.close(); carFile = getModuleArchive("okmodule", "1.0.0"); assertFalse(carFile.exists()); } @Ignore("This test largely depends on modules that are now binary-incompatible") @Test public void testTako() throws IOException { String subPath = "modules/bug1411"; String srcPath = getPackagePath()+subPath; List<String> options = new LinkedList<String>(); options.add("-src"); options.add(srcPath); options.addAll(defaultOptions); options.add("-continue"); ErrorCollector c = new ErrorCollector(); CeyloncTaskImpl task = getCompilerTask(options, c, subPath + "/dupdecl.ceylon", subPath + "/moduletest1/module.ceylon", subPath + "/moduletest1/package.ceylon", subPath + "/moduletest1/helloworld.ceylon", subPath + "/hello/hello.ceylon", subPath + "/hello/module.ceylon", subPath + "/hello/package.ceylon", subPath + "/testtest/module.ceylon", subPath + "/testtest/test.ceylon", subPath + "/sub/mod/module.ceylon", subPath + "/sub/mod/run.ceylon", subPath + "/sub/mod/package.ceylon", subPath + "/unknownmodule/module.ceylon", subPath + "/unknownmodule/run.ceylon", subPath + "/unknownmodule/package.ceylon", subPath + "/interop/module.ceylon", subPath + "/interop/interop.ceylon", subPath + "/jsonly/jsonly.ceylon", subPath + "/jsonly/module.ceylon", subPath + "/jsonly/package.ceylon", subPath + "/modulep/module.ceylon", subPath + "/modulep/main.ceylon", subPath + "/browser/dom/main.ceylon", subPath + "/browser/dom/package.ceylon", subPath + "/browser/module.ceylon", subPath + "/browser/main.ceylon", subPath + "/browser/package.ceylon", subPath + "/test/InheritanceAndBoxingTest.ceylon", subPath + "/test/ExceptionTest.ceylon", subPath + "/test/Foo.ceylon", subPath + "/test/GameOfLife.ceylon", subPath + "/test/Bar.ceylon", subPath + "/test/encoding.ceylon", subPath + "/test/helloworld.ceylon", subPath + "/swing/module.ceylon", subPath + "/swing/run.ceylon", subPath + "/swing/package.ceylon", subPath + "/interoprev/module.ceylon", subPath + "/interoprev/run.ceylon", subPath + "/interoprev/package.ceylon", subPath + "/java/hello.ceylon", subPath + "/java/module.ceylon", subPath + "/java/package.ceylon", subPath + "/helloworld.ceylon", subPath + "/wrongversion/module.ceylon", subPath + "/wrongversion/run.ceylon", subPath + "/wrongversion/package.ceylon", subPath + "/importhello/module.ceylon", subPath + "/importhello/helloworld.ceylon", subPath + "/usingimport.ceylon", // These depend on the error recovery we plan for 1.1 // subPath + "/javaa/bugJvm1290.ceylon", // subPath + "/javaa/module.ceylon", // subPath + "/javaa/run.ceylon" subPath + "/gavinprob/module.ceylon", subPath + "/gavinprob/main.ceylon", subPath + "/web_ide_script/module.ceylon", subPath + "/web_ide_script/hello_world.ceylon", subPath + "/timetest/module.ceylon", subPath + "/timetest/test.ceylon" ); Boolean ret = task.call(); assertFalse(ret); TreeSet<CompilerError> actualErrors = c.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, new CompilerError(1, "package not found in imported modules: 'java.lang' (define a module and add module import to its module descriptor)"), new CompilerError(2, "source code imports two different versions of module 'ceylon.file': version '0.5' and version '1.1.0'"), new CompilerError(2, "cannot find module artifact fooxhilio.bastardo-77.9(.car|.jar)\n" +" \t- dependency tree: unknownmodule/1.0.0 -> fooxhilio.bastardo/77.9"), new CompilerError(4, "function or value does not exist: 'nanoTime'"), new CompilerError(4, "type does not exist: 'Test'"), new CompilerError(4, "unsupported module name: this namespace is used by Java platform modules"), new CompilerError(5, "duplicate declaration name: 'run'"), new CompilerError(7, "duplicate declaration name: 'run'"), new CompilerError(10, "case must be a toplevel anonymous class: 'alive' is not toplevel"), new CompilerError(10, "case must be a toplevel anonymous class: 'dead' is not toplevel"), new CompilerError(10, "case must be a toplevel anonymous class: 'moribund' is not toplevel"), new CompilerError(10, "case must be a toplevel anonymous class: 'resurrected' is not toplevel"), new CompilerError(12, "imported declaration not found: 'newServer_bogus'"), new CompilerError(30, "function or value does not exist: 'newServer_bogus'"), new CompilerError(135, "function or value does not exist: 'array'"), new CompilerError(138, "could not determine type of function or value reference: 'cells'"), new CompilerError(139, "could not determine type of function or value reference: 'c'"), new CompilerError(140, "could not determine type of function or value reference: 'c'") ); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); String[] modules = new String[]{ "swing/1.0.0", "web_ide_script/1.0.0", "browser/1.0.0", "timetest/1.0.0", "interop/1.0.0", "importhello/0.1", "interoprev/1.0.0", "modulep/0.1", "hello/1.0.0", "moduletest1/0.1", "jsonly/1.0.0", "testtest/1.1", "sub.mod/1.0.0" }; for(String module : modules){ int sep = module.indexOf('/'); String name = module.substring(0, sep); String version = module.substring(sep+1); carFile = getModuleArchive(name, version); assertTrue("Module created car: "+module, carFile.exists()); } } @Test public void testErrorSameCompilationUnit() throws IOException { String subPath = "modules/errorInSameCompilationUnit"; String srcPath = getPackagePath()+subPath; List<String> options = new LinkedList<String>(); options.add("-src"); options.add(srcPath); options.addAll(defaultOptions); options.add("-continue"); ErrorCollector c = new ErrorCollector(); CeyloncTaskImpl task = getCompilerTask(options, c, subPath + "/someok.ceylon"); Boolean ret = task.call(); assertFalse(ret); TreeSet<CompilerError> actualErrors = c.get(Diagnostic.Kind.ERROR); compareErrors(actualErrors, new CompilerError(23, "type does not exist: 'ERROR'") ); File carFile = getModuleArchive("default", null); assertTrue(carFile.exists()); JarFile car = new JarFile(carFile); ZipEntry moduleClass = car.getEntry("a_.class"); assertNotNull(moduleClass); car.close(); } }