package net.thucydides.core.steps; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.inject.Inject; import net.thucydides.core.Thucydides; import net.thucydides.core.ThucydidesSystemProperty; import net.thucydides.core.logging.LoggingLevel; import net.thucydides.core.model.DataTable; import net.thucydides.core.model.Story; import net.thucydides.core.model.TestOutcome; import net.thucydides.core.util.EnvironmentVariables; import net.thucydides.core.util.NameConverter; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; public class ConsoleLoggingListener implements StepListener { // STAR WARS private static final List<String> BANNER_HEADINGS = ImmutableList.of( "\n--------------\n" + "- THUCYDIDES -\n" + "--------------", "\n\n-------------------------------------------------------------------------------------------------------\n" + ".___________. __ __ __ __ ______ ____ ____ _______ __ _______ _______ _______.\n" + "| || | | | | | | | / |\\ \\ / / | \\ | | | \\ | ____| / |\n" + "`---| |----`| |__| | | | | | | ,----' \\ \\/ / | .--. || | | .--. || |__ | (----`\n" + " | | | __ | | | | | | | \\_ _/ | | | || | | | | || __| \\ \\ \n" + " | | | | | | | `--' | | `----. | | | '--' || | | '--' || |____.----) | \n" + " |__| |__| |__| \\______/ \\______| |__| |_______/ |__| |_______/ |_______|_______/ \n" + " \n" + "-------------------------------------------------------------------------------------------------------\n"); // Standard private static final List<String> TEST_STARTED_HEADINGS = ImmutableList.of( "\n----------------\n" + "- TEST STARTED -\n" + "----------------", "\n _____ _____ ____ _____ ____ _____ _ ____ _____ _____ ____ \n" + " |_ _| ____/ ___|_ _| / ___|_ _|/ \\ | _ \\_ _| ____| _ \\ \n" + " | | | _| \\___ \\ | | \\___ \\ | | / _ \\ | |_) || | | _| | | | |\n" + " | | | |___ ___) || | ___) || |/ ___ \\| _ < | | | |___| |_| |\n" + " |_| |_____|____/ |_| |____/ |_/_/ \\_\\_| \\_\\|_| |_____|____/ \n" + " \n"); private static final List<String> TEST_PASSED_HEADINGS = ImmutableList.of( "\n---------------\n" + "- TEST PASSED -\n" + "---------------", "\n __ _____ _____ ____ _____ ____ _ ____ ____ _____ ____ \n" + " _ \\ \\ |_ _| ____/ ___|_ _| | _ \\ / \\ / ___|/ ___|| ____| _ \\ \n" + " (_)_____| | | | | _| \\___ \\ | | | |_) / _ \\ \\___ \\\\___ \\| _| | | | |\n" + " _|_____| | | | | |___ ___) || | | __/ ___ \\ ___) |___) | |___| |_| |\n" + " (_) | | |_| |_____|____/ |_| |_| /_/ \\_\\____/|____/|_____|____/ \n" + " /_/ \n"); private static final List<String> TEST_FAILED_HEADINGS = ImmutableList.of( "\n----------------\n" + "- TEST FAILED -\n" + "----------------", "\n __ _____ _____ ____ _____ _____ _ ___ _ _____ ____ \n" + " _ / / |_ _| ____/ ___|_ _| | ___/ \\ |_ _| | | ____| _ \\ \n" + " (_)_____| | | | | _| \\___ \\ | | | |_ / _ \\ | || | | _| | | | |\n" + " _|_____| | | | | |___ ___) || | | _/ ___ \\ | || |___| |___| |_| |\n" + " (_) | | |_| |_____|____/ |_| |_|/_/ \\_\\___|_____|_____|____/ \n" + " \\_\\ \n"); private static final List<String> TEST_SKIPPED_HEADINGS = ImmutableList.of( "\n----------------\n" + "- TEST SKIPPED -\n" + "----------------", "\n __ _____ _____ ____ _____ ____ _ _____ ____ ____ _____ ____ \n" + " _ / / |_ _| ____/ ___|_ _| / ___|| |/ /_ _| _ \\| _ \\| ____| _ \\ \n" + " (_)_____ / / | | | _| \\___ \\ | | \\___ \\| ' / | || |_) | |_) | _| | | | |\n" + " _|_____/ / | | | |___ ___) || | ___) | . \\ | || __/| __/| |___| |_| |\n" + " (_) /_/ |_| |_____|____/ |_| |____/|_|\\_\\___|_| |_| |_____|____/ \n" + " \n"); private static List<String> FAILURE_HEADINGS = ImmutableList.of( "\n-----------\n" + "- FAILURE -\n" + "-----------", "\n _____ _ ___ _ _ _ ____ _____ \n" + " | ___/ \\ |_ _| | | | | | _ \\| ____|\n" + " | |_ / _ \\ | || | | | | | |_) | _| \n" + " | _/ ___ \\ | || |___| |_| | _ <| |___ \n" + " |_|/_/ \\_\\___|_____|\\___/|_| \\_\\_____|\n" + " \n"); private final Logger logger; private final EnvironmentVariables environmentVariables; private final int headingStyle; private enum HeadingStyle { NORMAL, ASCII} public ConsoleLoggingListener(EnvironmentVariables environmentVariables, Logger logger) { this.logger = logger; this.environmentVariables = environmentVariables; String headerStyleValue = environmentVariables.getProperty(ThucydidesSystemProperty.THUCYDIDES_CONSOLE_HEADINGS, HeadingStyle.ASCII.toString()).toUpperCase(); if (HeadingStyle.NORMAL.toString().equals(headerStyleValue)) { headingStyle = 0; } else { headingStyle = 1; } logBanner(); } @Inject public ConsoleLoggingListener(EnvironmentVariables environmentVariables) { this(environmentVariables, LoggerFactory.getLogger(Thucydides.class)); } protected Logger getLogger() { return logger; } private void logBanner() { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(bannerHeading()); } } private String bannerHeading() { return BANNER_HEADINGS.get(headingStyle); } private boolean loggingLevelIsAtLeast(LoggingLevel minimumLoggingLevel) { return (getLoggingLevel().compareTo(minimumLoggingLevel) >= 0); } private LoggingLevel getLoggingLevel() { String logLevel = ThucydidesSystemProperty.THUCYDIDES_LOGGING.from(environmentVariables, LoggingLevel.NORMAL.name()); return LoggingLevel.valueOf(logLevel); } public void testSuiteStarted(Class<?> storyClass) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("Test Suite Started: " + NameConverter.humanize(storyClass.getSimpleName())); } } public void testSuiteStarted(Story story) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("Test Suite Started: " + NameConverter.humanize(story.getName())); } } public void testSuiteFinished() { } public void testStarted(String description) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(testStartedHeadings() + "\nTEST STARTED: " + description + underline(TEST_STARTED_HEADINGS.get(headingStyle))); } } private String testStartedHeadings() { return TEST_STARTED_HEADINGS.get(headingStyle); } private String underline(String banner) { StringBuilder underline = new StringBuilder(); int endOfLine = banner.indexOf('\n', 1); if (endOfLine >= 0) { underline.append(StringUtils.repeat('-', endOfLine)); } else { underline.append(StringUtils.repeat('-', banner.length())); } return "\n" + underline.toString(); } public void testFinished(TestOutcome result) { if (result.isFailure()) { logFailure(result); } else if (result.isPending()) { logPending(result); } else if (result.isSkipped()) { logSkipped(result); } else if (result.isSuccess()) { logSuccess(result); } } @Override public void testRetried() { } private void logFailure(TestOutcome result) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(testFailureHeading() + "\nTEST FAILED: " + result.getTitle() + underline(TEST_FAILED_HEADINGS.get(headingStyle))); logRelatedIssues(result); logFailureCause(result); underline(FAILURE_HEADINGS.get(headingStyle)); } } private String testFailureHeading() { return TEST_FAILED_HEADINGS.get(headingStyle); } private void logRelatedIssues(TestOutcome result) { Joiner joiner = Joiner.on(","); getLogger().info("RELATED ISSUES: " + joiner.join(result.getIssueKeys())); } private void logFailureCause(TestOutcome result) { if (result.getTestFailureMessage() != null) { getLogger().info(failureHeading() + "\n" + result.getTestFailureMessage()); } } private String failureHeading() { return FAILURE_HEADINGS.get(headingStyle); } private void logPending(TestOutcome result) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(testSkippedHeading() + "\nTEST PENDING: " + result.getTitle() + underline(testSkippedHeading())); } } private String testSkippedHeading() { return TEST_SKIPPED_HEADINGS.get(headingStyle); } private void logSkipped(TestOutcome result) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(testSkippedHeading() + "\nTEST SKIPPED: " + result.getTitle() + underline(testSkippedHeading())); } } private void logSuccess(TestOutcome result) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info(testPassedHeading() + "\nTEST PASSED: " + result.getTitle() + underline(testPassedHeading())); } } private String testPassedHeading() { return TEST_PASSED_HEADINGS.get(headingStyle); } public void stepStarted(ExecutedStepDescription description) { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("STARTING STEP " + description.getTitle()); } } public void skippedStepStarted(ExecutedStepDescription description) { stepStarted(description); } public void stepFinished() { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("FINISHING STEP"); } } public void stepFailed(StepFailure failure) { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("STEP FAILED: " + failure.getMessage()); } } public void lastStepFailed(StepFailure failure) { } public void stepIgnored() { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("IGNORING STEP"); } } public void stepPending() { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("PENDING STEP"); } } public void stepPending(String message) { if (loggingLevelIsAtLeast(getLoggingLevel().VERBOSE)) { getLogger().info("PENDING STEP " + "(" + message + ")"); } } public void testFailed(TestOutcome testOutcome, Throwable cause) { } public void testIgnored() { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("TEST IGNORED"); } } @Override public void testSkipped() { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("TEST SKIPPED"); } } @Override public void testPending() { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("TEST PENDING"); } } public void notifyScreenChange() { } public void useExamplesFrom(DataTable table) { } public void exampleStarted(Map<String,String> data) { } public void exampleFinished() { } @Override public void assumptionViolated(String message) { if (loggingLevelIsAtLeast(LoggingLevel.NORMAL)) { getLogger().info("ASSUMPTION VIOLATED"); } } }