/* * 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.Serializable; import java.util.*; import org.junit.*; import org.junit.runners.*; import static org.junit.Assert.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public final class CascadingFieldTest { static class Foo { Bar getBar() { return null; } static Bar globalBar() { return null; } void doSomething(String s) { throw new RuntimeException(s); } int getIntValue() { return 1; } Boolean getBooleanValue() { return true; } String getStringValue() { return "abc"; } public final Date getDate() { return null; } final List<Integer> getList() { return null; } } static class Bar { Bar() { throw new RuntimeException(); } int doSomething() { return 1; } boolean isDone() { return false; } Short getShort() { return 1; } List<?> getList() { return null; } Baz getBaz() { return null; } Runnable getTask() { return null; } } static final class Baz { final E e; Baz(E e) { this.e = e; } E getE() { return e; } void doSomething() {} } public enum E { A, B } public interface A { B getB(); } public interface B { C getC(); } public interface C {} @Mocked Foo foo; @Mocked A a; @Before public void recordCommonExpectations() { new Expectations() {{ Bar bar = foo.getBar(); minTimes = 0; bar.isDone(); result = true; minTimes = 0; }}; } @Test public void obtainCascadedInstancesAtAllLevels() { assertNotNull(foo.getBar()); assertNotNull(foo.getBar().getList()); assertNotNull(foo.getBar().getBaz()); assertNotNull(foo.getBar().getTask()); B b = a.getB(); assertNotNull(b); assertNotNull(b.getC()); } @Test public void obtainCascadedInstancesAtAllLevelsAgain() { Bar bar = foo.getBar(); assertNotNull(bar); assertNotNull(bar.getList()); assertNotNull(bar.getBaz()); assertNotNull(bar.getTask()); assertNotNull(a.getB()); assertNotNull(a.getB().getC()); } @Test public void cascadeOneLevel() { assertTrue(foo.getBar().isDone()); assertEquals(0, foo.getBar().doSomething()); assertEquals(0, Foo.globalBar().doSomething()); assertNotSame(foo.getBar(), Foo.globalBar()); assertEquals(0, foo.getBar().getShort().intValue()); foo.doSomething("test"); assertEquals(0, foo.getIntValue()); assertFalse(foo.getBooleanValue()); assertNull(foo.getStringValue()); assertNotNull(foo.getDate()); assertTrue(foo.getList().isEmpty()); new Verifications() {{ foo.doSomething(anyString); }}; } @Test public void exerciseCascadingMockAgain() { assertTrue(foo.getBar().isDone()); } @Test public void recordUnambiguousStrictExpectationsProducingDifferentCascadedInstances() { new StrictExpectations() {{ Bar c1 = Foo.globalBar(); c1.isDone(); result = true; Bar c2 = Foo.globalBar(); c2.doSomething(); result = 5; assertNotSame(c1, c2); }}; Bar b1 = Foo.globalBar(); assertTrue(b1.isDone()); Bar b2 = Foo.globalBar(); assertEquals(5, b2.doSomething()); assertNotSame(b1, b2); } @Test public void recordUnambiguousNonStrictExpectationsProducingDifferentCascadedInstances( @Mocked final Foo foo1, @Mocked final Foo foo2) { new Expectations() {{ Date c1 = foo1.getDate(); Date c2 = foo2.getDate(); assertNotSame(c1, c2); }}; Date d1 = foo1.getDate(); Date d2 = foo2.getDate(); assertNotSame(d1, d2); } @Test public void recordAmbiguousExpectationsOnInstanceMethodProducingTheSameCascadedInstance() { new Expectations() {{ Bar c1 = foo.getBar(); Bar c2 = foo.getBar(); assertSame(c1, c2); }}; Bar b1 = foo.getBar(); Bar b2 = foo.getBar(); assertSame(b1, b2); } @Test public void recordAmbiguousExpectationsOnStaticMethodProducingTheSameCascadedInstance() { new Expectations() {{ Bar c1 = Foo.globalBar(); Bar c2 = Foo.globalBar(); assertSame(c1, c2); }}; Bar b1 = Foo.globalBar(); Bar b2 = Foo.globalBar(); assertSame(b1, b2); } @Test public void recordAmbiguousExpectationWithMultipleCascadingCandidatesFollowedByExpectationRecordedOnFirstCandidate( @Injectable final Bar bar1, @Injectable Bar bar2) { new Expectations() {{ foo.getBar(); bar1.doSomething(); }}; foo.getBar(); bar1.doSomething(); } static final class AnotherFoo { Bar getBar() { return null; } } @Mocked AnotherFoo anotherFoo; @Test public void cascadingMockField() { new Expectations() {{ anotherFoo.getBar().doSomething(); result = 123; }}; assertEquals(123, new AnotherFoo().getBar().doSomething()); } @Test public void cascadingInstanceAccessedFromDelegateMethod() { new Expectations() {{ foo.getIntValue(); result = new Delegate() { @Mock int delegate() { return foo.getBar().doSomething(); } }; }}; assertEquals(0, foo.getIntValue()); } @Mocked BazCreatorAndConsumer bazCreatorAndConsumer; static class BazCreatorAndConsumer { Baz create() { return null; } void consume(Baz arg) { arg.toString(); } } @Test public void callMethodOnNonCascadedInstanceFromCustomArgumentMatcherWithCascadedInstanceAlsoCreated() { Baz nonCascadedInstance = new Baz(E.A); Baz cascadedInstance = bazCreatorAndConsumer.create(); assertNotSame(nonCascadedInstance, cascadedInstance); bazCreatorAndConsumer.consume(nonCascadedInstance); new Verifications() {{ bazCreatorAndConsumer.consume(with(new Delegate<Baz>() { @SuppressWarnings("unused") boolean matches(Baz actual) { return actual.getE() == E.A; } })); }}; } // Tests for cascaded instances obtained from generic methods ////////////////////////////////////////////////////// static class GenericBaseClass1<T> { T getValue() { return null; } } @Test public void cascadeGenericMethodFromSpecializedGenericClass(@Mocked GenericBaseClass1<C> mock) { C value = mock.getValue(); assertNotNull(value); } static class ConcreteSubclass1 extends GenericBaseClass1<A> {} @Test public void cascadeGenericMethodOfConcreteSubclassWhichExtendsGenericClass(@Mocked final ConcreteSubclass1 mock) { new Expectations() {{ mock.getValue().getB().getC(); result = new C() {}; }}; A value = mock.getValue(); assertNotNull(value); B b = value.getB(); assertNotNull(b); assertNotNull(b.getC()); new FullVerificationsInOrder() {{ mock.getValue().getB().getC(); }}; } interface Ab extends A {} static class GenericBaseClass2<T extends A> { T getValue() { return null; } } static class ConcreteSubclass2 extends GenericBaseClass2<Ab> {} @Test public void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundUsingInterface( @Mocked final ConcreteSubclass2 mock) { Ab value = mock.getValue(); assertNotNull(value); value.getB().getC(); new Verifications() {{ mock.getValue().getB().getC(); times = 1; }}; } @Test public void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundOnlyInVerificationBlock( @Mocked final ConcreteSubclass2 mock) { new FullVerifications() {{ Ab value = mock.getValue(); times = 0; B b = value.getB(); times = 0; b.getC(); times = 0; }}; } static final class Action implements A { @Override public B getB() { return null; } } static final class ActionHolder extends GenericBaseClass2<Action> {} @Test public void cascadeGenericMethodOfSubclassWhichExtendsGenericClassWithUpperBoundUsingClass( @Mocked final ActionHolder mock) { new StrictExpectations() {{ mock.getValue().getB().getC(); }}; mock.getValue().getB().getC(); } class Base<T extends Serializable> { @SuppressWarnings("unchecked") T value() { return (T) Long.valueOf(123); } } class Derived1 extends Base<Long> {} class Derived2 extends Base<Long> {} interface Factory1 { Derived1 get1(); } interface Factory2 { Derived2 get2(); } @Mocked Factory1 factory1; @Mocked Factory2 factory2; @Test public void useSubclassMockedThroughCascading() { Derived1 d1 = factory1.get1(); // cascade-mocks Derived1 (per-instance) Long v1 = d1.value(); assertEquals(0, v1.longValue()); Long v2 = new Derived1().value(); // new instance, not mocked assertEquals(123, v2.longValue()); } @Test public void useSubclassPreviouslyMockedThroughCascadingWhileMockingSiblingSubclass(@Injectable Derived2 d2) { Long v1 = new Derived1().value(); assertEquals(123, v1.longValue()); Long v2 = d2.value(); assertEquals(0, v2.longValue()); Long v3 = new Derived2().value(); assertEquals(123, v3.longValue()); } }