/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import org.junit.*;
import org.junit.runners.*;
import static org.junit.Assert.*;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public final class CascadingWithGenericsTest
{
static class Foo
{
Callable<?> returnTypeWithWildcard() { return null; }
<RT extends Baz> RT returnTypeWithBoundedTypeVariable() { return null; }
@SuppressWarnings("UnusedParameters")
<N extends Number> N genericMethodWithNonMockableBoundedTypeVariableAndClassParameter(Class<N> c) { return null; }
@SuppressWarnings("UnusedParameters")
<RT extends Bar> RT genericMethodWithBoundedTypeVariableAndClassParameter(Class<RT> cl) { return null; }
<T1 extends Baz, T2 extends List<? extends Number>> Pair<T1, T2> returnTypeWithMultipleTypeVariables()
{ return null; }
Callable<Baz> returnGenericTypeWithTypeArgument() { return null; }
Bar bar() { return null; }
}
@SuppressWarnings("unused")
public interface Pair<K, V> {}
static class Bar
{
Bar() { throw new RuntimeException(); }
int doSomething() { return 1; }
static String staticMethod() { return "notMocked"; }
}
static final class SubBar extends Bar {}
public interface Baz { Date getDate(); }
@Test
public void cascadeOneLevelDuringReplay(@Mocked Foo foo)
{
assertNotNull(foo.returnTypeWithWildcard());
assertNotNull(foo.returnTypeWithBoundedTypeVariable());
Pair<Baz, List<Integer>> x = foo.returnTypeWithMultipleTypeVariables();
assertNotNull(x);
}
@Test
public void cascadeOneLevelDuringRecord(@Mocked Callable<String> action, @Mocked Foo mockFoo)
{
Foo foo = new Foo();
Callable<?> cascaded = foo.returnTypeWithWildcard();
assertSame(action, cascaded);
}
@Test
public void cascadeTwoLevelsDuringRecord(@Mocked final Foo mockFoo)
{
final Date now = new Date();
new Expectations() {{
mockFoo.returnTypeWithBoundedTypeVariable().getDate(); result = now;
}};
Foo foo = new Foo();
assertSame(now, foo.returnTypeWithBoundedTypeVariable().getDate());
}
static class GenericFoo<T, U extends Bar>
{
T returnTypeWithUnboundedTypeVariable() { return null; }
U returnTypeWithBoundedTypeVariable() { return null; }
}
@Test
public void cascadeGenericMethods(@Mocked GenericFoo<Baz, SubBar> foo)
{
Baz t = foo.returnTypeWithUnboundedTypeVariable();
assertNotNull(t);
SubBar u = foo.returnTypeWithBoundedTypeVariable();
assertNotNull(u);
}
static class A { B<?> getB() { return null; } }
static class B<T> { T getValue() { return null; } }
@Test
public void cascadeOnMethodReturningAParameterizedClassWithAGenericMethod(@Injectable final A a)
{
new Expectations() {{
a.getB().getValue(); result = "test";
}};
assertEquals("test", a.getB().getValue());
}
@SuppressWarnings("unused") static class C<T> {}
static class D extends C<Foo> { <T extends Bar> T doSomething() { return null; } }
@Test
public void cascadeFromGenericMethodUsingTypeParameterOfSameNameAsTypeParameterFromBaseClass(@Mocked D mock)
{
Bar cascaded = mock.doSomething();
assertNotNull(cascaded);
}
static class Factory
{
static <T extends Bar> T bar() { return null; }
static <T extends Bar> T bar(@SuppressWarnings("UnusedParameters") Class<T> c) { return null; }
WithStaticInit staticInit() { return null; }
}
static class WithStaticInit
{
static final Bar T = Factory.bar();
static final SubBar S = Factory.bar(SubBar.class);
}
@Test
public void cascadeDuringStaticInitializationOfCascadedClass(@Mocked Factory mock)
{
assertNotNull(mock.staticInit());
assertNotNull(WithStaticInit.T);
assertNotNull(WithStaticInit.S);
}
@Test
public void cascadeFromGenericMethodWhereConcreteReturnTypeIsGivenByClassParameterButIsNotMockable(@Mocked Foo foo)
{
Integer n = foo.genericMethodWithNonMockableBoundedTypeVariableAndClassParameter(Integer.class);
assertNotNull(n);
}
@Test
public void cascadeFromGenericMethodWhereConcreteReturnTypeIsGivenByClassParameter(@Mocked Foo foo)
{
SubBar subBar = foo.genericMethodWithBoundedTypeVariableAndClassParameter(SubBar.class);
assertNotNull(subBar);
}
@Test
public void cascadeFromGenericMethodWhoseReturnTypeComesFromParameterOnOwnerType(
@Mocked Foo foo, @Mocked final Baz cascadedBaz) throws Exception
{
final Date date = new Date();
new Expectations() {{ cascadedBaz.getDate(); result = date; }};
Callable<Baz> callable = foo.returnGenericTypeWithTypeArgument();
Baz baz = callable.call();
assertSame(cascadedBaz, baz);
assertSame(date, baz.getDate());
}
public interface GenericInterface<T> { <S extends T> S save(S entity); }
public interface ConcreteInterface extends GenericInterface<Foo> {}
@Test
public void cascadingFromGenericMethodWhoseTypeParameterExtendsAnother(@Mocked ConcreteInterface mock)
{
Foo value = new Foo();
Foo saved = mock.save(value);
assertNotNull(saved);
assertNotSame(value, saved);
}
public interface GenericInterfaceWithBoundedTypeParameter<B extends Serializable> { B get(int id); }
@Test
public <T extends Serializable> void cascadeFromMethodReturningATypeVariable(
@Mocked final GenericInterfaceWithBoundedTypeParameter<T> mock)
{
new Expectations() {{
mock.get(1); result = "test";
mock.get(2); result = null;
}};
assertEquals("test", mock.get(1));
assertNull(mock.get(2));
}
static class TypeWithUnusedTypeParameterInGenericMethod { @SuppressWarnings("unused") <U> Foo foo() {return null;} }
@Test
public void cascadeFromMethodHavingUnusedTypeParameter(@Mocked TypeWithUnusedTypeParameterInGenericMethod mock)
{
Foo foo = mock.foo();
Bar bar = foo.bar();
assertNotNull(bar);
}
@Test
public void cascadeFromGenericMethodWhoseReturnTypeResolvesToAnotherGenericType(@Mocked B<C<?>> mock)
{
C<?> c = mock.getValue();
assertNotNull(c);
}
public interface BaseGenericInterface<B> { B genericMethod(); }
public interface GenericSubInterface<S> extends BaseGenericInterface<S> {}
public interface NonGenericInterface extends GenericSubInterface<Bar> {}
@Test
public void cascadeFromGenericMethodDefinedTwoLevelsDeepInInheritanceHierarchy(@Mocked NonGenericInterface mock) {
Bar cascadedResult = mock.genericMethod();
assertNotNull(cascadedResult);
}
interface NonPublicInterfaceWithGenericMethod { <T extends Runnable> T doSomething(); }
@Test
public void cascadeFromGenericMethodOfNonPublicInterface(@Mocked NonPublicInterfaceWithGenericMethod mock) {
Runnable result = mock.doSomething();
assertNotNull(result);
}
public interface FactoryInterface { <T> T genericWithClass(Class<T> type); }
@Test
public void cascadeFromGenericMethodWithClassParameterOfMockedInterface(@Mocked FactoryInterface mock)
{
Foo cascaded = mock.genericWithClass(Foo.class);
assertNotNull(cascaded);
}
@SuppressWarnings("unused") static class Outer<T> { class Inner {} }
static class Client { Outer<String>.Inner doSomething() { return null; } }
@Test
public void cascadeFromMethodReturningInnerInstanceOfGenericClass(@Mocked final Client mock)
{
final Outer.Inner innerInstance = new Outer().new Inner();
new Expectations() {{
mock.doSomething();
result = innerInstance;
}};
assertSame(innerInstance, mock.doSomething());
}
static class SubB<T> extends B<T> {}
static class ClassWithMethodReturningGenericClassInstance { SubB<C> doSomething() { return null; } }
@Test
public void cascadeFromMethodReturningInstanceOfGenericSubclassThenFromGenericMethodOfGenericBaseClass(
@Mocked ClassWithMethodReturningGenericClassInstance mock)
{
SubB<C> cascade1 = mock.doSomething();
C cascade2 = cascade1.getValue();
assertNotNull(cascade2);
}
public interface InterfaceWithGenericMethod<T> { @SuppressWarnings("unused") T genericMethod(); }
static class BaseClass { public Bar genericMethod() { return null; } }
static class SubClass extends BaseClass implements InterfaceWithGenericMethod<Bar> {}
@Test
public void cascadeFromGenericInterfaceMethodImplementedInBaseClassOfMockedSubClass(@Mocked SubClass mock)
{
Bar cascaded = mock.genericMethod();
assertNotNull(cascaded);
}
}