/* * 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 org.junit.rules.*; import static org.junit.Assert.*; @SuppressWarnings("unused") public final class DelegateTest { @Rule public final ExpectedException thrown = ExpectedException.none(); static class Collaborator { Collaborator() {} Collaborator(int i) {} int getValue() { return -1; } String doSomething(boolean b, int[] i, String s) { return s + b + i[0]; } static boolean staticMethod() { return true; } static boolean staticMethod(int i) { return i > 0; } protected native long nativeMethod(boolean b); final char finalMethod() { return 's'; } void addElements(List<String> elements) { elements.add("one element"); } Foo getFoo() { return null; } } static final class Foo { int doSomething() { return 1; } } @Test public void resultFromDelegate(@Mocked final Collaborator collaborator) { final boolean bExpected = true; final int[] iExpected = new int[0]; final String sExpected = "test"; new Expectations() {{ collaborator.getValue(); result = new Delegate() { int getValue() { return 2; } }; collaborator.doSomething(bExpected, iExpected, sExpected); result = new Delegate() { String doSomething(boolean b, int[] i, String s) { assertEquals(bExpected, b); assertArrayEquals(iExpected, i); assertEquals(sExpected, s); return ""; } }; }}; assertEquals(2, collaborator.getValue()); assertEquals("", collaborator.doSomething(bExpected, iExpected, sExpected)); } @Test public void consecutiveResultsThroughDelegatesHavingDifferentValues(@Mocked final Collaborator mock) { new Expectations() {{ mock.getValue(); result = new Delegate() { int getValue() { return 1; } }; result = new Delegate() { int getValue() { return 2; } }; }}; Collaborator collaborator = new Collaborator(); assertEquals(1, collaborator.getValue()); assertEquals(2, collaborator.getValue()); } @Test public void consecutiveReturnValuesThroughDelegatesUsingSingleReturnsWithVarargs( @Mocked final Collaborator collaborator) { final int[] array = {1, 2}; new Expectations() {{ collaborator.doSomething(true, array, ""); returns( new Delegate() { String execute(boolean b, int[] i, String s) { assertEquals(1, i[0]); return "a"; } }, new Delegate() { String execute(boolean b, int[] i, String s) { assertEquals(2, i[0]); return "b"; } }); }}; assertEquals("a", collaborator.doSomething(true, array, "")); array[0] = 2; assertEquals("b", collaborator.doSomething(true, array, "")); } @Test public void resultWithMultipleReturnValuesThroughSingleDelegate(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.getValue(); result = new Delegate() { int i = 1; int getValue() { return i++; } }; }}; assertEquals(1, collaborator.getValue()); assertEquals(2, collaborator.getValue()); assertEquals(3, collaborator.getValue()); } @Test public void constructorDelegateWithSingleMethod(@Mocked Collaborator mock) { final ConstructorDelegate delegate = new ConstructorDelegate(); new Expectations() {{ new Collaborator(anyInt); result = delegate; }}; new Collaborator(4); assertTrue(delegate.capturedArgument > 0); } static class ConstructorDelegate implements Delegate<Void> { int capturedArgument; void delegate(int i) { capturedArgument = i; } } @Test public void constructorDelegateWithMultipleMethods(@Mocked Collaborator mock) { new Expectations() {{ new Collaborator(anyInt); result = new Delegate() { void init(int i) { if (i < 0) throw new IllegalArgumentException(); } private void anotherMethod() {} }; }}; new Collaborator(123); try { new Collaborator(-123); fail(); } catch (IllegalArgumentException ignore) {} } @Test public void attemptToUseConstructorDelegateWithPrivateMethodsOnly(@Mocked Collaborator mock) { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("No non-private instance method found"); new Expectations() {{ new Collaborator(); result = new Delegate() { private void delegate() {} private void anotherMethod() {} }; }}; } @Test public void delegateForStaticMethod(@Mocked Collaborator unused) { new Expectations() {{ Collaborator.staticMethod(); result = new Delegate() { boolean staticMethod() { return false; } }; }}; assertFalse(Collaborator.staticMethod()); } @Test public void delegateWithStaticMethod(@Mocked Collaborator mock) { new Expectations() {{ Collaborator.staticMethod(anyInt); result = StaticDelegate.create(); }}; assertTrue(Collaborator.staticMethod(34)); } static final class StaticDelegate implements Delegate<Object> { static StaticDelegate create() { return new StaticDelegate(); } boolean delegateMethod(int i) { assertEquals(34, i); return true; } } @Test public void delegateForNativeMethod(@Mocked final Collaborator mock) { new Expectations() {{ mock.nativeMethod(anyBoolean); result = new Delegate() { Long nativeMethod(boolean b) { assertTrue(b); return 0L; } }; }}; assertEquals(0L, new Collaborator().nativeMethod(true)); } @Test public void delegateForFinalMethod(@Mocked final Collaborator mock) { new Expectations() {{ mock.finalMethod(); result = new Delegate() { char finalMethod() { return 'M'; } }; }}; assertEquals('M', new Collaborator().finalMethod()); } @Test public void delegateForMethodWithCompatibleButDistinctParameterType(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.addElements(this.<List<String>>withNotNull()); result = new Delegate() { void delegate(Collection<String> elements) { elements.add("test"); } }; }}; List<String> elements = new ArrayList<String>(); new Collaborator().addElements(elements); assertTrue(elements.contains("test")); } @Test public void delegateReceivingNullArguments(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.doSomething(true, null, null); result = new Delegate() { String delegate(boolean b, int[] i, String s) { //noinspection ImplicitArrayToString return b + " " + i + " " + s; } }; }}; String s = new Collaborator().doSomething(true, null, null); assertEquals("true null null", s); } @Test public void delegateWithTwoMethods(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.doSomething(true, null, "str"); result = new Delegate() { private String someOther() { return ""; } void doSomething(boolean b, int[] i, String s) {} }; }}; assertNull(collaborator.doSomething(true, null, "str")); } @Test public void delegateWithSingleMethodHavingADifferentName(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.doSomething(true, null, "str"); result = new Delegate() { void onReplay(boolean b, int[] i, String s) { assertTrue(b); assertNull(i); assertEquals("str", s); } }; }}; assertNull(new Collaborator().doSomething(true, null, "str")); } @Test public void delegateWithSingleMethodHavingNoParameters(@Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.doSomething(anyBoolean, null, null); result = new Delegate() { String onReplay() { return "action"; } }; }}; assertEquals("action", new Collaborator().doSomething(true, null, null)); } @Test public void delegateWithSingleMethodHavingNoParametersExceptForInvocationContext( @Mocked final Collaborator collaborator) { new Expectations() {{ collaborator.doSomething(anyBoolean, null, null); result = new Delegate() { void doSomething(Invocation inv) { assertEquals(1, inv.getInvocationCount()); } }; }}; assertNull(new Collaborator().doSomething(false, new int[] {1, 2}, "test")); } @Test public void delegateWithOneMethodHavingDifferentParameters(@Mocked final Collaborator collaborator) { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("delegate("); new Expectations() {{ collaborator.doSomething(true, null, "str"); result = new Delegate() { void delegate(boolean b, String s) {} }; }}; collaborator.doSomething(true, null, "str"); } @Test public void delegateWithTwoNonPrivateMethods(@Mocked final Collaborator collaborator) { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("More than one candidate delegate method found: "); thrown.expectMessage("someOther()"); thrown.expectMessage("doSomethingElse(boolean,int[],String)"); new Expectations() {{ collaborator.doSomething(true, null, "str"); result = new Delegate() { String someOther() { return ""; } void doSomethingElse(boolean b, int[] i, String s) {} }; }}; } @Test public void delegateCausingConcurrentMockInvocation(@Mocked final Collaborator mock) { final Collaborator collaborator = new Collaborator(); final Thread t = new Thread(new Runnable() { @Override public void run() { collaborator.doSomething(false, null, ""); } }); new Expectations() {{ mock.getValue(); times = 1; result = new Delegate() { int executeInAnotherThread() throws Exception { t.start(); t.join(); return 1; } }; }}; assertEquals(1, collaborator.getValue()); } @Test public void delegateWhichCallsTheSameMockedMethod(@Mocked final Collaborator mock) { new Expectations() {{ mock.getValue(); result = new Delegate() { int count; // Would result in a StackOverflowError without a termination condition. int delegate() { return count++ > 1 ? 123 : 1 + mock.getValue(); } }; }}; assertEquals(125, mock.getValue()); } @Test public void delegateWhichCallsAnotherMockedMethod_fullMocking(@Mocked final Collaborator mock) { new Expectations() {{ mock.getValue(); result = new Delegate() { int delegate() { return mock.finalMethod(); } }; mock.finalMethod(); result = 'A'; }}; assertEquals('A', mock.getValue()); } @Test public void delegateWhichCallsAnotherMockedMethod_partialMockingOfClass() { final Collaborator collaborator = new Collaborator(); new Expectations(Collaborator.class) {{ Collaborator.staticMethod(); result = false; collaborator.getValue(); result = new Delegate() { int delegate() { return Collaborator.staticMethod() ? 1 : collaborator.finalMethod(); } }; collaborator.finalMethod(); result = 'A'; }}; assertEquals('A', collaborator.getValue()); } @Test public void delegateWhichCallsAnotherMockedMethod_partialMockingOfInstance() { final Collaborator collaborator = new Collaborator(); new Expectations(collaborator) {{ collaborator.getValue(); result = new Delegate() { int delegate() { return collaborator.finalMethod(); } }; collaborator.finalMethod(); result = 'A'; }}; assertEquals('A', collaborator.getValue()); } @Test public void delegateWhichCallsAnotherMockedMethod_injectableMocking(@Injectable final Collaborator mock) { new Expectations() {{ mock.getValue(); result = new Delegate() { int delegate() { return mock.finalMethod(); } }; mock.finalMethod(); result = 'A'; }}; assertEquals('A', mock.getValue()); } @Test public void delegateWhichCallsAnotherMockedMethodProducingACascadedInstance(@Mocked final Collaborator mock) { new Expectations() {{ mock.getFoo().doSomething(); result = 123; mock.getValue(); result = new Delegate() { int delegate() { return mock.getFoo().doSomething(); } }; }}; assertEquals(123, mock.getFoo().doSomething()); assertEquals(123, mock.getValue()); } @Test public void delegateCallingMockedMethodLaterVerified( @Mocked final Collaborator collaborator, @Mocked final Runnable action) { new Expectations() {{ collaborator.getFoo(); result = new Delegate() { void delegate() { action.run(); } }; }}; collaborator.getFoo(); new Verifications() {{ action.run(); }}; } }