diff --git a/plugins/cucumber-jvm-formatter/cucumber-jvm-formatter.iml b/plugins/cucumber-jvm-formatter/cucumber-jvm-formatter.iml index 349de40e6270..fd438454136e 100644 --- a/plugins/cucumber-jvm-formatter/cucumber-jvm-formatter.iml +++ b/plugins/cucumber-jvm-formatter/cucumber-jvm-formatter.iml @@ -8,5 +8,6 @@ + \ No newline at end of file diff --git a/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvm2SMFormatter.java b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvm2SMFormatter.java new file mode 100644 index 000000000000..ca3980e24e8a --- /dev/null +++ b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvm2SMFormatter.java @@ -0,0 +1,215 @@ +package org.jetbrains.plugins.cucumber.java.run; + +import cucumber.api.TestCase; +import cucumber.api.TestStep; +import cucumber.api.event.*; +import cucumber.api.formatter.Formatter; +import gherkin.events.PickleEvent; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import static cucumber.api.Result.Type.*; +import static org.jetbrains.plugins.cucumber.java.run.CucumberJvmSMFormatterUtil.*; + +@SuppressWarnings("unused") +public class CucumberJvm2SMFormatter implements Formatter { + private static final String EXAMPLES_CAPTION = "Examples:"; + private static final String SCENARIO_OUTLINE_CAPTION = "Scenario: Line: "; + private Map pathToDescription = new HashMap(); + private String currentFilePath; + private int currentScenarioOutlineLine; + private String currentScenarioOutlineName; + + public CucumberJvm2SMFormatter() { + outCommand(String.format(TEMPLATE_ENTER_THE_MATRIX, getCurrentTime())); + outCommand(String.format(TEMPLATE_SCENARIO_COUNTING_STARTED, 0, getCurrentTime())); + } + + private EventHandler testCaseStartedHandler = new EventHandler() { + public void receive(TestCaseStarted event) { + CucumberJvm2SMFormatter.this.handleTestCaseStarted(event); + } + }; + + private EventHandler testCaseFinishedHandler = new EventHandler() { + public void receive(TestCaseFinished event) { + handleTestCaseFinished(event); + } + }; + + private EventHandler testRunFinishedHandler = new EventHandler() { + public void receive(TestRunFinished event) { + CucumberJvm2SMFormatter.this.handleTestRunFinished(event); + } + }; + + private EventHandler testStepStartedHandler = new EventHandler() { + public void receive(TestStepStarted event) { + handleTestStepStarted(event); + } + }; + + private EventHandler testStepFinishedHandler = new EventHandler() { + public void receive(TestStepFinished event) { + handleTestStepFinished(event); + } + }; + + private EventHandler testSourceReadHandler = new EventHandler() { + public void receive(TestSourceRead event) { + CucumberJvm2SMFormatter.this.handleTestSourceRead(event); + } + }; + + @Override + public void setEventPublisher(EventPublisher publisher) { + publisher.registerHandlerFor(TestCaseStarted.class, this.testCaseStartedHandler); + publisher.registerHandlerFor(TestCaseFinished.class, this.testCaseFinishedHandler); + + publisher.registerHandlerFor(TestStepStarted.class, this.testStepStartedHandler); + publisher.registerHandlerFor(TestStepFinished.class, this.testStepFinishedHandler); + publisher.registerHandlerFor(TestSourceRead.class, this.testSourceReadHandler); + + publisher.registerHandlerFor(TestRunFinished.class, this.testRunFinishedHandler); + } + + private void handleTestCaseStarted(TestCaseStarted event) { + if (currentFilePath == null) { + outCommand(String.format(TEMPLATE_TEST_SUITE_STARTED, getCurrentTime(), event.testCase.getUri(), + getFeatureFileDescription(event.testCase.getUri()))); + } + else if (!event.testCase.getUri().equals(currentFilePath)) { + closeCurrentScenarioOutline(); + outCommand(String.format(TEMPLATE_TEST_SUITE_FINISHED, getCurrentTime(), + getFeatureFileDescription(currentFilePath))); + outCommand(String.format(TEMPLATE_TEST_SUITE_STARTED, getCurrentTime(), event.testCase.getUri(), + getFeatureFileDescription(event.testCase.getUri()))); + } + + if (isScenarioOutline(event.testCase)) { + int mainScenarioLine = getScenarioOutlineLine(event.testCase); + if (currentScenarioOutlineLine != mainScenarioLine || currentFilePath == null || + !currentFilePath.equals(event.testCase.getUri())) { + closeCurrentScenarioOutline(); + currentScenarioOutlineLine = mainScenarioLine; + currentScenarioOutlineName = event.testCase.getName(); + outCommand(String.format(TEMPLATE_TEST_SUITE_STARTED, getCurrentTime(), + event.testCase.getUri() + ":" + currentScenarioOutlineLine, currentScenarioOutlineName)); + outCommand(String.format(TEMPLATE_TEST_SUITE_STARTED, getCurrentTime(), "", EXAMPLES_CAPTION)); + } + } else { + closeCurrentScenarioOutline(); + } + currentFilePath = event.testCase.getUri(); + + outCommand(String.format(TEMPLATE_TEST_SUITE_STARTED, getCurrentTime(), + event.testCase.getUri() + ":" + event.testCase.getLine(), getScenarioName(event.testCase))); + } + + private static void handleTestCaseFinished(TestCaseFinished event) { + outCommand(String.format(TEMPLATE_TEST_SUITE_FINISHED, getCurrentTime(), getScenarioName(event.testCase))); + } + + private void handleTestRunFinished(TestRunFinished event) { + closeCurrentScenarioOutline(); + outCommand(String.format(TEMPLATE_TEST_SUITE_FINISHED, getCurrentTime(), + getFeatureFileDescription(currentFilePath))); + } + private static void handleTestStepStarted(TestStepStarted event) { + if (event.testStep.isHook()) { + return; + } + + outCommand(String.format(TEMPLATE_TEST_STARTED, getCurrentTime(), getStepLocation(event.testStep), + getStepName(event.testStep))); + } + + private static void handleTestStepFinished(TestStepFinished event) { + if (event.testStep.isHook()) { + return; + } + if (event.result.getStatus() == PASSED) { + // write nothing + } else if (event.result.getStatus() == SKIPPED || event.result.getStatus() == PENDING) { + outCommand(String.format(TEMPLATE_TEST_PENDING, getStepName(event.testStep), getCurrentTime())); + } else { + outCommand(String.format(TEMPLATE_TEST_FAILED, getCurrentTime(), "", + escape(event.result.getErrorMessage()), getStepName(event.testStep), "")); + } + Long duration = event.result.getDuration() != null ? event.result.getDuration() / 1000000: 0; + outCommand(String.format(TEMPLATE_TEST_FINISHED, getCurrentTime(), duration, getStepName(event.testStep))); + } + + private String getFeatureFileDescription(String uri) { + if (pathToDescription.containsKey(uri)) { + return pathToDescription.get(uri); + } + return uri; + } + + private void handleTestSourceRead(TestSourceRead event) { + closeCurrentScenarioOutline(); + + String[] lines = event.source.split("\n"); + if (lines.length > 0) { + pathToDescription.put(event.uri, lines[0]); + } else { + pathToDescription.put(event.uri, event.source); + } + } + + private void closeCurrentScenarioOutline() { + if (currentScenarioOutlineLine > 0) { + outCommand(String.format(TEMPLATE_TEST_SUITE_FINISHED, getCurrentTime(), EXAMPLES_CAPTION)); + outCommand(String.format(TEMPLATE_TEST_SUITE_FINISHED, getCurrentTime(), currentScenarioOutlineName)); + currentScenarioOutlineLine = 0; + currentScenarioOutlineName = null; + } + } + + private static String getStepLocation(TestStep step) { + return step.getStepLocation() + ":" + step.getStepLine(); + } + + private static String getStepName(TestStep step) { + return step.getStepText(); + } + + private static void outCommand(String s) { + //noinspection UseOfSystemOutOrSystemErr + System.out.println(s); + } + + private static PickleEvent getPickleEvent(TestCase testCase) { + try { + Field pickleEventField = TestCase.class.getDeclaredField("pickleEvent"); + pickleEventField.setAccessible(true); + return (PickleEvent)pickleEventField.get(testCase); + } + catch (Exception ignored) { + } + return null; + } + + private static boolean isScenarioOutline(TestCase testCase) { + PickleEvent pickleEvent = getPickleEvent(testCase); + return pickleEvent != null && pickleEvent.pickle.getLocations().size() > 1; + } + + private static int getScenarioOutlineLine(TestCase testCase) { + PickleEvent pickleEvent = getPickleEvent(testCase); + if (pickleEvent != null) { + return pickleEvent.pickle.getLocations().get(pickleEvent.pickle.getLocations().size() - 1).getLine(); + } + return 0; + } + + private static String getScenarioName(TestCase testCase) { + if (isScenarioOutline(testCase)) { + return SCENARIO_OUTLINE_CAPTION + testCase.getLine(); + } + return testCase.getName(); + } +} diff --git a/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatter.java b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatter.java index 46c4220049e6..d7234b755c6e 100644 --- a/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatter.java +++ b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatter.java @@ -7,14 +7,13 @@ import gherkin.formatter.model.*; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.text.SimpleDateFormat; import java.util.ArrayDeque; -import java.util.Date; import java.util.List; import java.util.Queue; +import static org.jetbrains.plugins.cucumber.java.run.CucumberJvmSMFormatterUtil.*; + public class CucumberJvmSMFormatter implements Formatter, Reporter { - public static final String TEAMCITY_PREFIX = "##teamcity"; public static final int MILLION = 1000000; private int scenarioCount; private int passedScenarioCount; @@ -28,33 +27,6 @@ public class CucumberJvmSMFormatter implements Formatter, Reporter { private int undefinedStepCount; private boolean endedByNewLine = true; - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ"); - - private static final String TEMPLATE_TEST_STARTED = - TEAMCITY_PREFIX + "[testStarted timestamp = '%s' locationHint = 'file:///%s' captureStandardOutput = 'true' name = '%s']"; - private static final String TEMPLATE_TEST_FAILED = - TEAMCITY_PREFIX + "[testFailed timestamp = '%s' details = '%s' message = '%s' name = '%s' %s]"; - private static final String TEMPLATE_SCENARIO_FAILED = TEAMCITY_PREFIX + "[customProgressStatus timestamp='%s' type='testFailed']"; - private static final String TEMPLATE_TEST_PENDING = - TEAMCITY_PREFIX + "[testIgnored name = '%s' message = 'Skipped step' timestamp = '%s']"; - - private static final String TEMPLATE_TEST_FINISHED = - TEAMCITY_PREFIX + - "[testFinished timestamp = '%s' duration = '%s' name = '%s']"; - - private static final String TEMPLATE_ENTER_THE_MATRIX = TEAMCITY_PREFIX + "[enteredTheMatrix timestamp = '%s']"; - - private static final String TEMPLATE_TEST_SUITE_STARTED = - TEAMCITY_PREFIX + "[testSuiteStarted timestamp = '%s' locationHint = 'file://%s' name = '%s']"; - private static final String TEMPLATE_TEST_SUITE_FINISHED = TEAMCITY_PREFIX + "[testSuiteFinished timestamp = '%s' name = '%s']"; - - private static final String TEMPLATE_SCENARIO_COUNTING_STARTED = - TEAMCITY_PREFIX + "[customProgressStatus testsCategory = 'Scenarios' count = '%s' timestamp = '%s']"; - private static final String TEMPLATE_SCENARIO_COUNTING_FINISHED = - TEAMCITY_PREFIX + "[customProgressStatus testsCategory = '' count = '0' timestamp = '%s']"; - private static final String TEMPLATE_SCENARIO_STARTED = TEAMCITY_PREFIX + "[customProgressStatus type = 'testStarted' timestamp = '%s']"; - private static final String TEMPLATE_SCENARIO_FINISHED = TEAMCITY_PREFIX + "[customProgressStatus type = 'testFinished' timestamp = '%s']"; - public static final String RESULT_STATUS_PENDING = "pending"; private Appendable appendable; @@ -300,14 +272,6 @@ public class CucumberJvmSMFormatter implements Formatter, Reporter { public void before(Match match, Result result) { } - private static String getCurrentTime() { - return DATE_FORMAT.format(new Date()); - } - - private static String escape(String source) { - return source.replace("|", "||").replace("\n", "|n").replace("\r", "|r").replace("'", "|'").replace("[", "|[").replace("]", "|]"); - } - private void outCommand(String s) { outCommand(s, false); } diff --git a/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatterUtil.java b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatterUtil.java new file mode 100644 index 000000000000..c201cafdf31b --- /dev/null +++ b/plugins/cucumber-jvm-formatter/src/org/jetbrains/plugins/cucumber/java/run/CucumberJvmSMFormatterUtil.java @@ -0,0 +1,43 @@ +package org.jetbrains.plugins.cucumber.java.run; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CucumberJvmSMFormatterUtil { + public static final String TEAMCITY_PREFIX = "##teamcity"; + + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ"); + + public static final String TEMPLATE_TEST_STARTED = + TEAMCITY_PREFIX + "[testStarted timestamp = '%s' locationHint = 'file:///%s' captureStandardOutput = 'true' name = '%s']"; + public static final String TEMPLATE_TEST_FAILED = + TEAMCITY_PREFIX + "[testFailed timestamp = '%s' details = '%s' message = '%s' name = '%s' %s]"; + public static final String TEMPLATE_SCENARIO_FAILED = TEAMCITY_PREFIX + "[customProgressStatus timestamp='%s' type='testFailed']"; + public static final String TEMPLATE_TEST_PENDING = + TEAMCITY_PREFIX + "[testIgnored name = '%s' message = 'Skipped step' timestamp = '%s']"; + + public static final String TEMPLATE_TEST_FINISHED = + TEAMCITY_PREFIX + + "[testFinished timestamp = '%s' duration = '%s' name = '%s']"; + + public static final String TEMPLATE_ENTER_THE_MATRIX = TEAMCITY_PREFIX + "[enteredTheMatrix timestamp = '%s']"; + + public static final String TEMPLATE_TEST_SUITE_STARTED = + TEAMCITY_PREFIX + "[testSuiteStarted timestamp = '%s' locationHint = 'file://%s' name = '%s']"; + public static final String TEMPLATE_TEST_SUITE_FINISHED = TEAMCITY_PREFIX + "[testSuiteFinished timestamp = '%s' name = '%s']"; + + public static final String TEMPLATE_SCENARIO_COUNTING_STARTED = + TEAMCITY_PREFIX + "[customProgressStatus testsCategory = 'Scenarios' count = '%s' timestamp = '%s']"; + public static final String TEMPLATE_SCENARIO_COUNTING_FINISHED = + TEAMCITY_PREFIX + "[customProgressStatus testsCategory = '' count = '0' timestamp = '%s']"; + public static final String TEMPLATE_SCENARIO_STARTED = TEAMCITY_PREFIX + "[customProgressStatus type = 'testStarted' timestamp = '%s']"; + public static final String TEMPLATE_SCENARIO_FINISHED = TEAMCITY_PREFIX + "[customProgressStatus type = 'testFinished' timestamp = '%s']"; + + public static String getCurrentTime() { + return DATE_FORMAT.format(new Date()); + } + + public static String escape(String source) { + return source.replace("|", "||").replace("\n", "|n").replace("\r", "|r").replace("'", "|'").replace("[", "|[").replace("]", "|]"); + } +}