/* * 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.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; import org.junit.Assert; import com.redhat.ceylon.compiler.java.metadata.Variance; import static com.redhat.ceylon.compiler.java.metadata.Variance.*; import com.redhat.ceylon.model.loader.ModelLoader; import com.redhat.ceylon.model.loader.ModelResolutionException; import com.redhat.ceylon.model.loader.TypeParser; import com.redhat.ceylon.model.loader.TypeParserException; import com.redhat.ceylon.model.typechecker.model.Class; import com.redhat.ceylon.model.typechecker.model.ClassOrInterface; import com.redhat.ceylon.model.typechecker.model.Interface; import com.redhat.ceylon.model.typechecker.model.Declaration; import com.redhat.ceylon.model.typechecker.model.IntersectionType; import com.redhat.ceylon.model.typechecker.model.Module; import com.redhat.ceylon.model.typechecker.model.Package; import com.redhat.ceylon.model.typechecker.model.Type; import com.redhat.ceylon.model.typechecker.model.Scope; import com.redhat.ceylon.model.typechecker.model.SiteVariance; import com.redhat.ceylon.model.typechecker.model.TypeDeclaration; import com.redhat.ceylon.model.typechecker.model.TypeParameter; import com.redhat.ceylon.model.typechecker.model.UnionType; import com.redhat.ceylon.model.typechecker.model.Unit; import com.redhat.ceylon.model.typechecker.util.TypePrinter; public class TypeParserTests { private static final Unit mockLangUnit = new Unit(); private static final Unit mockPkgUnit = new Unit(); private static final Unit mockDefaultUnit = new Unit(); private static final class MockPackage extends Package { ArrayList<Declaration> members = new ArrayList<>(); private final Module module; public MockPackage(Module module) { this.module = module; super.setModule(module); } public Module getModule() { return module; } @Override public void addMember(Declaration m) { members.add(m); } @Override public List<Declaration> getMembers() { return members; } } private static final Module mockLang = new Module(){ public Package getPackage(String name) { return mockLangPackage; } }; private static final Package mockLangPackage = new MockPackage(mockLang); static { mockLang.setUnit(mockLangUnit); mockLang.setLanguageModule(mockLang); mockLang.setName(Arrays.asList("ceylon", "language")); mockLang.setAvailable(true); mockLangPackage.setUnit(mockLangUnit); mockLangPackage.setName(Arrays.asList("ceylon", "language")); mockLang.getPackages().add(mockLangPackage); mockLangUnit.setPackage(mockLangPackage); } private static final Module mockDefaultModule = new Module(){ public Package getPackage(String name) { if (name.isEmpty()) { return mockDefaultPackage; } else if ("pkg".equals(name)) { return mockDefaultPackage; } else if ("ceylon.language".equals(name)) { return mockLangPackage; } throw new RuntimeException(name); } }; private static final Package mockDefaultPackage = new MockPackage(mockDefaultModule); static { mockDefaultModule.setLanguageModule(mockLang); mockDefaultModule.setName(Arrays.asList("")); mockDefaultModule.setUnit(mockDefaultUnit); mockDefaultPackage.setUnit(mockDefaultUnit); mockDefaultPackage.setName(Arrays.asList("")); mockDefaultUnit.setPackage(mockDefaultPackage); } private static final Module mockPkgModule = new Module(){ public Package getPackage(String name) { if ("pkg".equals(name)) { return mockPkgPackage; } else if (name.isEmpty()) { return mockDefaultPackage; } else if ("ceylon.language".equals(name)) { return mockLangPackage; } throw new RuntimeException(); } }; private static final Package mockPkgPackage = new MockPackage(mockPkgModule); static { mockPkgModule.setLanguageModule(mockLang); mockPkgModule.setName(Arrays.asList("pkg")); mockPkgModule.setUnit(mockPkgUnit); mockPkgPackage.setUnit(mockPkgUnit); mockPkgPackage.setName(Arrays.asList("pkg")); mockPkgUnit.setPackage(mockPkgPackage); } static class MockLoader implements ModelLoader { static final ModelLoader instance = new MockLoader(); private Map<String, ClassOrInterface> classes = new HashMap<String,ClassOrInterface>(); private Module defaultModule = mockDefaultModule; private Package defaultPkg = mockDefaultModule.getPackage(""); private Unit unit = mockDefaultUnit; private Module lang = mockLang; private Package langPkg = mockLang.getPackage("ceylon.language"); private MockLoader(){ //defaultModule.setName(Arrays.asList("")); //defaultModule.setLanguageModule(lang); //defaultPkg.setName(Arrays.asList("")); //defaultPkg.setModule(defaultModule); //unit.setPackage(defaultPkg); Class a = makeClass("a", defaultPkg); makeClass("b", a); makeClass("b", defaultPkg); makeClass("c", defaultPkg); makeClass("d", defaultPkg); makeClass("e", defaultPkg); makeClass("f", defaultPkg); Class t2 = makeParameterisedClass(defaultPkg, "t2", null, null, makeTp("A", Variance.NONE), makeTp("B", Variance.NONE)); makeParameterisedClass(t2, "t2", null, null, makeTp("A", Variance.NONE), makeTp("B", Variance.NONE)); Package otherPkg = new Package(); otherPkg.setUnit(mockPkgUnit); otherPkg.setName(Arrays.asList("pkg")); Module otherModeul = new Module(); otherModeul.setUnit(mockPkgUnit); otherPkg.setModule(otherModeul); makeClass("u", otherPkg); Class b = makeClass("v", otherPkg); makeClass("w", b); makeClass("package", otherPkg); langPkg.addMember(makeInterface("Empty", langPkg)); langPkg.addMember(makeClass("Null", langPkg)); langPkg.addMember(makeClass("Boolean", langPkg)); langPkg.addMember(makeInterface("Nothing", langPkg));// a lie, it's not an interface TypeParameter itElement = makeTp("Element", OUT); Interface iterable = makeParameterisedInterface(langPkg, "Iterable", null, itElement, makeTp("Absent", OUT)); langPkg.addMember(iterable); TypeParameter seqElement = makeTp("Element", OUT); Interface sequential = makeParameterisedInterface(langPkg, "Sequential", new Type[]{iterable.appliedType(null, Collections.singletonList(seqElement.getType()))},seqElement); langPkg.addMember(sequential); TypeParameter seqlElement = makeTp("Element", OUT); Interface sequence = makeParameterisedInterface(langPkg, "Sequence", new Type[]{sequential.appliedType(null, Collections.singletonList(seqlElement.getType()))}, seqlElement); langPkg.addMember(sequence); TypeParameter tupElement = makeTp("Element", OUT); langPkg.addMember(makeParameterisedClass(langPkg, "Tuple", null, new Type[]{sequential.appliedType(null, Collections.singletonList(tupElement.getType()))}, tupElement, makeTp("First", OUT), makeTp("Rest", OUT))); langPkg.addMember(makeParameterisedInterface(langPkg, "Callable", null, makeTp("Result", OUT), makeTp("Arguments", IN))); langPkg.addMember(makeParameterisedClass(langPkg, "Entry", null, null, makeTp("Key", OUT), makeTp("Item", OUT))); } @Override public Type getType(Module module, String pkg, String name, Scope scope) { Class klass = (Class)getDeclaration(module, pkg, name, scope); return klass.getType(); } @Override public Declaration getDeclaration(Module module, String pkg, String name, Scope scope) { ClassOrInterface klass = classes.get(name); if(klass == null) throw new ModelResolutionException("Unknown type: "+name); return klass; } private Class makeParameterisedClass(String name) { return makeParameterisedClass(null, name, null, null); } private Class makeParameterisedClass(Scope container, String name, Type extended, Type[] satisfied, TypeParameter... tps) { return makeParameterizedClassOrInterface(makeClass(name, container), tps, extended, satisfied); } private Interface makeParameterisedInterface(Scope container, String name, Type[] satisfied, TypeParameter...tps) { return makeParameterizedClassOrInterface(makeInterface(name, container), tps, null, satisfied); } private <T extends ClassOrInterface> T makeParameterizedClassOrInterface(T klass, TypeParameter[] tps, Type extended, Type[] satisfied) { if (extended != null) { klass.setExtendedType(extended); } if (satisfied != null) { klass.setSatisfiedTypes(Arrays.asList(satisfied)); } List<TypeParameter> typeParameters = new ArrayList<TypeParameter>(tps.length); for (TypeParameter tp : tps) { tp.setUnit(klass.getUnit()); tp.setContainer(klass); tp.setDeclaration(klass); typeParameters.add(tp); } klass.setTypeParameters(typeParameters ); return klass; } TypeParameter makeTp(String name, Variance v) { TypeParameter typeParam = new TypeParameter(); typeParam.setName(name); typeParam.setContravariant(v == Variance.IN); typeParam.setCovariant(v == Variance.OUT); return typeParam; } private Class makeClass(String name, Scope container) { return makeClassOrInterface(new Class(), name, container); } private Interface makeInterface(String name, Scope container) { return makeClassOrInterface(new Interface(), name, container); } private <T extends ClassOrInterface> T makeClassOrInterface(T klass, String name, Scope container) { klass.setName(name); klass.setShared(true); container.addMember(klass); klass.setContainer(container); if (container instanceof Package) { klass.setUnit(((Package)container).getUnit()); } else if (container instanceof ClassOrInterface) { klass.setUnit(((ClassOrInterface)container).getUnit()); } else { throw new RuntimeException(""+container); } if (container.getQualifiedNameString().isEmpty()) { classes.put(name, klass); } else { classes.put(container.getQualifiedNameString()+"."+name, klass); } return klass; } @Override public Declaration getDeclaration(Module module, String typeName, DeclarationType declarationType) { throw new RuntimeException("Not yet implemented"); } @Override public Module getLoadedModule(String moduleName, String version) { throw new RuntimeException("Not yet implemented"); } } @Test public void testUnion(){ Type type = new TypeParser(MockLoader.instance).decodeType("a|b|c", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); UnionType union = (UnionType) declaration; List<Type> types = union.getCaseTypes(); Assert.assertEquals(3, types.size()); Assert.assertEquals("a", types.get(0).getDeclaration().getName()); Assert.assertTrue(types.get(0).getDeclaration() instanceof Class); Assert.assertEquals("b", types.get(1).getDeclaration().getName()); Assert.assertTrue(types.get(1).getDeclaration() instanceof Class); Assert.assertEquals("c", types.get(2).getDeclaration().getName()); Assert.assertTrue(types.get(2).getDeclaration() instanceof Class); } @Test public void testIntersection(){ Type type = new TypeParser(MockLoader.instance).decodeType("a&b&c", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof IntersectionType); IntersectionType intersection = (IntersectionType) declaration; List<Type> types = intersection.getSatisfiedTypes(); Assert.assertEquals(3, types.size()); Assert.assertEquals("a", types.get(0).getDeclaration().getName()); Assert.assertTrue(types.get(0).getDeclaration() instanceof Class); Assert.assertEquals("b", types.get(1).getDeclaration().getName()); Assert.assertTrue(types.get(1).getDeclaration() instanceof Class); Assert.assertEquals("c", types.get(2).getDeclaration().getName()); Assert.assertTrue(types.get(2).getDeclaration() instanceof Class); } @Test public void testIntersectionAndUnion(){ Type type = new TypeParser(MockLoader.instance).decodeType("a&b|c", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); UnionType union = (UnionType) declaration; List<Type> unionTypes = union.getCaseTypes(); Assert.assertEquals(2, unionTypes.size()); Assert.assertTrue(unionTypes.get(0).getDeclaration() instanceof IntersectionType); IntersectionType intersection = (IntersectionType) unionTypes.get(0).getDeclaration(); List<Type> intersectionTypes = intersection.getSatisfiedTypes(); Assert.assertEquals(2, intersectionTypes.size()); Assert.assertEquals("a", intersectionTypes.get(0).getDeclaration().getName()); Assert.assertTrue(intersectionTypes.get(0).getDeclaration() instanceof Class); Assert.assertEquals("b", intersectionTypes.get(1).getDeclaration().getName()); Assert.assertTrue(intersectionTypes.get(1).getDeclaration() instanceof Class); Assert.assertEquals("c", unionTypes.get(1).getDeclaration().getName()); Assert.assertTrue(unionTypes.get(1).getDeclaration() instanceof Class); } @Test public void testParams(){ Type type = new TypeParser(MockLoader.instance).decodeType("t2<b,c>", null, mockDefaultModule, mockPkgUnit); assertTypeWithParameters(type); Assert.assertTrue(type.getVarianceOverrides().isEmpty()); } @Test public void testParamsVariance1(){ Type type = new TypeParser(MockLoader.instance).decodeType("t2<in b,out c>", null, mockDefaultModule, mockPkgUnit); assertTypeWithParameters(type); Map<TypeParameter, SiteVariance> varianceOverrides = type.getVarianceOverrides(); Assert.assertNotNull(varianceOverrides); Assert.assertEquals(2, varianceOverrides.size()); List<TypeParameter> tps = type.getDeclaration().getTypeParameters(); Assert.assertEquals(SiteVariance.IN, varianceOverrides.get(tps.get(0))); Assert.assertEquals(SiteVariance.OUT, varianceOverrides.get(tps.get(1))); } @Test public void testParamsVariance2(){ Type type = new TypeParser(MockLoader.instance).decodeType("t2<b,out c>", null, mockDefaultModule, mockPkgUnit); assertTypeWithParameters(type); Map<TypeParameter, SiteVariance> varianceOverrides = type.getVarianceOverrides(); Assert.assertNotNull(varianceOverrides); Assert.assertEquals(1, varianceOverrides.size()); List<TypeParameter> tps = type.getDeclaration().getTypeParameters(); Assert.assertEquals(null, varianceOverrides.get(tps.get(0))); Assert.assertEquals(SiteVariance.OUT, varianceOverrides.get(tps.get(1))); } @Test public void testParamsVariance3(){ Type type = new TypeParser(MockLoader.instance).decodeType("t2<in b,c>", null, mockDefaultModule, mockPkgUnit); assertTypeWithParameters(type); Map<TypeParameter, SiteVariance> varianceOverrides = type.getVarianceOverrides(); Assert.assertNotNull(varianceOverrides); Assert.assertEquals(1, varianceOverrides.size()); List<TypeParameter> tps = type.getDeclaration().getTypeParameters(); Assert.assertEquals(SiteVariance.IN, varianceOverrides.get(tps.get(0))); Assert.assertEquals(null, varianceOverrides.get(tps.get(1))); } private void assertTypeWithParameters(Type type) { Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("t2", declaration.getName()); List<Type> tal = type.getTypeArgumentList(); Assert.assertEquals(2, tal.size()); Assert.assertEquals("b", tal.get(0).getDeclaration().getName()); Assert.assertTrue(tal.get(0).getDeclaration() instanceof Class); Assert.assertEquals("c", tal.get(1).getDeclaration().getName()); Assert.assertTrue(tal.get(1).getDeclaration() instanceof Class); } @Test public void testUnionParams(){ Type type = new TypeParser(MockLoader.instance).decodeType("a|t2<b|c,t2<d,e|f>>", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); UnionType union = (UnionType) declaration; List<Type> caseTypes = union.getCaseTypes(); Assert.assertEquals(2, caseTypes.size()); // a Assert.assertEquals("a", caseTypes.get(0).getDeclaration().getName()); Assert.assertTrue(caseTypes.get(0).getDeclaration() instanceof Class); // first t2 Type firstT2 = caseTypes.get(1); TypeDeclaration firstT2Declaration = firstT2.getDeclaration(); Assert.assertNotNull(firstT2Declaration); Assert.assertTrue(firstT2Declaration instanceof Class); Assert.assertEquals("t2", firstT2Declaration.getName()); Assert.assertEquals(2, firstT2.getTypeArgumentList().size()); // b|c Type bc = firstT2.getTypeArgumentList().get(0); Assert.assertTrue(bc.getDeclaration() instanceof UnionType); Assert.assertEquals(2, bc.getDeclaration().getCaseTypes().size()); // b Type b = bc.getDeclaration().getCaseTypes().get(0); Assert.assertEquals("b", b.getDeclaration().getName()); Assert.assertTrue(b.getDeclaration() instanceof Class); // c Type c = bc.getDeclaration().getCaseTypes().get(1); Assert.assertEquals("c", c.getDeclaration().getName()); Assert.assertTrue(c.getDeclaration() instanceof Class); // second t2 Type secondT2 = firstT2.getTypeArgumentList().get(1); TypeDeclaration secondT2Declaration = firstT2.getDeclaration(); Assert.assertNotNull(secondT2Declaration); Assert.assertTrue(secondT2Declaration instanceof Class); Assert.assertEquals("t2", secondT2Declaration.getName()); Assert.assertEquals(2, secondT2.getTypeArgumentList().size()); // d Type d = secondT2.getTypeArgumentList().get(0); Assert.assertEquals("d", d.getDeclaration().getName()); Assert.assertTrue(d.getDeclaration() instanceof Class); // e|f Type ef = secondT2.getTypeArgumentList().get(1); Assert.assertTrue(ef.getDeclaration() instanceof UnionType); Assert.assertEquals(2, ef.getDeclaration().getCaseTypes().size()); // e Type e = ef.getDeclaration().getCaseTypes().get(0); Assert.assertEquals("e", e.getDeclaration().getName()); Assert.assertTrue(e.getDeclaration() instanceof Class); // f Type f = ef.getDeclaration().getCaseTypes().get(1); Assert.assertEquals("f", f.getDeclaration().getName()); Assert.assertTrue(f.getDeclaration() instanceof Class); } @Test public void testQualified(){ Type type = new TypeParser(MockLoader.instance).decodeType("a.b", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("a.b", declaration.getQualifiedNameString()); Type qualifyingType = type.getQualifyingType(); Assert.assertNotNull(qualifyingType); TypeDeclaration qualifyingDeclaration = qualifyingType.getDeclaration(); Assert.assertNotNull(qualifyingDeclaration); Assert.assertTrue(qualifyingDeclaration instanceof Class); Assert.assertEquals("a", qualifyingDeclaration.getName()); } @Test public void testQualifiedAndParameterised(){ Type type = new TypeParser(MockLoader.instance).decodeType("t2<a,b>.t2<c,d>", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("t2.t2", declaration.getQualifiedNameString()); Assert.assertEquals(2, type.getTypeArgumentList().size()); // c Type c = type.getTypeArgumentList().get(0); Assert.assertEquals("c", c.getDeclaration().getName()); Assert.assertTrue(c.getDeclaration() instanceof Class); // d Type d = type.getTypeArgumentList().get(1); Assert.assertEquals("d", d.getDeclaration().getName()); Assert.assertTrue(d.getDeclaration() instanceof Class); Type qualifyingType = type.getQualifyingType(); Assert.assertNotNull(qualifyingType); TypeDeclaration qualifyingDeclaration = qualifyingType.getDeclaration(); Assert.assertNotNull(qualifyingDeclaration); Assert.assertTrue(qualifyingDeclaration instanceof Class); Assert.assertEquals("t2", qualifyingDeclaration.getName()); Assert.assertEquals(2, qualifyingType.getTypeArgumentList().size()); // a Type a = qualifyingType.getTypeArgumentList().get(0); Assert.assertEquals("a", a.getDeclaration().getName()); Assert.assertTrue(a.getDeclaration() instanceof Class); // b Type b = qualifyingType.getTypeArgumentList().get(1); Assert.assertEquals("b", b.getDeclaration().getName()); Assert.assertTrue(b.getDeclaration() instanceof Class); } @Test public void testPackageQualified(){ Type type = new TypeParser(MockLoader.instance).decodeType("pkg::v", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("pkg::v", declaration.getQualifiedNameString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testComplexQualified(){ Type type = new TypeParser(MockLoader.instance).decodeType("<pkg::u&pkg::v>.w", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("pkg::v.w", declaration.getQualifiedNameString()); Type qualifyingType = type.getQualifyingType(); Assert.assertNotNull(qualifyingType); TypeDeclaration qualifyingDeclaration = qualifyingType.getDeclaration(); Assert.assertNotNull(qualifyingDeclaration); Assert.assertTrue(qualifyingDeclaration instanceof IntersectionType); Assert.assertEquals("u&v", qualifyingDeclaration.getName()); } @Test public void testEmptyAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Empty", declaration.getQualifiedNameString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testSequenceAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a+]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Sequence", declaration.getQualifiedNameString()); Assert.assertEquals("[a+]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testSequentialAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a*]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Sequential", declaration.getQualifiedNameString()); Assert.assertEquals("a[]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple1Abbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple2Abbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple3Abbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b,c]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b, c]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple1OrMoreAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b*]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b*]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple2OrMoreAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b+]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b+]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple2OrMoreAbbrev2(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b,c*]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b, c*]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple3OrMoreAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b,c+]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a, b, c+]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple1To3Abbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b=,c=]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); // can only test this for Callable as TypeNamePrinter only prints '=' for Callable // Assert.assertEquals("[a, b=, c=]", type.asString()); Assert.assertEquals("ceylon.language::Tuple<a|b|c,a,ceylon.language::Empty|ceylon.language::Tuple<b|c,b,ceylon.language::Empty|ceylon.language::Tuple<c,c,ceylon.language::Empty>>>", printType(type)); Assert.assertNull(type.getQualifyingType()); } // [a,b=,c+] it not allowed (for good reason) @Test public void testTuple1To3StarAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a,b=,c*]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("ceylon.language::Tuple<a|b|c,a,ceylon.language::Empty|ceylon.language::Tuple<b|c,b,ceylon.language::Sequential<c>>>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testTuple0To1Abbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("[a=]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); Assert.assertEquals("ceylon.language::Empty|ceylon.language::Tuple<a,a,ceylon.language::Empty>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testHomoTuple1(){ Type type = new TypeParser(MockLoader.instance).decodeType("a[1]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("[a]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testHomoTuple2(){ Type type = new TypeParser(MockLoader.instance).decodeType("a[2]", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Tuple", declaration.getQualifiedNameString()); Assert.assertEquals("a[2]", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testIterableAbbrev(){ try { new TypeParser(MockLoader.instance).decodeType("{a}", null, mockDefaultModule, mockPkgUnit); Assert.fail(); } catch ( TypeParserException e) { Assert.assertEquals("com.redhat.ceylon.model.loader.TypeParserException: Expected multiplicity in abbreviated Iterable type: 2", e.toString()); } } @Test public void testPossiblyEmptyIterableAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("{a*}", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Iterable", declaration.getQualifiedNameString()); Assert.assertEquals("{a*}", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testNonEmptyIterableAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("{a+}", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Iterable", declaration.getQualifiedNameString()); Assert.assertEquals("{a+}", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testCallableAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("a(b)", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Callable", declaration.getQualifiedNameString()); Assert.assertEquals("a(b)", type.asString()); Assert.assertNull(type.getQualifyingType()); type = new TypeParser(MockLoader.instance).decodeType("a(b,pkg::u*)", null, mockPkgModule, mockPkgUnit); Assert.assertNotNull(type); declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Callable", declaration.getQualifiedNameString()); Assert.assertEquals("ceylon.language::Callable<a,ceylon.language::Tuple<b|pkg::u,b,ceylon.language::Sequential<pkg::u>>>", printType(type)); Assert.assertNull(type.getQualifyingType()); type = new TypeParser(MockLoader.instance).decodeType("a(b=,pkg::u*)", null, mockPkgModule, mockPkgUnit); Assert.assertNotNull(type); declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Callable", declaration.getQualifiedNameString()); Assert.assertEquals("ceylon.language::Callable<a,ceylon.language::Empty|ceylon.language::Tuple<b|pkg::u,b,ceylon.language::Sequential<pkg::u>>>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testSpreadCallableAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("a(*[b,a])", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Callable", declaration.getQualifiedNameString()); Assert.assertEquals("a(b, a)", type.asString()); Assert.assertNull(type.getQualifyingType()); } @Test public void testEntryAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType(" a -> b ", null, mockDefaultModule, mockDefaultUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Entry", declaration.getQualifiedNameString()); Assert.assertEquals("ceylon.language::Entry<a,b>", printType(type)); Assert.assertNull(type.getQualifyingType()); type = new TypeParser(MockLoader.instance).decodeType("pkg::u|pkg::v->b", null, mockPkgModule, mockPkgUnit); Assert.assertNotNull(type); declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("ceylon.language::Entry", declaration.getQualifiedNameString()); Assert.assertEquals("ceylon.language::Entry<pkg::u|pkg::v,b>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testOptionalAbbrev(){ Type type = new TypeParser(MockLoader.instance).decodeType("a?", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); Assert.assertEquals("ceylon.language::Null|a", printType(type)); Assert.assertNull(type.getQualifyingType()); type = new TypeParser(MockLoader.instance).decodeType("pkg::u&pkg::v?", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof IntersectionType); Assert.assertEquals("pkg::u&<ceylon.language::Null|pkg::v>", printType(type)); Assert.assertNull(type.getQualifyingType()); type = new TypeParser(MockLoader.instance).decodeType("pkg::u|pkg::v[]?", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); Assert.assertEquals("pkg::u|ceylon.language::Null|ceylon.language::Sequential<pkg::v>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testCallableOfEntry(){ Type type = new TypeParser(MockLoader.instance).decodeType("ceylon.language::Boolean(ceylon.language::Nothing->ceylon.language::Nothing)", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Interface); Assert.assertEquals("ceylon.language::Callable<ceylon.language::Boolean,ceylon.language::Tuple<ceylon.language::Entry<ceylon.language::Nothing,ceylon.language::Nothing>,ceylon.language::Entry<ceylon.language::Nothing,ceylon.language::Nothing>,ceylon.language::Empty>>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testOptionalEntry(){ Type type = new TypeParser(MockLoader.instance).decodeType("<ceylon.language::Boolean->a>?", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof UnionType); Assert.assertEquals("ceylon.language::Null|ceylon.language::Entry<ceylon.language::Boolean,a>", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test public void testTypeCallPackage(){ Type type = new TypeParser(MockLoader.instance).decodeType("pkg::package", null, mockDefaultModule, mockPkgUnit); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("pkg::package", printType(type)); Assert.assertNull(type.getQualifyingType()); } @Test(expected = ModelResolutionException.class) public void testParameterisedPackage(){ new TypeParser(MockLoader.instance).decodeType("unknown<a>.b", null, mockDefaultModule, mockPkgUnit); } @Test(expected = ModelResolutionException.class) public void testUnknownMember(){ new TypeParser(MockLoader.instance).decodeType("a.unknown", null, mockDefaultModule, mockPkgUnit); } @Test(expected = TypeParserException.class) public void testInvalidType(){ new TypeParser(MockLoader.instance).decodeType("t2<a,b", null, mockDefaultModule, mockPkgUnit); } TypePrinter typePrinter = new TypePrinter( false, true, false, false, false, true, true); String printType(Type t) { return typePrinter.print(t, t.getDeclaration().getUnit()); } }