package org.testory;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.testory.Testory.mock;
import static org.testory.Testory.thenCalled;
import static org.testory.Testory.when;
import static org.testory.testing.Fakes.newObject;
import static org.testory.testing.HamcrestMatchers.hasMessageContaining;
import static org.testory.testing.Purging.triggerPurge;
import org.junit.Before;
import org.junit.Test;
import org.testory.common.Closure;
import org.testory.proxy.Invocation;
import org.testory.proxy.InvocationMatcher;
public class TestThenCalledAllOverloadings {
private Object object;
private Mockable mock;
private Invocation invocation;
@Before
public void before() {
triggerPurge();
object = newObject("object");
mock = mock(Mockable.class);
}
@Test
public void chained_verification_does_not_log_invocation() {
mock.invoke();
thenCalled(mock).invoke();
thenCalled(mock).invoke();
}
@Test
public void includes_invocations_inside_when() {
when(mock.invoke());
thenCalled(onInstance(mock));
}
@Test
public void includes_invocations_before_when() {
mock.invoke();
when("do something");
thenCalled(onInstance(mock));
}
@Test
public void includes_invocations_inside_when_closure() {
when(new Closure() {
public Object invoke() throws Throwable {
mock.invoke();
return null;
}
});
thenCalled(onInstance(mock));
}
@Test
public void includes_invocations_before_when_closure() {
mock.invoke();
when(new Closure() {
public Object invoke() throws Throwable {
return null;
}
});
thenCalled(onInstance(mock));
}
@Test
public void invocation_matcher_matches_invocation_on_mock() throws NoSuchMethodException {
mock.acceptObject(object);
thenCalled(new InvocationMatcher() {
public boolean matches(Invocation inv) {
if (inv.instance == mock) {
invocation = inv;
return true;
}
return false;
}
});
assertSame(mock, invocation.instance);
assertEquals(Mockable.class.getDeclaredMethod("acceptObject", Object.class), invocation.method);
assertEquals(asList(object), invocation.arguments);
}
@Test
public void failure_prints_actual_number_of_calls() {
mock.invoke();
mock.invoke();
mock.invoke();
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {
assertThat(e, hasMessageContaining(""
+ " but called" + "\n"
+ " times " + 3 + "\n"));
}
}
@Test
public void failure_prints_actual_invocations() {
mock.invoke();
mock.acceptObject(object);
mock.acceptObjects(object, object);
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {
assertThat(e, hasMessageContaining(""
+ " actual invocations\n"
+ " " + mock + ".invoke()\n"
+ " " + mock + ".acceptObject(" + object + ")\n"
+ " " + mock + ".acceptObjects(" + object + ", " + object + ")\n"));
}
}
@Test
public void failure_prints_actual_invocations_with_array_arguments() {
mock.invoke();
mock.acceptObject(new Object[][] { { object } });
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {
assertThat(e, hasMessageContaining(""
+ " " + mock + ".acceptObject([[" + object + "]])\n"));
}
}
@Test
public void failure_prints_special_message_if_no_actual_invocations() {
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {
assertThat(e, hasMessageContaining(""
+ " actual invocations\n"
+ " none\n"));
}
}
@Test
public void printing_failure_does_not_log_invocation_on_tostring() {
mock.invoke();
mock.invoke();
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {}
try {
thenCalled(onInstance(mock));
fail();
} catch (TestoryAssertionError e) {
assertThat(e, not(hasMessageContaining(mock + ".toString()")));
}
}
private static InvocationMatcher onInstance(final Object mock) {
return new InvocationMatcher() {
public boolean matches(Invocation invocation) {
return invocation.instance == mock;
}
public String toString() {
return "onInstance(" + mock + ")";
}
};
}
private static abstract class Mockable {
abstract Object invoke();
abstract void acceptObject(Object o);
abstract void acceptObjects(Object o, Object o2);
}
}