// Copyright © 2011-2014, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
package fi.jumi.core.runs;
import fi.jumi.api.drivers.TestId;
import fi.jumi.core.api.*;
import fi.jumi.core.util.Boilerplate;
import javax.annotation.concurrent.NotThreadSafe;
import java.util.*;
/**
* Filters unnecessary events and checks some notifier API usage. Most of the notifier API usage checks are the
* responsibility of {@link fi.jumi.core.runs.Run} - this class does only checks that are not convenient to do there
* (e.g. due to requiring mutable state).
*/
@NotThreadSafe
public class RunEventNormalizer implements RunListener {
private final SuiteListener listener;
private final TestFile testFile;
private final Map<TestId, String> testNamesById = new HashMap<>();
public RunEventNormalizer(SuiteListener listener, TestFile testFile) {
this.listener = listener;
this.testFile = testFile;
}
@Override
public String toString() {
return Boilerplate.toString(getClass(), testFile);
}
private String withContext(String message) {
return "Incorrect notifier API usage in " + testFile + ": " + message;
}
@Override
public void onTestFound(TestId testId, String name) {
if (hasNotBeenFoundBefore(testId)) {
checkParentWasFoundFirst(testId);
rememberFoundTest(testId, name);
listener.onTestFound(testFile, testId, name);
} else {
checkNameIsSameAsBefore(testId, name);
}
}
private void rememberFoundTest(TestId testId, String name) {
testNamesById.put(testId, name);
}
private boolean hasNotBeenFoundBefore(TestId testId) {
return !testNamesById.containsKey(testId);
}
private void checkParentWasFoundFirst(TestId testId) {
if (!testId.isRoot() && hasNotBeenFoundBefore(testId.getParent())) {
throw new IllegalStateException(withContext("parent of " + testId + " must be found first"));
}
}
private void checkNameIsSameAsBefore(TestId testId, String newName) {
String oldName = testNamesById.get(testId);
if (oldName != null && !oldName.equals(newName)) {
throw new IllegalArgumentException(withContext("test " + testId + " was already found with another name: " + oldName));
}
}
@Override
public void onInternalError(String message, Throwable cause) {
// TODO: should we prepend the testFile as context information to the message?
listener.onInternalError(message, StackTrace.from(cause));
}
@Override
public void onRunStarted(RunId runId) {
listener.onRunStarted(runId, testFile);
}
@Override
public void onTestStarted(RunId runId, TestId testId) {
checkHasBeenFound(testId);
listener.onTestStarted(runId, testId);
}
private void checkHasBeenFound(TestId testId) {
if (hasNotBeenFoundBefore(testId)) {
throw new IllegalStateException(withContext("the test " + testId + " must be found first"));
}
}
@Override
public void onPrintedOut(RunId runId, String text) {
listener.onPrintedOut(runId, text);
}
@Override
public void onPrintedErr(RunId runId, String text) {
listener.onPrintedErr(runId, text);
}
@Override
public void onFailure(RunId runId, TestId testId, Throwable cause) {
listener.onFailure(runId, StackTrace.from(cause));
}
@Override
public void onTestFinished(RunId runId, TestId testId) {
listener.onTestFinished(runId);
}
@Override
public void onRunFinished(RunId runId) {
listener.onRunFinished(runId);
}
}