| /* |
| * Copyright (c) 2014, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package com.google.dart.engine.internal.type; |
| |
| import com.google.dart.engine.EngineTestCase; |
| import com.google.dart.engine.element.ClassElement; |
| import com.google.dart.engine.type.FunctionType; |
| import com.google.dart.engine.type.InterfaceType; |
| import com.google.dart.engine.type.Type; |
| import com.google.dart.engine.type.UnionType; |
| |
| import static com.google.dart.engine.element.ElementFactory.classElement; |
| import static com.google.dart.engine.element.ElementFactory.functionElement; |
| |
| import java.util.Set; |
| |
| public class UnionTypeImplTest extends EngineTestCase { |
| private ClassElement classA; |
| private InterfaceType typeA; |
| private ClassElement classB; |
| private InterfaceType typeB; |
| |
| private Type uA; |
| private Type uB; |
| private Type uAB; |
| private Type uBA; |
| |
| private Type[] us; |
| |
| public void test_emptyUnionsNotAllowed() { |
| try { |
| UnionTypeImpl.union(); |
| } catch (IllegalArgumentException e) { |
| return; |
| } |
| fail("Expected illegal argument exception."); |
| } |
| |
| public void test_equality_beingASubtypeOfAnElementIsNotSufficient() { |
| // Non-equal if some elements are different |
| assertFalse(uAB.equals(uA)); |
| } |
| |
| public void test_equality_insertionOrderDoesntMatter() { |
| // Insertion order doesn't matter, only sets of elements |
| assertTrue(uAB.equals(uBA)); |
| assertTrue(uBA.equals(uAB)); |
| } |
| |
| public void test_equality_reflexivity() { |
| for (Type u : us) { |
| assertTrue(u.equals(u)); |
| } |
| } |
| |
| public void test_equality_singletonsCollapse() { |
| assertTrue(typeA.equals(uA)); |
| assertTrue(uA.equals(typeA)); |
| } |
| |
| public void test_isMoreSpecificThan_allElementsOnLHSAreSubtypesOfSomeElementOnRHS() { |
| // Unions are subtypes when all elements are subtypes |
| assertTrue(uAB.isMoreSpecificThan(uA)); |
| assertTrue(uAB.isMoreSpecificThan(typeA)); |
| } |
| |
| public void test_isMoreSpecificThan_element() { |
| // Elements of union are sub types |
| assertTrue(typeA.isMoreSpecificThan(uAB)); |
| assertTrue(typeB.isMoreSpecificThan(uAB)); |
| } |
| |
| public void test_isMoreSpecificThan_notSubtypeOfAnyElement() { |
| // Types that are not subtypes of elements are not subtypes |
| assertFalse(typeA.isMoreSpecificThan(uB)); |
| } |
| |
| public void test_isMoreSpecificThan_reflexivity() { |
| for (Type u : us) { |
| assertTrue(u.isMoreSpecificThan(u)); |
| } |
| } |
| |
| // This tests the less strict (more unsound) subtype semantics for union types. |
| // It will break if we change to the more strict definition of subtyping. |
| public void test_isMoreSpecificThan_someElementOnLHSIsNotASubtypeOfAnyElementOnRHS() { |
| // Unions are subtypes when some element is a subtype |
| assertTrue(uAB.isMoreSpecificThan(uB)); |
| assertTrue(uAB.isMoreSpecificThan(typeB)); |
| } |
| |
| public void test_isMoreSpecificThan_subtypeOfSomeElement() { |
| // Subtypes of elements are sub types |
| assertTrue(typeB.isMoreSpecificThan(uA)); |
| } |
| |
| public void test_isSubtypeOf_allElementsOnLHSAreSubtypesOfSomeElementOnRHS() { |
| // Unions are subtypes when all elements are subtypes |
| assertTrue(uAB.isSubtypeOf(uA)); |
| assertTrue(uAB.isSubtypeOf(typeA)); |
| } |
| |
| public void test_isSubtypeOf_element() { |
| // Elements of union are sub types |
| assertTrue(typeA.isSubtypeOf(uAB)); |
| assertTrue(typeB.isSubtypeOf(uAB)); |
| } |
| |
| public void test_isSubtypeOf_notSubtypeOfAnyElement() { |
| // Types that are not subtypes of elements are not subtypes |
| assertFalse(typeA.isSubtypeOf(uB)); |
| } |
| |
| public void test_isSubtypeOf_reflexivity() { |
| for (Type u : us) { |
| assertTrue(u.isSubtypeOf(u)); |
| } |
| } |
| |
| // This tests the less strict (more unsound) subtype semantics for union types. |
| // It will break if we change to the more strict definition of subtyping. |
| public void test_isSubtypeOf_someElementOnLHSIsNotASubtypeOfAnyElementOnRHS() { |
| // Unions are subtypes when some element is a subtype |
| assertTrue(uAB.isSubtypeOf(uB)); |
| assertTrue(uAB.isSubtypeOf(typeB)); |
| } |
| |
| public void test_isSubtypeOf_subtypeOfSomeElement() { |
| // Subtypes of elements are sub types |
| assertTrue(typeB.isSubtypeOf(uA)); |
| } |
| |
| public void test_nestedUnionsCollapse() { |
| UnionType u = (UnionType) UnionTypeImpl.union(uAB, typeA); |
| for (Type t : u.getElements()) { |
| if (t instanceof UnionType) { |
| fail("Expected only non-union types but found " + t + "!"); |
| } |
| } |
| } |
| |
| public void test_noLossage() { |
| UnionType u = (UnionType) UnionTypeImpl.union(typeA, typeB, typeB, typeA, typeB, typeB); |
| Set<Type> elements = u.getElements(); |
| assertTrue(elements.contains(typeA)); |
| assertTrue(elements.contains(typeB)); |
| assertTrue(elements.size() == 2); |
| } |
| |
| public void test_substitute() { |
| // Based on [InterfaceTypeImplTest.test_substitute_equal]. |
| ClassElement classAE = classElement("A", "E"); |
| InterfaceType typeAE = classAE.getType(); |
| Type[] args = {typeB}; |
| Type[] params = {classAE.getTypeParameters()[0].getType()}; |
| Type typeAESubbed = typeAE.substitute(args, params); |
| |
| assertFalse(typeAE.equals(typeAESubbed)); |
| assertEquals( |
| UnionTypeImpl.union(typeA, typeAE).substitute(args, params), |
| UnionTypeImpl.union(typeA, typeAESubbed)); |
| } |
| |
| public void test_toString_pair() { |
| String s = uAB.toString(); |
| assertTrue(s.equals("{A,B}") || s.equals("{B,A}")); |
| assertEquals(s, uAB.getDisplayName()); |
| } |
| |
| public void test_toString_singleton() { |
| // Singleton unions collapse to the the single type. |
| assertEquals("A", uA.toString()); |
| } |
| |
| public void test_unionTypeIsLessSpecificThan_function() { |
| // Based on [FunctionTypeImplTest.test_isAssignableTo_normalAndPositionalArgs]. |
| ClassElement a = classElement("A"); |
| FunctionType t = functionElement("t", null, new ClassElement[] {a}).getType(); |
| Type uAT = UnionTypeImpl.union(uA, t); |
| assertTrue(t.isMoreSpecificThan(uAT)); |
| assertFalse(t.isMoreSpecificThan(uAB)); |
| } |
| |
| public void test_unionTypeIsSuperTypeOf_function() { |
| // Based on [FunctionTypeImplTest.test_isAssignableTo_normalAndPositionalArgs]. |
| ClassElement a = classElement("A"); |
| FunctionType t = functionElement("t", null, new ClassElement[] {a}).getType(); |
| Type uAT = UnionTypeImpl.union(uA, t); |
| assertTrue(t.isSubtypeOf(uAT)); |
| assertFalse(t.isSubtypeOf(uAB)); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| classA = classElement("A"); |
| typeA = classA.getType(); |
| classB = classElement("B", typeA); |
| typeB = classB.getType(); |
| |
| uA = UnionTypeImpl.union(typeA); |
| uB = UnionTypeImpl.union(typeB); |
| uAB = UnionTypeImpl.union(typeA, typeB); |
| uBA = UnionTypeImpl.union(typeB, typeA); |
| |
| us = new Type[] {uA, uB, uAB, uBA}; |
| } |
| } |