/*
* Galaxy
* Copyright (C) 2012 Parallel Universe Software Co.
*
* This file is part of Galaxy.
*
* Galaxy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Galaxy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Galaxy. If not, see <http://www.gnu.org/licenses/>.
*/
package co.paralleluniverse.galaxy.test;
import java.util.Arrays;
import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.internal.stubbing.answers.CallsRealMethods;
import org.mockito.internal.stubbing.answers.DoesNothing;
import org.mockito.internal.stubbing.answers.Returns;
import org.mockito.internal.stubbing.answers.ThrowsException;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.OngoingStubbing;
import org.mockito.stubbing.Stubber;
/**
*
* @author pron
*/
public final class LogMock {
//private static boolean log = false;
private static final ThreadTreeLocal<Boolean> log = new ThreadTreeLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
private static final ThreadTreeLocal<Thread> mainThread = new ThreadTreeLocal<Thread>();
public static final Answer<?> LOGS_CALLS = logAnswer(Mockito.RETURNS_DEFAULTS);
private static <T> Answer<T> logAnswer(final Answer<T> answer) {
return new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object retValue;
try {
retValue = answer.answer(invocation);
if (log.get()) {
if (!(invocation.getMethod().getName().equals("toString") && invocation.getMethod().getParameterTypes().length == 0 && invocation.getMethod().getReturnType().equals(String.class))) {
if (invocation.getMethod().getReturnType().equals(void.class) || invocation.getMethod().getReturnType().equals(Void.class))
System.out.println((Thread.currentThread() != mainThread.get() ? Thread.currentThread().getName() : "") + " CALL: " + invocation + " (" + Arrays.toString(Thread.currentThread().getStackTrace()) + ")");
else
System.out.println((Thread.currentThread() != mainThread.get() ? Thread.currentThread().getName() : "") + " CALL: " + invocation + " => " + retValue + " (" + Arrays.toString(Thread.currentThread().getStackTrace()) + ")");
}
}
return retValue;
} catch (Throwable t) {
if (log.get())
System.out.println((Thread.currentThread() != mainThread.get() ? Thread.currentThread().getName() : "") + " CALL: " + invocation + " => " + "thrown " + t);
throw t;
}
}
};
}
public static void startLogging() {
mainThread.set(Thread.currentThread());
log.set(true); // log = true; //
}
public static void stopLogging() {
log.set(false); // log = false; //
mainThread.set(null);
}
public static <T> T spy(T object) {
return Mockito.mock((Class<T>) object.getClass(), Mockito.withSettings().spiedInstance(object).defaultAnswer(logAnswer(Mockito.CALLS_REAL_METHODS)));
}
public static <T> T mock(Class<T> classToMock) {
return Mockito.mock(classToMock, Mockito.withSettings().defaultAnswer(LOGS_CALLS));
}
public static <T> T mock(Class<T> classToMock, String name) {
return Mockito.mock(classToMock, Mockito.withSettings().name(name).defaultAnswer(LOGS_CALLS));
}
public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
return Mockito.mock(classToMock, mockSettings.defaultAnswer(LOGS_CALLS));
}
public static <T> T mock(Class<T> classToMock, Answer answer) {
return Mockito.mock(classToMock, answer);
}
public static <T> OngoingStubbing<T> when(T methodCall) {
return new OngoingStubbingExt<T>(Mockito.when(methodCall));
}
public static Stubber doThrow(Throwable toBeThrown) {
return doAnswer(new ThrowsException(toBeThrown));
}
public static Stubber doReturn(Object toBeReturned) {
return doAnswer(new Returns(toBeReturned));
}
public static Stubber doNothing() {
return doAnswer(new DoesNothing());
}
public static Stubber doAnswer(Answer answer) {
return new StubberExt(Mockito.doAnswer(logAnswer(answer)));
}
private static class OngoingStubbingExt<T> implements OngoingStubbing<T> {
private final OngoingStubbing<T> delegate;
public OngoingStubbingExt(OngoingStubbing<T> delegate) {
this.delegate = delegate;
}
@Override
public OngoingStubbing<T> thenThrow(Throwable... throwables) {
if (throwables.length > 1)
throw new UnsupportedOperationException();
return thenAnswer(new ThrowsException(throwables[0]));
}
@Override
public OngoingStubbing<T> thenThrow(Class<? extends Throwable>... throwableClasses) {
try {
if (throwableClasses.length > 0)
throw new UnsupportedOperationException();
return thenAnswer(new ThrowsException(throwableClasses[0].newInstance()));
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
@Override
public OngoingStubbing<T> thenReturn(T value, T... values) {
if (values.length > 0)
throw new UnsupportedOperationException();
return thenReturn(value);
}
@Override
public OngoingStubbing<T> thenReturn(T retValue) {
return thenAnswer(new Returns(retValue));
}
@Override
public OngoingStubbing<T> thenCallRealMethod() {
return thenAnswer(new CallsRealMethods());
}
@Override
public OngoingStubbing<T> thenAnswer(Answer<?> answer) {
return new OngoingStubbingExt(delegate.thenAnswer(logAnswer(answer)));
}
@Override
public OngoingStubbing<T> then(Answer<?> answer) {
return new OngoingStubbingExt(delegate.then(logAnswer(answer)));
}
@Override
public <M> M getMock() {
return delegate.getMock();
}
}
private static class StubberExt implements Stubber {
private final Stubber delegate;
public StubberExt(Stubber delegate) {
this.delegate = delegate;
}
@Override
public Stubber doThrow(Throwable toBeThrown) {
return doAnswer(new ThrowsException(toBeThrown));
}
@Override
public Stubber doThrow(Class<? extends Throwable> toBeThrown) {
try {
return doAnswer(new ThrowsException(toBeThrown.newInstance()));
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
@Override
public Stubber doReturn(Object toBeReturned) {
return doAnswer(new Returns(toBeReturned));
}
@Override
public Stubber doNothing() {
return doAnswer(new DoesNothing());
}
@Override
public Stubber doAnswer(Answer answer) {
return new StubberExt(delegate.doAnswer(logAnswer(answer)));
}
@Override
public Stubber doCallRealMethod() {
return delegate.doCallRealMethod();
}
@Override
public <T> T when(T mock) {
return delegate.when(mock);
}
}
private LogMock() {
}
}