package org.xpect.lib;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.ComparisonFailure;
import org.junit.runner.RunWith;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.xpect.XpectFile;
import org.xpect.XpectImport;
import org.xpect.XpectInvocation;
import org.xpect.expectation.IExpectationRegion;
import org.xpect.expectation.IStringDiffExpectation;
import org.xpect.expectation.IStringExpectation;
import org.xpect.expectation.StringDiffExpectation;
import org.xpect.expectation.StringExpectation;
import org.xpect.lib.XpectTestResultTest.ReflectiveXpectFileRunner;
import org.xpect.runner.Xpect;
import org.xpect.runner.XpectFileRunner;
import org.xpect.runner.XpectRunner;
import org.xpect.runner.XpectTestRunner;
import org.xpect.setup.XpectSetupFactory;
import org.xpect.state.StateContainer;
import org.xpect.text.IRegion;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@RunWith(XpectRunner.class)
@XpectImport(ReflectiveXpectFileRunner.class)
public class XpectTestResultTest {
public static class FailureListener extends RunListener {
private Failure failure;
public Failure getFailure() {
return failure;
}
@Override
public void testAssumptionFailure(Failure failure) {
this.failure = failure;
}
@Override
public void testFailure(Failure failure) throws Exception {
this.failure = failure;
}
}
@XpectSetupFactory
public final static class ReflectiveXpectFileRunner extends XpectFileRunner {
private final Map<XpectTestRunner, XpectTestRunner> reflectiveToInspected = Maps.newHashMap();
public ReflectiveXpectFileRunner(StateContainer state, XpectFile file) {
super(state, file);
}
@Override
protected List<Runner> createChildren() {
List<Runner> filtered = Lists.newArrayList();
List<XpectTestRunner> lastReflectives = Lists.newArrayList();
List<Runner> allChildren = super.createChildren();
for (Runner runner : allChildren) {
if (runner instanceof XpectTestRunner) {
XpectTestRunner testRunner = (XpectTestRunner) runner;
if (isReflectiveTest(testRunner.getInvocation())) {
lastReflectives.add(testRunner);
filtered.add(runner);
} else if (!lastReflectives.isEmpty()) {
for (XpectTestRunner reflective : lastReflectives)
reflectiveToInspected.put(reflective, testRunner);
lastReflectives.clear();
} else {
filtered.add(runner);
}
} else {
filtered.add(runner);
}
}
return filtered;
}
public Map<XpectTestRunner, XpectTestRunner> getReflectiveToInspected() {
return reflectiveToInspected;
}
protected boolean isReflectiveTest(XpectInvocation invocation) {
return XpectTestResultTest.class.isAssignableFrom(invocation.getMethod().getTest().getJavaClass());
}
}
protected IRegion getExpectationRegion(XpectTestRunner runner) {
return runner.getInvocation().getRelatedRegion(IExpectationRegion.class);
}
protected Failure run(XpectTestRunner inspected) {
if (inspected == null)
Assert.fail("This test needs to be followed by another XPECT statement.");
FailureListener failureListener = new FailureListener();
RunNotifier notifier = new RunNotifier();
notifier.addListener(failureListener);
inspected.run(notifier);
Failure failure = failureListener.getFailure();
if (failure == null)
Assert.fail("The test didn't fail: " + inspected.getDescription().getDisplayName());
return failure;
}
@Xpect
public void testFailureDiff(@StringDiffExpectation IStringDiffExpectation expectation, XpectTestRunner runner) {
ReflectiveXpectFileRunner fileRunner = (ReflectiveXpectFileRunner) runner.getFileRunner();
XpectTestRunner inspected = fileRunner.getReflectiveToInspected().get(runner);
Failure failure = run(inspected);
Throwable exception = failure.getException();
if (exception instanceof ComparisonFailure) {
IRegion region = getExpectationRegion(inspected);
ComparisonFailure comparisonFailure = (ComparisonFailure) exception;
String expected = comparisonFailure.getExpected();
String actual = comparisonFailure.getActual();
String trimmedExpected = trim(expected, expected, region);
String trimmedActual = trim(actual, expected, region);
expectation.assertDiffEquals(trimmedExpected, trimmedActual);
} else {
throw new AssertionError("The exception is not a " + ComparisonFailure.class.getName(), exception);
}
}
@Xpect
public void testFailureMessage(@StringExpectation IStringExpectation expectation, XpectTestRunner runner) {
ReflectiveXpectFileRunner fileRunner = (ReflectiveXpectFileRunner) runner.getFileRunner();
XpectTestRunner inspected = fileRunner.getReflectiveToInspected().get(runner);
Failure failure = run(inspected);
expectation.assertEquals(failure.getMessage());
}
protected String trim(String string, String ref, IRegion region) {
if (region == null)
return string;
int offsetFromEnd = ref.length() - (region.getOffset() + region.getLength());
return string.substring(region.getOffset(), string.length() - offsetFromEnd);
}
}