blob: d36250191b09b916f858522aa032a18bacdef933 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* 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.intellij.execution.testframework.sm.runner.ui;
import com.intellij.execution.process.AnsiEscapeDecoder;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.testframework.PoolOfTestIcons;
import com.intellij.execution.testframework.Printer;
import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.execution.testframework.TestsUIUtil;
import com.intellij.execution.testframework.sm.SMTestsRunnerBundle;
import com.intellij.execution.testframework.sm.runner.SMTestProxy;
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
import com.intellij.execution.testframework.ui.TestsProgressAnimator;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Set;
import static com.intellij.execution.testframework.sm.runner.ui.SMPoolOfTestIcons.*;
/**
* @author Roman Chernyatchik
*/
public class TestsPresentationUtil {
@NonNls private static final String DOUBLE_SPACE = " ";
@NonNls private static final String SECONDS_SUFFIX = " " + SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.seconds");
@NonNls private static final String MILLISECONDS_SUFFIX = " " + SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.milliseconds");
@NonNls private static final String WORLD_CREATION_TIME = "0" + SECONDS_SUFFIX;
@NonNls private static final String DURATION_UNKNOWN = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.duration.unknown");
@NonNls private static final String DURATION_NO_TESTS = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.duration.no.tests");
@NonNls private static final String DURATION_NOT_RUN = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.duration.not.run");
@NonNls private static final String DURATION_RUNNING_PREFIX = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.duration.prefix.running");
@NonNls private static final String DURATION_TERMINATED_PREFIX = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.duration.prefix.terminated");
@NonNls private static final String COLON = ": ";
public static final SimpleTextAttributes PASSED_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, TestsUIUtil.PASSED_COLOR);
public static final SimpleTextAttributes DEFFECT_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, Color.RED);
public static final SimpleTextAttributes TERMINATED_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, Color.ORANGE);
@NonNls private static final String RESULTS_NO_TESTS = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.results.no.tests");
@NonNls private static final String NO_NAME_TEST = SMTestsRunnerBundle.message(
"sm.test.runner.ui.tests.tree.presentation.labels.test.noname");
@NonNls private static final String UNKNOWN_TESTS_COUNT = "<...>";
@NonNls static final String DEFAULT_TESTS_CATEGORY = "Tests";
private TestsPresentationUtil() {
}
public static String getProgressStatus_Text(final long startTime,
final long endTime,
final int testsTotal,
final int testsCount,
final int failuresCount,
@Nullable final Set<String> allCategories,
final boolean isFinished) {
final StringBuilder sb = new StringBuilder();
if (endTime == 0) {
sb.append(SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.running"));
} else {
sb.append(SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.done"));
}
if (allCategories != null) {
// if all categories is just one default tests category - let's do not add prefixes
if (allCategories.size() > 1
|| (allCategories.size() == 1 && !DEFAULT_TESTS_CATEGORY.equals(allCategories.iterator().next()))) {
sb.append(' ');
boolean first = true;
for (String category : allCategories) {
if (StringUtil.isEmpty(category)) {
continue;
}
// separator
if (!first) {
sb.append(", ");
}
// first symbol - to lower case
final char firstChar = category.charAt(0);
sb.append(first ? firstChar : Character.toLowerCase(firstChar));
sb.append(category.substring(1));
first = false;
}
}
}
sb.append(' ').append(testsCount).append(' ');
sb.append(SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.of"));
sb.append(' ').append(testsTotal != 0 ? testsTotal
: !isFinished ? UNKNOWN_TESTS_COUNT : 0);
if (failuresCount > 0) {
sb.append(DOUBLE_SPACE);
sb.append(SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.failed"));
sb.append(' ').append(failuresCount);
}
if (endTime != 0) {
final long time = endTime - startTime;
sb.append(DOUBLE_SPACE);
sb.append('(').append(convertToSecondsOrMs(time)).append(')');
}
sb.append(DOUBLE_SPACE);
return sb.toString();
}
public static void formatRootNodeWithChildren(final SMTestProxy.SMRootTestProxy testProxy,
final TestTreeRenderer renderer) {
renderer.setIcon(getIcon(testProxy, renderer.getConsoleProperties()));
final TestStateInfo.Magnitude magnitude = testProxy.getMagnitudeInfo();
final String text;
if (magnitude == TestStateInfo.Magnitude.RUNNING_INDEX) {
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.running.tests");
} else if (magnitude == TestStateInfo.Magnitude.TERMINATED_INDEX) {
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.was.terminated");
} else {
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.test.results");
}
renderer.append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
public static void formatRootNodeWithoutChildren(final SMTestProxy.SMRootTestProxy testProxy,
final TestTreeRenderer renderer) {
final TestStateInfo.Magnitude magnitude = testProxy.getMagnitudeInfo();
if (magnitude == TestStateInfo.Magnitude.RUNNING_INDEX) {
renderer.setIcon(getIcon(testProxy, renderer.getConsoleProperties()));
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tests.tree.presentation.labels.instantiating.tests"),
SimpleTextAttributes.REGULAR_ATTRIBUTES);
} else if (magnitude == TestStateInfo.Magnitude.NOT_RUN_INDEX) {
renderer.setIcon(PoolOfTestIcons.NOT_RAN);
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tests.tree.presentation.labels.not.test.results"),
SimpleTextAttributes.ERROR_ATTRIBUTES);
} else if (magnitude == TestStateInfo.Magnitude.TERMINATED_INDEX) {
renderer.setIcon(PoolOfTestIcons.TERMINATED_ICON);
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tests.tree.presentation.labels.was.terminated"),
SimpleTextAttributes.REGULAR_ATTRIBUTES);
} else if (magnitude == TestStateInfo.Magnitude.PASSED_INDEX) {
renderer.setIcon(PoolOfTestIcons.PASSED_ICON);
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tests.tree.presentation.labels.all.tests.passed"),
SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
else {
if (!testProxy.getChildren().isEmpty()) {
// some times test proxy may be updated faster than tests tree
// so let's process such situation correctly
formatRootNodeWithChildren(testProxy, renderer);
}
else {
renderer.setIcon(PoolOfTestIcons.NOT_RAN);
renderer.append(testProxy.isTestsReporterAttached()
? SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found")
: SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.test.reporter.not.attached"),
SimpleTextAttributes.ERROR_ATTRIBUTES);
}
}
}
public static void formatTestProxy(final SMTestProxy testProxy,
final TestTreeRenderer renderer) {
renderer.setIcon(getIcon(testProxy, renderer.getConsoleProperties()));
renderer.append(testProxy.getPresentableName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
@NotNull
public static String getPresentableName(final SMTestProxy testProxy) {
final SMTestProxy parent = testProxy.getParent();
final String name = testProxy.getName();
String presentationCandidate = name;
if (parent != null) {
final String parentName = parent.getName();
if (name.startsWith(parentName)) {
presentationCandidate = name.substring(parentName.length());
// remove "." separator
if (presentationCandidate.startsWith(".")) {
presentationCandidate = presentationCandidate.substring(1);
}
}
}
// trim
presentationCandidate = presentationCandidate.trim();
// remove extra spaces
presentationCandidate = presentationCandidate.replaceAll("\\s+", " ");
if (StringUtil.isEmpty(presentationCandidate)) {
return NO_NAME_TEST;
}
return presentationCandidate;
}
@NotNull
public static String getPresentableNameTrimmedOnly(@NotNull SMTestProxy testProxy) {
String name = testProxy.getName();
if (name != null) {
name = name.trim();
}
if (name == null || name.isEmpty()) {
name = NO_NAME_TEST;
}
return name;
}
@Nullable
private static Icon getIcon(final SMTestProxy testProxy,
final TestConsoleProperties consoleProperties) {
final TestStateInfo.Magnitude magnitude = testProxy.getMagnitudeInfo();
final boolean hasErrors = testProxy.hasErrors();
switch (magnitude) {
case ERROR_INDEX:
return ERROR_ICON;
case FAILED_INDEX:
return hasErrors ? FAILED_E_ICON : FAILED_ICON;
case IGNORED_INDEX:
return hasErrors ? IGNORED_E_ICON : IGNORED_ICON;
case NOT_RUN_INDEX:
return NOT_RAN;
case COMPLETE_INDEX:
case PASSED_INDEX:
return hasErrors ? PASSED_E_ICON : PASSED_ICON;
case RUNNING_INDEX:
if (consoleProperties.isPaused()) {
return hasErrors ? PAUSED_E_ICON : AllIcons.RunConfigurations.TestPaused;
}
else {
final int frameIndex = TestsProgressAnimator.getCurrentFrameIndex();
return hasErrors ? FRAMES_E[frameIndex] : TestsProgressAnimator.FRAMES[frameIndex];
}
case SKIPPED_INDEX:
return hasErrors ? SKIPPED_E_ICON : SKIPPED_ICON;
case TERMINATED_INDEX:
return hasErrors ? TERMINATED_E_ICON : TERMINATED_ICON;
}
return null;
}
@Nullable
public static String getTestStatusPresentation(final SMTestProxy proxy) {
return proxy.getMagnitudeInfo().getTitle();
}
public static void appendSuiteStatusColorPresentation(final SMTestProxy proxy,
final ColoredTableCellRenderer renderer) {
int passedCount = 0;
int errorsCount = 0;
int failedCount = 0;
int ignoredCount = 0;
if (proxy.isLeaf()) {
// If suite is empty show <no tests> label and exit from method
renderer.append(RESULTS_NO_TESTS, proxy.wasLaunched() ? PASSED_ATTRIBUTES : DEFFECT_ATTRIBUTES);
return;
}
final List<SMTestProxy> allTestCases = proxy.getAllTests();
for (SMTestProxy testOrSuite : allTestCases) {
// we should ignore test suites
if (testOrSuite.isSuite()) {
continue;
}
// if test check it state
switch (testOrSuite.getMagnitudeInfo()) {
case COMPLETE_INDEX:
case PASSED_INDEX:
passedCount++;
break;
case ERROR_INDEX:
errorsCount++;
break;
case FAILED_INDEX:
failedCount++;
break;
case IGNORED_INDEX:
case SKIPPED_INDEX:
ignoredCount++;
break;
case NOT_RUN_INDEX:
case TERMINATED_INDEX:
case RUNNING_INDEX:
//Do nothing
break;
}
}
final String separator = " ";
if (failedCount > 0) {
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.results.count.msg.failed",
failedCount) + separator,
DEFFECT_ATTRIBUTES);
}
if (errorsCount > 0) {
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.results.count.msg.errors",
errorsCount) + separator,
DEFFECT_ATTRIBUTES);
}
if (ignoredCount > 0) {
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.results.count.msg.ignored",
ignoredCount) + separator,
SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
}
if (passedCount > 0) {
renderer.append(SMTestsRunnerBundle.message(
"sm.test.runner.ui.tabs.statistics.columns.results.count.msg.passed",
passedCount),
PASSED_ATTRIBUTES);
}
}
/**
* @param proxy Test or Suite
* @return Duration presentation for given proxy
*/
@Nullable
public static String getDurationPresentation(final SMTestProxy proxy) {
switch (proxy.getMagnitudeInfo()) {
case COMPLETE_INDEX:
case PASSED_INDEX:
case FAILED_INDEX:
case ERROR_INDEX:
case IGNORED_INDEX:
case SKIPPED_INDEX:
return getDurationTimePresentation(proxy);
case NOT_RUN_INDEX:
return DURATION_NOT_RUN;
case RUNNING_INDEX:
return getDurationWithPrefixPresentation(proxy, DURATION_RUNNING_PREFIX);
case TERMINATED_INDEX:
return getDurationWithPrefixPresentation(proxy, DURATION_TERMINATED_PREFIX);
default:
return DURATION_UNKNOWN;
}
}
private static String getDurationWithPrefixPresentation(final SMTestProxy proxy,
final String prefix) {
// If duration is known
if (proxy.getDuration() != null) {
return prefix + COLON + getDurationTimePresentation(proxy);
}
return '<' + prefix + '>';
}
private static String getDurationTimePresentation(final SMTestProxy proxy) {
final Long duration = proxy.getDuration();
if (duration == null) {
// if suite without children
return proxy.isSuite() && proxy.isLeaf()
? DURATION_NO_TESTS
: DURATION_UNKNOWN;
} else {
return convertToSecondsOrMs(duration.longValue());
}
}
/**
* @param duration In milliseconds
* @return Value in seconds or millisecond depending on its value
*/
private static String convertToSecondsOrMs(@NotNull final Long duration) {
if (duration == 0) {
return WORLD_CREATION_TIME;
} else if (duration < 100) {
return String.valueOf(duration) + MILLISECONDS_SUFFIX;
} else {
return String.valueOf(duration.floatValue() / 1000) + SECONDS_SUFFIX;
}
}
public static void appendTestStatusColorPresentation(final SMTestProxy proxy,
final ColoredTableCellRenderer renderer) {
final String title = getTestStatusPresentation(proxy);
final TestStateInfo.Magnitude info = proxy.getMagnitudeInfo();
switch (info) {
case COMPLETE_INDEX:
case PASSED_INDEX:
renderer.append(title, PASSED_ATTRIBUTES);
break;
case RUNNING_INDEX:
renderer.append(title, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
break;
case NOT_RUN_INDEX:
renderer.append(title, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
break;
case IGNORED_INDEX:
case SKIPPED_INDEX:
renderer.append(title, SimpleTextAttributes.EXCLUDED_ATTRIBUTES);
break;
case ERROR_INDEX:
case FAILED_INDEX:
renderer.append(title, DEFFECT_ATTRIBUTES);
break;
case TERMINATED_INDEX:
renderer.append(title, TERMINATED_ATTRIBUTES);
break;
}
}
public static void printWithAnsiColoring(@NotNull final Printer printer, @NotNull String text, @NotNull final Key processOutputType) {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText(text, ProcessOutputTypes.STDOUT, new AnsiEscapeDecoder.ColoredTextAcceptor() {
@Override
public void coloredTextAvailable(String text, Key attributes) {
ConsoleViewContentType contentType = ConsoleViewContentType.getConsoleViewType(attributes);
if (contentType == null || contentType == ConsoleViewContentType.NORMAL_OUTPUT) {
contentType = ConsoleViewContentType.getConsoleViewType(processOutputType);
}
printer.print(text, contentType);
}
});
}
}