/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.common.reflect;
import java.io.Serializable;
import java.util.Comparator;
import java.util.List;
import junit.framework.TestCase;
@AndroidIncompatible // lots of failures, possibly some related to bad equals() implementations?
public class TypeTokenSubtypeTest extends TestCase {
public void testOwnerTypeSubtypes() throws Exception {
new OwnerTypeSubtypingTests().testAllDeclarations();
}
public void testWildcardSubtypes() throws Exception {
new WildcardSubtypingTests().testAllDeclarations();
}
public void testSubtypeOfInnerClass_nonStaticAnonymousClass() {
TypeToken<?> supertype = new TypeToken<Mall<Outdoor>.Shop<Electronics>>() {};
Class<?> subclass = new Mall<Outdoor>().new Shop<Electronics>() {}.getClass();
assertTrue(TypeToken.of(subclass).isSubtypeOf(supertype));
}
public void testSubtypeOfInnerClass_nonStaticAnonymousClass_typeParameterOfOwnerTypeNotMatch() {
TypeToken<?> supertype = new TypeToken<Mall<Outdoor>.Shop<Electronics>>() {};
Class<?> subclass = new Mall<Indoor>().new Shop<Electronics>() {}.getClass();
assertFalse(TypeToken.of(subclass).isSubtypeOf(supertype));
}
public void testSubtypeOfInnerClass_nonStaticAnonymousClass_typeParameterOfInnerTypeNotMatch() {
TypeToken<?> supertype = new TypeToken<Mall<Outdoor>.Shop<Electronics>>() {};
Class<?> subclass = new Mall<Outdoor>().new Shop<Grocery>() {}.getClass();
assertFalse(TypeToken.of(subclass).isSubtypeOf(supertype));
}
public static void testSubtypeOfInnerClass_staticAnonymousClass() {
TypeToken<?> supertype = new TypeToken<Mall<Outdoor>.Shop<Electronics>>() {};
Class<?> subclass = new Mall<Outdoor>().new Shop<Electronics>() {}.getClass();
assertTrue(TypeToken.of(subclass).isSubtypeOf(supertype));
}
public static void testSubtypeOfStaticAnonymousClass() {
Class<?> superclass = new Mall<Outdoor>().new Shop<Electronics>() {}.getClass();
assertTrue(TypeToken.of(superclass).isSubtypeOf(superclass));
assertFalse(TypeToken.of(new Mall<Outdoor>().new Shop<Electronics>() {}.getClass())
.isSubtypeOf(superclass));
}
public void testSubtypeOfNonStaticAnonymousClass() {
Class<?> superclass = new Mall<Outdoor>().new Shop<Electronics>() {}.getClass();
assertTrue(TypeToken.of(superclass).isSubtypeOf(superclass));
assertFalse(TypeToken.of(new Mall<Outdoor>().new Shop<Electronics>() {}.getClass())
.isSubtypeOf(superclass));
}
private static class OwnerTypeSubtypingTests extends SubtypeTester {
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> innerTypeIsSubtype(
Mall<Outdoor>.Retailer<Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<Outdoor>.Shop<? extends Electronics> innerTypeIsSubtype_supertypeWithWildcard(
Mall<Outdoor>.Retailer<Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<?>.Shop<?> innerTypeIsSubtype_withWildcards(
Mall<? extends Indoor>.Retailer<? extends Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> ownerTypeIsSubtype(
Outlet<Outdoor>.Shop<Electronics> shop) {
return isSubtype(shop);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<? extends Outdoor>.Shop<Electronics> ownerTypeIsSubtype_supertypeWithWildcard(
Outlet<Outdoor>.Shop<Electronics> shop) {
return isSubtype(shop);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<?>.Shop<Electronics> ownerTypeIsSubtype_withWildcards(
Outlet<? extends Outdoor>.Shop<Electronics> shop) {
return isSubtype(shop);
}
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> bothOwnerTypeAndInnerTypeAreSubtypes(
Outlet<Outdoor>.Retailer<Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<? super Outdoor>.Shop<? extends Electronics>
bothOwnerTypeAndInnerTypeAreSubtypes_supertypeWithWildcard(
Outlet<Outdoor>.Retailer<Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Mall<? super Outdoor>.Shop<? extends Electronics>
bothOwnerTypeAndInnerTypeAreSubtypes_withWildcards(
Outlet<Outdoor>.Retailer<Electronics> retailer) {
return isSubtype(retailer);
}
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> ownerTypeDoesNotMatch(
Mall<Indoor>.Shop<Electronics> shop) {
return notSubtype(shop);
}
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> ownerTypeDoesNotMatch_subtypeWithWildcard(
Mall<? extends Outdoor>.Shop<Electronics> shop) {
return notSubtype(shop);
}
@TestSubtype
public Mall<? extends Outdoor>.Shop<Electronics> ownerTypeDoesNotMatch_supertypeWithWildcard(
Mall<?>.Shop<Electronics> shop) {
return notSubtype(shop);
}
@TestSubtype
public Mall<Outdoor>.Retailer<Electronics> innerTypeDoesNotMatch(
Mall<Outdoor>.Shop<Grocery> shop) {
return notSubtype(shop);
}
@TestSubtype
public Mall<Outdoor>.Shop<Electronics> innerTypeDoesNotMatch_subtypeWithWildcard(
Mall<Outdoor>.Shop<? extends Electronics> shop) {
return notSubtype(shop);
}
@TestSubtype
public Mall<Outdoor>.Shop<? extends Electronics> innerTypeDoesNotMatch_supertypeWithWildcard(
Mall<Outdoor>.Shop<Grocery> shop) {
return notSubtype(shop);
}
@TestSubtype(suppressGetSubtype = true)
public ConsumerFacing<Electronics> supertypeIsNestedClass(
Mall<Indoor>.Retailer<Electronics> shop) {
return isSubtype(shop);
}
@TestSubtype
public ConsumerFacing<Grocery> nestedClassIsNotSupertypeDueToTypeParameter(
Mall<Indoor>.Shop<Electronics> shop) {
return notSubtype(shop);
}
@TestSubtype
public ConsumerFacing<Grocery> nestedClassIsNotSupertype(
Mall<Indoor>.Shop<Grocery> shop) {
return notSubtype(shop);
}
@TestSubtype(suppressGetSubtype = true)
public Comparator<Electronics> supertypeIsTopLevelClass(
Mall<Indoor>.Retailer<Electronics> shop) {
return isSubtype(shop);
}
@TestSubtype
public Comparator<Electronics> topLevelClassIsNotSupertypeDueToTypeParameter(
Mall<Indoor>.Retailer<Grocery> shop) {
return notSubtype(shop);
}
@TestSubtype
public Comparator<Electronics> topLevelClassIsNotSupertype(
Mall<Indoor>.Shop<Electronics> shop) {
return notSubtype(shop);
}
}
private static class WildcardSubtypingTests extends SubtypeTester {
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? extends T> supertypeWithWildcardUpperBound(List<T> list) {
return isSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? extends T> supertypeWithWildcardUpperBound_notMatch(List<String> list) {
return notSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? super T> supertypeWithWildcardULowerBound(List<T> list) {
return isSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? extends T> supertypeWithWildcardULowerBound_notMatch(List<String> list) {
return notSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<?> wildcardsMatchByUpperBound(List<? extends T> list) {
return isSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? extends T> wildCardsDoNotMatchByUpperBound(List<?> list) {
return notSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? super String> wildcardsMatchByLowerBound(
List<? super CharSequence> list) {
return isSubtype(list);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public <T> Iterable<? super CharSequence> wildCardsDoNotMatchByLowerBound(
List<? super String> list) {
return notSubtype(list);
}
// Can't test getSupertype() or getSubtype() because JDK reflection doesn't consider
// Foo<?> and Foo<? extends Bar> equal for class Foo<T extends Bar>
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseIterable<?> explicitTypeBoundIsSubtypeOfImplicitTypeBound(
UseIterable<? extends Iterable<?>> obj) {
return isSubtype(obj);
}
// Can't test getSupertype() or getSubtype() because JDK reflection doesn't consider
// Foo<?> and Foo<? extends Bar> equal for class Foo<T extends Bar>
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseIterable<? extends Iterable<?>> implicitTypeBoundIsSubtypeOfExplicitTypeBound(
UseIterable<?> obj) {
return isSubtype(obj);
}
// Can't test getSupertype() or getSubtype() because JDK reflection doesn't consider
// Foo<?> and Foo<? extends Bar> equal for class Foo<T extends Bar>
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseIterable<? extends Iterable<?>> omittedTypeBoundIsSubtypeOfExplicitTypeBound(
UseIterable<? extends CharSequence> obj) {
return isSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Enum<? extends Enum<?>> implicitlyBoundedEnumIsSubtypeOfExplicitlyBoundedEnum(
Enum<?> obj) {
return isSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public Enum<?> explicitlyBoundedEnumIsSubtypeOfImplicitlyBoundedEnum(
Enum<? extends Enum<?>> obj) {
return isSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseSerializableIterable<? extends Serializable>
implicitTypeBoundIsSubtypeOfPartialExplicitTypeBound(UseSerializableIterable<?> obj) {
return isSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseSerializableIterable<?> partialImplicitTypeBoundIsSubtypeOfImplicitTypeBound(
UseSerializableIterable<? extends Iterable<?>> obj) {
return isSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseSerializableIterable<? extends CharSequence>
implicitTypeBoundIsNotSubtypeOfDifferentTypeBound(UseSerializableIterable<?> obj) {
return notSubtype(obj);
}
@TestSubtype(suppressGetSupertype = true, suppressGetSubtype = true)
public UseSerializableIterable<? extends CharSequence>
partialExplicitTypeBoundIsNotSubtypeOfDifferentTypeBound(
UseSerializableIterable<? extends Serializable> obj) {
return notSubtype(obj);
}
}
// TODO(benyu): migrate all subtyping tests from TypeTokenTest to this class using SubtypeTester.
private interface Outdoor {}
private interface Indoor {}
private interface Grocery {}
private interface Electronics {}
private interface ConsumerFacing<T> {}
private static class Mall<T> {
class Shop<ProductT> {}
abstract class Retailer<ProductT> extends Shop<ProductT>
implements Comparator<ProductT>, ConsumerFacing<ProductT> {}
}
private static class Outlet<T> extends Mall<T> {}
private static interface UseIterable<T extends Iterable<?>> {}
private static interface UseSerializableIterable<T extends Serializable&Iterable<?>> {}
}