package fitnesse.junit; import java.io.Closeable; import fitnesse.testrunner.TestsRunnerListener; import fitnesse.testsystems.Assertion; import fitnesse.testsystems.ExceptionResult; import fitnesse.testsystems.ExecutionResult; import fitnesse.testsystems.TestPage; import fitnesse.testsystems.TestResult; import fitnesse.testsystems.TestSummary; import fitnesse.testsystems.TestSystem; import fitnesse.testsystems.TestSystemListener; import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; public class JUnitRunNotifierResultsListener implements TestSystemListener, TestsRunnerListener, Closeable { private final Class<?> mainClass; private final RunNotifier notifier; private final DescriptionFactory descriptionFactory; private int totalNumberOfTests; private int completedTests; private Throwable firstFailure; public JUnitRunNotifierResultsListener(RunNotifier notifier, Class<?> mainClass, DescriptionFactory descriptionFactory) { this.notifier = notifier; this.mainClass = mainClass; this.descriptionFactory = descriptionFactory; } @Override public void announceNumberTestsToRun(int testsToRun) { totalNumberOfTests = testsToRun; } @Override public void unableToStartTestSystem(String testSystemName, Throwable cause) { notifyOfTestSystemException(testSystemName, cause); } @Override public void testStarted(TestPage test) { firstFailure = null; notifier.fireTestStarted(descriptionFor(test)); } @Override public void testComplete(TestPage test, TestSummary testSummary) { increaseCompletedTests(); Description description = descriptionFor(test); if (firstFailure != null) { notifier.fireTestFailure(new Failure(description, firstFailure)); } else if (testSummary.getExceptions() > 0) { notifier.fireTestFailure(new Failure(description, new Exception("Exception occurred on page " + test.getFullPath()))); } else if (testSummary.getWrong() > 0) { notifier.fireTestFailure(new Failure(description, new AssertionError("Test failures occurred on page " + test.getFullPath()))); } notifier.fireTestFinished(description); } @Override public void testOutputChunk(String output) { } @Override public void testAssertionVerified(Assertion assertion, TestResult testResult) { if (testResult != null && testResult.doesCount() && (testResult.getExecutionResult() == ExecutionResult.FAIL || testResult.getExecutionResult() == ExecutionResult.ERROR)) { firstFailure(testResult.getExecutionResult(), createMessage(testResult)); } } @Override public void testExceptionOccurred(Assertion assertion, ExceptionResult exceptionResult) { firstFailure(exceptionResult.getExecutionResult(), exceptionResult.getMessage()); } @Override public void testSystemStarted(TestSystem testSystem) { } @Override public void testSystemStopped(TestSystem testSystem, Throwable cause) { notifyOfTestSystemException(testSystem.getName(), cause); } @Override public void close() { if (completedTests != totalNumberOfTests) { String msg = String.format( "Not all tests executed. Completed %s of %s tests.", completedTests, totalNumberOfTests); Exception e = new Exception(msg); notifier.fireTestFailure(new Failure(suiteDescription(), e)); } } protected void notifyOfTestSystemException(String testSystemName, Throwable cause) { if (cause != null) { Exception e = new Exception("Exception while executing tests using: " + testSystemName, cause); notifier.fireTestFailure(new Failure(suiteDescription(), e)); } } private Description suiteDescription() { return getDescriptionFactory().createSuiteDescription(getMainClass()); } protected Description descriptionFor(TestPage test) { return getDescriptionFactory().createDescription(getMainClass(), test); } String createMessage(TestResult testResult) { if (testResult.hasActual() && testResult.hasExpected()) { return String.format("[%s] expected [%s]", testResult.getActual(), testResult.getExpected()); } else if ((testResult.hasActual() || testResult.hasExpected()) && testResult.hasMessage()) { return String.format("[%s] %s", testResult.hasActual() ? testResult.getActual() : testResult.getExpected(), testResult.getMessage()); } return testResult.getMessage(); } private void firstFailure(ExecutionResult executionResult, String message) { if (firstFailure != null) { return; } if (executionResult == ExecutionResult.ERROR) { firstFailure = new Exception(message); } else { firstFailure = new AssertionError(message); } } public Class<?> getMainClass() { return mainClass; } public RunNotifier getNotifier() { return notifier; } public DescriptionFactory getDescriptionFactory() { return descriptionFactory; } public int getTotalNumberOfTests() { return totalNumberOfTests; } protected void increaseCompletedTests() { completedTests++; } public int getCompletedTests() { return completedTests; } public Throwable getFirstFailure() { return firstFailure; } protected void setFirstFailure(Throwable firstFailure) { this.firstFailure = firstFailure; } }