// 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.ipc.encoding; import fi.jumi.actors.eventizers.Event; import fi.jumi.api.drivers.TestId; import fi.jumi.core.api.*; import fi.jumi.core.ipc.buffer.IpcBuffer; import javax.annotation.concurrent.NotThreadSafe; import java.nio.file.Paths; @NotThreadSafe public class SuiteListenerEncoding extends EncodingUtil implements SuiteListener, MessageEncoding<SuiteListener> { private static final byte onSuiteStarted = 1; private static final byte onInternalError = 2; private static final byte onTestFileFound = 3; private static final byte onAllTestFilesFound = 4; private static final byte onTestFound = 5; private static final byte onRunStarted = 6; private static final byte onTestStarted = 7; private static final byte onPrintedOut = 8; private static final byte onPrintedErr = 9; private static final byte onFailure = 10; private static final byte onTestFinished = 11; private static final byte onRunFinished = 12; private static final byte onTestFileFinished = 13; private static final byte onSuiteFinished = 14; public SuiteListenerEncoding(IpcBuffer buffer) { super(buffer); } @Override public String getInterfaceName() { return SuiteListener.class.getName(); } @Override public int getInterfaceVersion() { return 1; } @Override public void encode(Event<SuiteListener> message) { message.fireOn(this); } @Override public void decode(SuiteListener target) { byte type = readEventType(); switch (type) { case onSuiteStarted: target.onSuiteStarted(); break; case onInternalError: target.onInternalError(readString(), readStackTrace()); break; case onTestFileFound: target.onTestFileFound(readTestFile()); break; case onAllTestFilesFound: target.onAllTestFilesFound(); break; case onTestFound: target.onTestFound(readTestFile(), readTestId(), readString()); break; case onRunStarted: target.onRunStarted(readRunId(), readTestFile()); break; case onTestStarted: target.onTestStarted(readRunId(), readTestId()); break; case onPrintedOut: target.onPrintedOut(readRunId(), readString()); break; case onPrintedErr: target.onPrintedErr(readRunId(), readString()); break; case onFailure: target.onFailure(readRunId(), readStackTrace()); break; case onTestFinished: target.onTestFinished(readRunId()); break; case onRunFinished: target.onRunFinished(readRunId()); break; case onTestFileFinished: target.onTestFileFinished(readTestFile()); break; case onSuiteFinished: target.onSuiteFinished(); break; default: throw new IllegalArgumentException("Unknown type " + type); } } // encoding events @Override public void onSuiteStarted() { writeEventType(onSuiteStarted); } @Override public void onInternalError(String message, StackTrace cause) { writeEventType(onInternalError); writeString(message); writeStackTrace(cause); } @Override public void onTestFileFound(TestFile testFile) { writeEventType(onTestFileFound); writeTestFile(testFile); } @Override public void onAllTestFilesFound() { writeEventType(onAllTestFilesFound); } @Override public void onTestFound(TestFile testFile, TestId testId, String name) { writeEventType(onTestFound); writeTestFile(testFile); writeTestId(testId); writeString(name); } @Override public void onRunStarted(RunId runId, TestFile testFile) { writeEventType(onRunStarted); writeRunId(runId); writeTestFile(testFile); } @Override public void onTestStarted(RunId runId, TestId testId) { writeEventType(onTestStarted); writeRunId(runId); writeTestId(testId); } @Override public void onPrintedOut(RunId runId, String text) { writeEventType(onPrintedOut); writeRunId(runId); writeString(text); } @Override public void onPrintedErr(RunId runId, String text) { writeEventType(onPrintedErr); writeRunId(runId); writeString(text); } @Override public void onFailure(RunId runId, StackTrace cause) { writeEventType(onFailure); writeRunId(runId); writeStackTrace(cause); } @Override public void onTestFinished(RunId runId) { writeEventType(onTestFinished); writeRunId(runId); } @Override public void onRunFinished(RunId runId) { writeEventType(onRunFinished); writeRunId(runId); } @Override public void onTestFileFinished(TestFile testFile) { writeEventType(onTestFileFinished); writeTestFile(testFile); } @Override public void onSuiteFinished() { writeEventType(onSuiteFinished); } // TestFile private void writeTestFile(TestFile testFile) { writeString(testFile.getPath()); } private TestFile readTestFile() { return TestFile.fromPath(Paths.get(readString())); } // TestId private void writeTestId(TestId testId) { writeIntArray(testId.getPath()); } private TestId readTestId() { return TestId.of(readIntArray()); } // RunId private void writeRunId(RunId runId) { buffer.writeInt(runId.toInt()); } private RunId readRunId() { return new RunId(buffer.readInt()); } // StackTrace void writeStackTrace(StackTrace stackTrace) { writeString(stackTrace.getExceptionClass()); writeString(stackTrace.toString()); writeNullableString(stackTrace.getMessage()); writeStackTraceElements(stackTrace.getStackTrace()); writeOptionalException(stackTrace.getCause()); writeExceptions(stackTrace.getSuppressed()); } StackTrace readStackTrace() { return new StackTrace.Builder() .setExceptionClass(readString()) .setToString(readString()) .setMessage(readNullableString()) .setStackTrace(readStackTraceElements()) .setCause(readOptionalException()) .setSuppressed(readExceptions()) .build(); } private void writeStackTraceElements(StackTraceElement[] elements) { writeArray(elements, this::writeStackTraceElement); } private StackTraceElement[] readStackTraceElements() { return readArray(this::readStackTraceElement, StackTraceElement[]::new); } private void writeStackTraceElement(StackTraceElement element) { writeString(element.getClassName()); writeString(element.getMethodName()); writeNullableString(element.getFileName()); buffer.writeInt(element.getLineNumber()); } private StackTraceElement readStackTraceElement() { String className = readString(); String methodName = readString(); String fileName = readNullableString(); int lineNumber = buffer.readInt(); return new StackTraceElement(className, methodName, fileName, lineNumber); } // Throwable (assumed to be StackTrace at runtime) private void writeOptionalException(Throwable exception) { writeExceptions(exception == null ? new Throwable[0] : new Throwable[]{exception}); } private Throwable readOptionalException() { Throwable[] exceptions = readExceptions(); return exceptions.length == 0 ? null : exceptions[0]; } private void writeExceptions(Throwable[] exceptions) { writeArray(exceptions, this::writeException); } private Throwable[] readExceptions() { return readArray(this::readException, Throwable[]::new); } private void writeException(Throwable exception) { writeStackTrace((StackTrace) exception); } private Throwable readException() { return readStackTrace(); } }