/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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 org.jboss.weld.tests.unit.reflection.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Type;
import java.util.List;
import javax.enterprise.util.TypeLiteral;
import org.junit.Assert;
import org.jboss.weld.resolution.AssignabilityRules;
import org.jboss.weld.resolution.EventTypeAssignabilityRules;
import org.jboss.weld.util.reflection.GenericArrayTypeImpl;
import org.junit.Test;
@SuppressWarnings("serial")
public class EventTypeAssignabilityTest {
protected AssignabilityRules getRules() {
return EventTypeAssignabilityRules.instance();
}
@Test
public <E> void testTypeVariableMatchesFoo() throws Exception {
Type fooType = Foo.class;
Type variableType = new TypeLiteral<E>(){}.getType();
Assert.assertTrue("E should be assignable from Foo", getRules().matches(variableType, fooType));
}
@Test
public <E> void testVariableFooMatchesStringFoo() throws Exception {
Type stringFooType = new TypeLiteral<Foo<String>>(){}.getType();
Type variableFooType = new TypeLiteral<Foo<E>>(){}.getType();
Assert.assertTrue("Foo<E> should be assignable from Foo<String>", getRules().matches(variableFooType, stringFooType));
}
@Test
public <E> void testVariableFooArrayMatchesStringFooArray() throws Exception {
Type stringFooArrayType = new TypeLiteral<Foo<String>[]>(){}.getType();
Type variableFooArrayType = new TypeLiteral<Foo<E>[]>(){}.getType();
Assert.assertTrue("Foo<E>[] should be assignable from Foo<String>[]", getRules().matches(variableFooArrayType, stringFooArrayType));
}
@Test
public <F extends Number> void testParameterizedBeanWithBoundedVariableTypeParameter() throws Exception {
Assert.assertTrue("Foo<F extends Number> should be assignable to Foo",
getRules().matches(
Foo.class,
new TypeLiteral<Foo<F>>() { }.getType()));
}
@Test
public void testFooArrayMatchesItself() throws Exception {
Type clazz = Foo[].class;
Type genericArrayType = new TypeLiteral<Foo[]>(){}.getType();
Assert.assertTrue("array should match itself", getRules().matches(clazz, clazz));
Assert.assertTrue("array should match itself", getRules().matches(genericArrayType, genericArrayType));
Assert.assertTrue("array should match itself", getRules().matches(genericArrayType, clazz));
Assert.assertTrue("array should match itself", getRules().matches(clazz, genericArrayType));
}
@Test
public void testWildcardMatchesParameterizedType() {
Type eventType = new TypeLiteral<Foo<List<String>>>() {}.getType();
Type observerType1 = new TypeLiteral<Foo<? extends List>>() {}.getType();
Type observerType2 = new TypeLiteral<Foo<?>>() {}.getType();
Type observerType3 = new TypeLiteral<Foo<? extends List<String>>>() {}.getType();
assertTrue("Foo<? extends List> should be assignable from Foo<List<String>>", getRules().matches(observerType1, eventType));
assertTrue("Foo<?> should be assignable from Foo<List<String>>", getRules().matches(observerType2, eventType));
assertTrue("Foo<? extends List<String> should be assignable from Foo<List<String>>", getRules().matches(observerType3, eventType));
}
@Test
public void testParameterizedTypes() {
Type observerType = new TypeLiteral<Foo<Number>>() {}.getType();
Type eventType1 = new TypeLiteral<Foo<Number>>() {}.getType();
Type eventType2 = new TypeLiteral<Foo<Integer>>() {}.getType();
assertTrue("Foo<Number> should be assignable to Foo<Number>", getRules().matches(observerType, eventType1));
assertFalse("Foo<Integer> should not be assignable to Foo<Number>", getRules().matches(observerType, eventType2));
}
@Test
public void testArrayCovariance1() {
Type type1 = new Number[0].getClass();
Type type2 = new Integer[0].getClass();
assertTrue(getRules().matches(type1, type2));
}
@Test
public void testArrayCovariance2() {
Type type1 = new GenericArrayTypeImpl(new TypeLiteral<List<?>>() {
}.getType());
Type type2 = new List[0].getClass();
assertTrue(getRules().matches(type2, type1));
}
@Test
public void testBoxingNotAppliedOnArrays() {
Type type1 = new int[0].getClass();
Type type2 = new Integer[0].getClass();
assertFalse(getRules().matches(type1, type2));
}
@Test
public void testWildcardFooArrayMatchesStringFooArray() throws Exception {
Type stringFooArrayType = new TypeLiteral<Foo<String>[]>() {
}.getType();
Type wildcardFooArrayType = new TypeLiteral<Foo<?>[]>() {
}.getType();
Assert.assertTrue("Foo<?>[] should not be assignable from Foo<String>[]", getRules().matches(wildcardFooArrayType, stringFooArrayType));
}
@Test
public void testIntegerFooMatchesItself() throws Exception {
Type type = new TypeLiteral<Foo<Integer>>() {
}.getType();
Assert.assertTrue("type should match itself", getRules().matches(type, type));
}
@Test
public void testIntegerFooDoesNotMatchStringFoo() throws Exception {
Type type1 = new TypeLiteral<Foo<Integer>>() {
}.getType();
Type type2 = new TypeLiteral<Foo<String>>() {
}.getType();
Assert.assertFalse("Foo<Integer> should not match Foo<String>", getRules().matches(type1, type2));
}
@Test
public void testFooMatchesItself() throws Exception {
Type type = Foo.class;
Assert.assertTrue("type should match itself", getRules().matches(type, type));
}
@Test
public void testParameterizedArrayDoesNotMatchComponentOfArray() throws Exception {
Type arrayType = new TypeLiteral<Foo<String>[]>() {
}.getType();
Type componentType = new TypeLiteral<Foo<String>>() {
}.getType();
Assert.assertFalse("array type should not match its component type", getRules().matches(arrayType, componentType));
}
@Test
public void testParameterizedArrayMatches() throws Exception {
Type type = new TypeLiteral<Foo<Integer>[]>() {
}.getType();
Assert.assertTrue("type should match itself", getRules().matches(type, type));
}
@Test
public void testArraysDontMatch() throws Exception {
Type type1 = new TypeLiteral<Foo<Integer>[]>() {
}.getType();
Type type2 = new TypeLiteral<Foo<String>[]>() {
}.getType();
Assert.assertFalse("Foo<Integer>[] should not match Foo<String>[]", getRules().matches(type1, type2));
}
@Test
public void testWildcardFooMatchesStringFoo() throws Exception {
Type stringFooType = new TypeLiteral<Foo<String>>() {
}.getType();
Type wildcardFooType = new TypeLiteral<Foo<?>>() {
}.getType();
Assert.assertTrue("Foo<?> should be assignable from Foo<String>", getRules().matches(wildcardFooType, stringFooType));
}
@Test
public void testStringFooArrayDoesNotMatchWildcardFooArray() throws Exception {
Type stringFooArrayType = new TypeLiteral<Foo<String>[]>() {
}.getType();
Type wildcardFooArrayType = new TypeLiteral<Foo<?>[]>() {
}.getType();
Assert.assertFalse("Foo<String>[] should not be assignable from Foo<?>[]", getRules().matches(stringFooArrayType, wildcardFooArrayType));
}
@Test
public void testRawRequiredTypeMatchesParameterizedBeanWithObjectTypeParameter() throws Exception {
Assert.assertTrue("Foo<Object> should be assignable to Foo", getRules().matches(Foo.class, new TypeLiteral<Foo<Object>>() {
}.getType()));
}
@Test
public <T, S extends Integer> void testArrays() {
Assert.assertTrue("int[][] should be assignable to int[][]", getRules().matches(new int[0][].getClass(), new int[0][].getClass()));
Assert.assertTrue("Integer[][] should be assignable to Integer[][]", getRules().matches(new Integer[0][].getClass(), new Integer[0][].getClass()));
Assert.assertTrue("Integer[][] should be assignable to Number[][]", getRules().matches(new Number[0][].getClass(), new Integer[0][].getClass()));
Assert.assertTrue("Integer[][] should be assignable to T[]", getRules().matches(new TypeLiteral<T[]>() {}.getType(), new Integer[0][].getClass()));
Assert.assertTrue("Integer[][] should be assignable to T[][]", getRules().matches(new TypeLiteral<T[][]>() {}.getType(), new Integer[0][].getClass()));
Assert.assertFalse("Integer[][] should not be assignable to S[] where S extends Integer", getRules().matches(new TypeLiteral<S[]>() {}.getType(), new Integer[0][].getClass()));
Assert.assertTrue("Integer[][] should be assignable to S[][] where S extends Integer", getRules().matches(new TypeLiteral<S[][]>() {}.getType(), new Integer[0][].getClass()));
Assert.assertFalse("Number[][] should not be assignable to S[][] where S extends Integer", getRules().matches(new TypeLiteral<S[][]>() {}.getType(), new Number[0][].getClass()));
}
@Test
public void testArrayBoxing() {
/*
* This is not explicitly said in the CDI spec however Java SE does not support array boxing so neither should CDI.
*/
Assert.assertFalse("Integer[] should not be assignable to int[]", getRules().matches(new int[0].getClass(), new Integer[0].getClass()));
Assert.assertFalse("int[] should not be assignable to Integer[]", getRules().matches(new Integer[0].getClass(), new int[0].getClass()));
}
@Test
public <T1 extends Number, T2 extends T1> void testTypeVariableWithTypeVariableBound() {
Assert.assertTrue("Number should be assignable to T2 extends T1 extends Number", getRules().matches(new TypeLiteral<T2>() {}.getType(), Number.class));
Assert.assertFalse("Number should not be assignable to T2 extends T1 extends Runnable", getRules().matches(new TypeLiteral<T2>() {}.getType(), Runnable.class));
}
@Test
public <T1 extends Number, T2 extends T1> void testWildcardWithTypeVariableBound() {
Assert.assertTrue("List<Number> should be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Number>>() {}.getType()));
Assert.assertTrue("List<Integer> should be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Integer>>() {}.getType()));
Assert.assertFalse("List<Object> should not be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Object>>() {}.getType()));
Assert.assertTrue("List<Number> should be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Number>>() {}.getType()));
Assert.assertFalse("List<Integer> should not be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Integer>>() {}.getType()));
Assert.assertTrue("List<Object> should be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Object>>() {}.getType()));
}
}