/* * 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 static org.junit.Assert.*; public final class DelegateInvocationProceedTest { public static class BaseClassToBeMocked { protected String name; public final String getName() { return name; } public final int baseMethod(int i) { return i + 1; } protected int methodToBeMocked(int i) throws IOException { return i; } } public static class ClassToBeMocked extends BaseClassToBeMocked { public ClassToBeMocked() { name = ""; } public ClassToBeMocked(String name) { this.name = name; } public boolean methodToBeMocked() { return true; } @Override protected int methodToBeMocked(int i) throws IOException { return super.methodToBeMocked(i); } int methodToBeMocked(int i, Object... args) { int result = i; for (Object arg : args) { if (arg != null) result++; } return result; } String anotherMethodToBeMocked(String s, boolean b, List<Integer> ints) { return (b ? s.toUpperCase() : s.toLowerCase()) + ints; } } @Test public void proceedFromDelegateMethodOnRegularMockedClass(@Mocked final ClassToBeMocked mocked) { new Expectations() {{ mocked.methodToBeMocked(); result = new Delegate() { @Mock boolean delegate(Invocation inv) { return inv.proceed(); } }; }}; assertTrue(mocked.methodToBeMocked()); } @Test public void proceedFromDelegateMethodOnInjectableMockedClass(@Injectable final ClassToBeMocked mocked) { new Expectations() {{ mocked.methodToBeMocked(); result = new Delegate() { @Mock boolean delegate(Invocation inv) { return inv.proceed(); } }; }}; assertTrue(mocked.methodToBeMocked()); } @Test public void proceedFromDelegateMethodWithParameters() throws Exception { final ClassToBeMocked mocked = new ClassToBeMocked(); new Expectations(mocked) {{ mocked.methodToBeMocked(anyInt); result = new Delegate() { @Mock int delegate(Invocation inv, int i) { Integer j = inv.proceed(); return j + 1; } }; mocked.methodToBeMocked(anyInt, (Object[]) any); maxTimes = 1; result = new Delegate() { @Mock Integer delegate(Invocation inv, int i, Object... args) { args[2] = "mock"; return inv.proceed(); } }; }}; assertEquals(124, mocked.methodToBeMocked(123)); assertEquals(-8, mocked.methodToBeMocked(-9)); assertEquals(7, mocked.methodToBeMocked(3, "Test", new Object(), null, 45)); } @Test public void proceedConditionallyFromDelegateMethod() { final ClassToBeMocked mocked = new ClassToBeMocked(); new Expectations(mocked) {{ mocked.anotherMethodToBeMocked(anyString, anyBoolean, null); result = new Delegate() { @Mock String delegate(Invocation inv, String s, boolean b, List<Number> ints) { if (!b) { return s; } ints.add(45); return inv.proceed(); } }; }}; // Do not proceed: assertNull(mocked.anotherMethodToBeMocked(null, false, null)); // Do proceed: List<Integer> values = new ArrayList<Integer>(); assertEquals("TEST[45]", mocked.anotherMethodToBeMocked("test", true, values)); // Do not proceed again: assertEquals("No proceed", mocked.anotherMethodToBeMocked("No proceed", false, null)); } @Test public void proceedFromDelegateMethodIntoRealMethodWithModifiedArguments() throws Exception { final ClassToBeMocked mocked = new ClassToBeMocked(); new Expectations(ClassToBeMocked.class) {{ mocked.methodToBeMocked(anyInt); result = new Delegate() { @Mock Integer delegate1(Invocation invocation, int i) { return invocation.proceed(i + 2); } }; mocked.methodToBeMocked(anyInt, (Object[]) any); result = new Delegate() { @Mock Integer delegate2(Invocation inv, int i, Object... args) { return inv.proceed(1, 2, "3"); } }; }}; assertEquals(3, mocked.methodToBeMocked(1)); assertEquals(3, mocked.methodToBeMocked(-2, null, "Abc", true, 'a')); } @Test public void proceedFromDelegateMethodIntoConstructor() { new Expectations(ClassToBeMocked.class) {{ new ClassToBeMocked(); result = new Delegate() { @Mock void init(Invocation inv) { assertNotNull(inv.getInvokedInstance()); inv.proceed(); } }; }}; ClassToBeMocked obj = new ClassToBeMocked(); assertEquals("", obj.name); } @Test public void proceedConditionallyFromDelegateMethodIntoConstructor() { new Expectations(ClassToBeMocked.class) {{ new ClassToBeMocked(anyString); result = new Delegate() { @Mock void init(Invocation inv, String name) { assertNotNull(inv.getInvokedInstance()); if ("proceed".equals(name)) { inv.proceed(); } } }; }}; assertEquals("proceed", new ClassToBeMocked("proceed").name); assertNull(new ClassToBeMocked("do not proceed").name); } @Test public void proceedConditionallyFromDelegateMethodIntoJREConstructor() { new Expectations(ProcessBuilder.class) {{ new ProcessBuilder(anyString); result = new Delegate() { @Mock void init(Invocation inv, String... command) { if ("proceed".equals(command[0])) { inv.proceed(); } } }; }}; ProcessBuilder obj1 = new ProcessBuilder("proceed"); assertEquals("proceed", obj1.command().get(0)); ProcessBuilder obj2 = new ProcessBuilder("do not proceed"); assertNull(obj2.command()); } @SuppressWarnings("UseOfObsoleteCollectionType") @Test public void proceedFromDelegateMethodIntoJREConstructorWhichCallsAnotherInTheSameClass() { new Expectations(Vector.class) {{ new Vector<String>(anyInt); result = new Delegate() { @Mock void init(Invocation inv, int i) { inv.proceed(); } }; }}; assertEquals(1, new Vector<String>(1).capacity()); assertEquals(10, new Vector<String>().capacity()); } @Test public void proceedFromDelegateMethodIntoMethodInheritedFromBaseClass() { final ClassToBeMocked obj = new ClassToBeMocked(); new Expectations(obj) {{ obj.baseMethod(anyInt); result = new Delegate() { @Mock int baseMethod(Invocation inv, int i) { return inv.proceed(i + 1); } }; }}; assertEquals(3, obj.baseMethod(1)); } @Test public void proceedFromDelegateMethodIntoOverridingMethodWhichCallsSuper(@Mocked final ClassToBeMocked mocked) throws Exception { new Expectations() {{ mocked.methodToBeMocked(1); result = new Delegate() { @Mock int delegate(Invocation inv) { return inv.proceed(); } }; }}; assertEquals(1, mocked.methodToBeMocked(1)); } @Test public void proceedFromDelegateMethodIntoOverridingMethodThatCallsSuperWhichAlsoHasAProceedingDelegate( @Mocked final BaseClassToBeMocked mockedBase, @Mocked final ClassToBeMocked mocked) throws Exception { new Expectations() {{ mockedBase.methodToBeMocked(1); result = new Delegate() { // Will not execute when calling on subclass instance. @Mock int delegate(Invocation inv) { int i = inv.proceed(); return i + 1; } }; mocked.methodToBeMocked(1); result = new Delegate() { @Mock int delegate(Invocation inv) { return inv.proceed(); } }; }}; assertEquals(2, mockedBase.methodToBeMocked(1)); assertEquals(1, mocked.methodToBeMocked(1)); } @Test public void replaceMockedInstanceWithRealOne() { final ClassToBeMocked notMocked = new ClassToBeMocked("not mocked"); new Expectations(ClassToBeMocked.class) {{ new ClassToBeMocked(anyString); result = notMocked; }}; assertEquals("not mocked", new ClassToBeMocked("test").getName()); } @Test public void throwExceptionFromProceedIntoJREMethod( @Injectable final AbstractExecutorService c1, @Mocked final ClassToBeMocked c2) throws Exception { new Expectations() {{ c1.submit((Runnable) any); result = new Delegate() { @Mock void delegate(Invocation inv) { inv.proceed(); } }; }}; try { c1.submit((Runnable) null); fail(); } catch (NullPointerException ignored) { new Expectations() {{ c2.methodToBeMocked(anyInt); result = 123; }}; assertEquals(123, c2.methodToBeMocked(1)); } } }