/*
* Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.goide.runconfig.testing.frameworks.gotest;
import com.goide.runconfig.testing.GoTestEventsConverterBase;
import com.goide.runconfig.testing.GoTestLocator;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.execution.testframework.sm.ServiceMessageBuilder;
import com.intellij.execution.testframework.sm.runner.OutputToGeneralTestEventsConverter;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import jetbrains.buildServer.messages.serviceMessages.ServiceMessageTypes;
import jetbrains.buildServer.messages.serviceMessages.ServiceMessageVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.ParseException;
public abstract class GoTestEventsConverterBaseImpl extends OutputToGeneralTestEventsConverter implements GoTestEventsConverterBase {
public enum TestResult {PASSED, FAILED, SKIPPED}
@Nullable
private ServiceMessageVisitor myVisitor;
@Nullable
private String myCurrentTestName;
@Nullable
private TestResult myCurrentTestResult;
private long myCurrentTestStart;
public GoTestEventsConverterBaseImpl(@NotNull String testFrameworkName, @NotNull TestConsoleProperties consoleProperties) {
super(testFrameworkName, consoleProperties);
}
protected abstract int processLine(@NotNull String line, int start, Key outputType, ServiceMessageVisitor visitor)
throws ParseException;
@Nullable
protected String getCurrentTestName() {
return myCurrentTestName;
}
@Override
public final boolean processServiceMessages(@NotNull String text, Key outputType, ServiceMessageVisitor visitor) throws ParseException {
if (myVisitor == null && visitor != null) {
myVisitor = visitor;
}
if (text.isEmpty()) {
return true;
}
int startOffset = 0;
int newStartOffset = processLine(text, startOffset, outputType, visitor);
while (startOffset != newStartOffset && newStartOffset < text.length()) {
startOffset = newStartOffset;
newStartOffset = processLine(text, startOffset, outputType, visitor);
}
if (newStartOffset < text.length()) {
processOutput(text.substring(startOffset), outputType, visitor);
}
return true;
}
protected void processOutput(@NotNull String text, Key outputType, ServiceMessageVisitor visitor) throws ParseException {
if (text.isEmpty()) {
return;
}
boolean isErrorMessage = ProcessOutputTypes.STDERR == outputType;
if (myCurrentTestName != null) {
ServiceMessageBuilder builder = isErrorMessage ? ServiceMessageBuilder.testStdErr(myCurrentTestName)
: ServiceMessageBuilder.testStdOut(myCurrentTestName);
super.processServiceMessages(builder.addAttribute("out", text).toString(), outputType, visitor);
return;
}
ServiceMessageBuilder messageBuilder = new ServiceMessageBuilder(ServiceMessageTypes.MESSAGE);
if (isErrorMessage) {
messageBuilder.addAttribute("text", StringUtil.trimEnd(text, "\n")).addAttribute("status", "ERROR");
}
else {
messageBuilder.addAttribute("text", text).addAttribute("status", "NORMAL");
}
super.processServiceMessages(messageBuilder.toString(), outputType, visitor);
}
@Override
public void dispose() {
myVisitor = null;
super.dispose();
}
protected void startTest(@NotNull String testName, @Nullable ServiceMessageVisitor visitor) throws ParseException {
if (isCurrentlyRunningTest(testName)) {
return;
}
finishDelayedTest(visitor);
myCurrentTestName = testName;
myCurrentTestResult = null;
myCurrentTestStart = System.currentTimeMillis();
String testStartedMessage = ServiceMessageBuilder.testStarted(testName).addAttribute("locationHint", testUrl(testName)).toString();
super.processServiceMessages(testStartedMessage, null, visitor);
}
@Override
public final void flushBufferBeforeTerminating() {
try {
if (!finishDelayedTest(myVisitor)) {
if (myCurrentTestName != null) {
finishTestInner(myCurrentTestName, TestResult.PASSED, myVisitor);
}
}
}
catch (ParseException ignore) {
}
myVisitor = null;
super.flushBufferBeforeTerminating();
}
protected void finishTest(@NotNull String name, @NotNull TestResult result, @Nullable ServiceMessageVisitor visitor)
throws ParseException {
if (isCurrentlyRunningTest(name)) {
if (myCurrentTestResult == null) {
// delay finishing test, we'll use it as a container for future output
myCurrentTestResult = result;
}
return;
}
finishTestInner(name, result, visitor);
}
protected boolean finishDelayedTest(ServiceMessageVisitor visitor) throws ParseException {
if (myCurrentTestName != null && myCurrentTestResult != null) {
finishTestInner(myCurrentTestName, myCurrentTestResult, visitor);
return true;
}
return false;
}
private boolean isCurrentlyRunningTest(@NotNull String testName) {
return testName.equals(myCurrentTestName);
}
private void finishTestInner(@NotNull String name,
@NotNull TestResult result,
@Nullable ServiceMessageVisitor visitor) throws ParseException {
if (isCurrentlyRunningTest(name)) {
myCurrentTestName = null;
myCurrentTestResult = null;
}
String duration = myCurrentTestStart > 0 ? Long.toString(System.currentTimeMillis() - myCurrentTestStart) : null;
switch (result) {
case PASSED:
break;
case FAILED:
String failedMessage = ServiceMessageBuilder.testFailed(name).addAttribute("message", "").toString();
super.processServiceMessages(failedMessage, null, visitor);
break;
case SKIPPED:
String skipMessage = ServiceMessageBuilder.testIgnored(name).addAttribute("message", "").toString();
super.processServiceMessages(skipMessage, null, visitor);
break;
}
String finishedMessage = ServiceMessageBuilder.testFinished(name).addAttribute("duration", duration).toString();
super.processServiceMessages(finishedMessage, null, visitor);
}
@NotNull
private static String testUrl(@NotNull String testName) {
return GoTestLocator.PROTOCOL + "://" + testName;
}
}