package org.jbehave.core.reporters;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.jbehave.core.configuration.Keywords;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.BLUE;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.BOLD;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.GREEN;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.MAGENTA;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.RED;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.RESET;
import static org.jbehave.core.reporters.ANSIConsoleOutput.SGRCode.YELLOW;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_END;
import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_START;
/**
* <p>
* Story reporter that outputs as ANSI-coded text to System.out.
* </p>
*/
public class ANSIConsoleOutput extends ConsoleOutput {
private static final char ESCAPE_CHARACTER = (char) 27;
private static final String SGR_CONTROL = "m";
private static final String CODE_SEPARATOR = ";";
@SuppressWarnings("serial")
private Map<String, SGRCode> codes = new HashMap<String, SGRCode>() {
{
put("successful", GREEN);
put("pending", YELLOW);
put("pendingMethod", YELLOW);
put("notPerformed", MAGENTA);
put("ignorable", BLUE);
put("failed", RED);
put("cancelled", RED);
put("restarted", MAGENTA);
}
};
public ANSIConsoleOutput() {
super();
}
public ANSIConsoleOutput(Keywords keywords) {
super(keywords);
}
public ANSIConsoleOutput(Properties outputPatterns, Keywords keywords, boolean reportFailureTrace) {
super(outputPatterns, keywords, reportFailureTrace);
}
@Override
protected String format(String eventKey, String defaultPattern, Object... args) {
final String formatted = super.format(eventKey, defaultPattern, args);
if (codes.containsKey(eventKey)) {
SGRCode code = codes.get(eventKey);
return escapeCodeFor(code) + boldifyParams(formatted, code) + escapeCodeFor(RESET);
}
return formatted;
}
private String boldifyParams(String formatted, SGRCode currentColor) {
final String valueStart = lookupPattern(PARAMETER_VALUE_START, PARAMETER_VALUE_START);
final String valueEnd = lookupPattern(PARAMETER_VALUE_END, PARAMETER_VALUE_END);
return formatted
.replaceAll(valueStart, escapeCodeFor(BOLD, currentColor))
.replaceAll(valueEnd, escapeCodeFor(RESET, currentColor));
}
private String escapeCodeFor(SGRCode code) {
return controlSequenceInitiator(code + SGR_CONTROL);
}
private String escapeCodeFor(SGRCode first, SGRCode second) {
return controlSequenceInitiator(first + CODE_SEPARATOR + second + SGR_CONTROL);
}
private String controlSequenceInitiator(String code) {
return ESCAPE_CHARACTER + "[" + code;
}
public void assignCodeToEvent(String eventKey, SGRCode code) {
codes.put(eventKey, code);
}
public static enum SGRCode {
RESET(0),
BOLD(1),
DARK(2),
ITALIC(3),
UNDERLINE(4),
BLINK(5),
RAPID_BLINK(6),
NEGATIVE(7),
CONCEALED(8),
STRIKETHROUGH(9),
BLACK(30),
RED(31),
GREEN(32),
YELLOW(33),
BLUE(34),
MAGENTA(35),
CYAN(36),
WHITE(37),
ON_BLACK(40),
ON_RED(41),
ON_GREEN(42),
ON_YELLOW(43),
ON_BLUE(44),
ON_MAGENTA(45),
ON_CYAN(46),
ON_WHITE(47);
private final int code;
SGRCode(int code) {
this.code = code;
}
@Override
public String toString() {
return Integer.toString(code);
}
}
}