blob: 079c58e69bf168ed2cc1fe3db78989ec51f9e7a4 [file] [log] [blame]
/*
* 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};
}
}