/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
public final class MockUpForGenericsTest
{
// Mock-ups for generic classes/methods ////////////////////////////////////////////////////////////////////////////
public static final class Collaborator
{
public <N extends Number> N genericMethod(@SuppressWarnings("UnusedParameters") N n) { return null; }
}
@Test
public void mockGenericMethod()
{
new MockUp<Collaborator>() {
@Mock <T extends Number> T genericMethod(T t) { return t; }
// This also works (same erasure):
// @Mock Number genericMethod(Number t) { return t; }
};
Integer n = new Collaborator().genericMethod(123);
assertEquals(123, n.intValue());
Long l = new Collaborator().genericMethod(45L);
assertEquals(45L, l.longValue());
Short s = new Collaborator().genericMethod((short) 6);
assertEquals(6, s.shortValue());
Double d = new Collaborator().genericMethod(0.5);
assertEquals(0.5, d, 0);
}
@SuppressWarnings("UnusedParameters")
public static final class GenericClass<T1, T2>
{
public void aMethod(T1 t) { throw new RuntimeException("t=" + t); }
public int anotherMethod(T1 t, int i, T2 p) { return 2 * i; }
public int anotherMethod(Integer t, int i, String p) { return -2 * i; }
}
@Test
public void mockGenericClassWithUnspecifiedTypeArguments()
{
new MockUp<GenericClass<?, ?>>() {
@Mock
void aMethod(Object o)
{
StringBuilder s = (StringBuilder) o;
s.setLength(0);
s.append("mock");
s.toString();
}
@Mock
int anotherMethod(Object o, int i, Object list)
{
assertTrue(o instanceof StringBuilder);
//noinspection unchecked
assertEquals(0, ((Collection<String>) list).size());
return -i;
}
};
StringBuilder s = new StringBuilder("test");
GenericClass<StringBuilder, List<String>> g = new GenericClass<StringBuilder, List<String>>();
g.aMethod(s);
int r1 = g.anotherMethod(new StringBuilder("test"), 58, Collections.<String>emptyList());
int r2 = g.anotherMethod(123, 65, "abc");
assertEquals("mock", s.toString());
assertEquals(-58, r1);
assertEquals(-130, r2);
}
@Test
public void mockBothGenericAndNonGenericMethodsInGenericClass()
{
new MockUp<GenericClass<String, Boolean>>() {
@Mock int anotherMethod(Integer t, int i, String p) { return 2; }
@Mock int anotherMethod(String t, int i, Boolean p) { return 1; }
};
GenericClass<String, Boolean> o = new GenericClass<String, Boolean>();
assertEquals(1, o.anotherMethod("generic", 1, true));
assertEquals(2, o.anotherMethod(123, 2, "non generic"));
}
static class GenericBaseClass<T, U> { public U find(@SuppressWarnings("UnusedParameters") T id) { return null; } }
@Test
public void mockGenericMethodWithMockMethodHavingParameterTypesMatchingTypeArguments()
{
new MockUp<GenericBaseClass<String, Integer>>() {
@Mock
Integer find(String id) { return id.hashCode(); }
};
int i = new GenericBaseClass<String, Integer>().find("test");
assertEquals("test".hashCode(), i);
}
@Test
public void cannotCallGenericMethodWhenSomeMockMethodExpectsDifferentTypes()
{
new MockUp<GenericBaseClass<String, Integer>>() { @Mock Integer find(String id) { return 1; } };
try {
new GenericBaseClass<Integer, String>().find(1);
fail();
}
catch (IllegalArgumentException e) {
assertTrue(e.getMessage().startsWith("Failure to invoke method: "));
}
}
static class NonGenericSuperclass extends GenericBaseClass<Integer, String> {}
final class NonGenericSubclass extends NonGenericSuperclass {}
@Test
public void mockGenericMethodFromInstantiationOfNonGenericSubclass()
{
new MockUp<NonGenericSubclass>() {
@Mock
String find(Integer id) { return "mocked" + id; }
};
String s = new NonGenericSubclass().find(1);
assertEquals("mocked1", s);
}
static class GenericSuperclass<I> extends GenericBaseClass<I, String> {}
final class AnotherNonGenericSubclass extends GenericSuperclass<Integer> {}
@Test
public void mockGenericMethodFromInstantiationOfNonGenericSubclassWhichExtendsAGenericIntermediateSuperclass()
{
new MockUp<AnotherNonGenericSubclass>() {
@Mock
String find(Integer id) { return "mocked" + id; }
};
String s = new AnotherNonGenericSubclass().find(1);
assertEquals("mocked1", s);
}
@SuppressWarnings("UnusedParameters")
public static class NonGenericClassWithGenericMethods
{
public static <T> T staticMethod(Class<T> cls, String s) { throw new RuntimeException(); }
public <C> void instanceMethod(Class<C> cls, String s) { throw new RuntimeException(); }
public final <N extends Number> void instanceMethod(Class<N> cls) { throw new RuntimeException(); }
}
@Test
public void mockGenericMethodsOfNonGenericClass()
{
new MockUp<NonGenericClassWithGenericMethods>() {
@Mock <T> T staticMethod(Class<T> cls, String s) { return null; }
@Mock <C> void instanceMethod(Class<C> cls, String s) {}
@Mock void instanceMethod(Class<?> cls) {}
};
new NonGenericClassWithGenericMethods().instanceMethod(Integer.class);
NonGenericClassWithGenericMethods.staticMethod(Collaborator.class, "test1");
new NonGenericClassWithGenericMethods().instanceMethod(Byte.class, "test2");
}
// Mock-ups for generic interfaces /////////////////////////////////////////////////////////////////////////////////
public interface GenericInterface<T> { void method(T t); }
@Test
public void mockGenericInterfaceMethodWithMockMethodHavingParameterOfTypeObject()
{
GenericInterface<Boolean> mock = new MockUp<GenericInterface<Boolean>>() {
@Mock
void method(Object b) { assertTrue((Boolean) b); }
}.getMockInstance();
mock.method(true);
}
public interface NonGenericSubInterface extends GenericInterface<Long> {}
@Test
public void mockMethodOfSubInterfaceWithGenericTypeArgument()
{
NonGenericSubInterface mock = new MockUp<NonGenericSubInterface>() {
@Mock void method(Long l) { assertTrue(l > 0); }
}.getMockInstance();
mock.method(123L);
}
@Test
public void mockGenericInterfaceMethod()
{
Comparable<Integer> cmp = new MockUp<Comparable<Integer>>() {
@Mock
int compareTo(Integer i) { assertEquals(123, i.intValue()); return 2; }
}.getMockInstance();
assertEquals(2, cmp.compareTo(123));
}
}