diff --git a/core/src/main/java/cucumber/api/Scenario.java b/core/src/main/java/cucumber/api/Scenario.java index a97ddda6b1..f3706a2440 100644 --- a/core/src/main/java/cucumber/api/Scenario.java +++ b/core/src/main/java/cucumber/api/Scenario.java @@ -1,6 +1,7 @@ package cucumber.api; import java.util.Collection; +import java.util.List; /** * Before or After Hooks that declare a parameter of this type will receive an instance of this class. @@ -51,4 +52,20 @@ public interface Scenario { * @return the name of the Scenario */ String getName(); + + /** + * @return the id of the Scenario. + */ + String getId(); + + /** + * @return the uri of the feature file of the Scenario. + */ + String getUri(); + + /** + * @return the line(s) in the feature file of the Scenario. Scenarios form Scenario Outlines + * return both the line of the example row the the line of the scenario outline. + */ + List getLines(); } diff --git a/core/src/main/java/cucumber/api/TestCase.java b/core/src/main/java/cucumber/api/TestCase.java index 368a8dacd8..8398072566 100644 --- a/core/src/main/java/cucumber/api/TestCase.java +++ b/core/src/main/java/cucumber/api/TestCase.java @@ -23,7 +23,7 @@ public void run(EventBus bus) { boolean skipNextStep = false; Long startTime = bus.getTime(); bus.send(new TestCaseStarted(startTime, this)); - ScenarioImpl scenarioResult = new ScenarioImpl(bus, pickleEvent.pickle); + ScenarioImpl scenarioResult = new ScenarioImpl(bus, pickleEvent); for (TestStep step : testSteps) { Result stepResult = step.run(bus, pickleEvent.pickle.getLanguage(), scenarioResult, skipNextStep); if (!stepResult.is(Result.Type.PASSED)) { diff --git a/core/src/main/java/cucumber/runtime/ScenarioImpl.java b/core/src/main/java/cucumber/runtime/ScenarioImpl.java index d1e8424b62..b197f6f043 100644 --- a/core/src/main/java/cucumber/runtime/ScenarioImpl.java +++ b/core/src/main/java/cucumber/runtime/ScenarioImpl.java @@ -5,11 +5,14 @@ import cucumber.api.event.EmbedEvent; import cucumber.api.event.WriteEvent; import cucumber.runner.EventBus; +import gherkin.events.PickleEvent; import gherkin.pickles.Pickle; +import gherkin.pickles.PickleLocation; import gherkin.pickles.PickleTag; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -20,13 +23,25 @@ public class ScenarioImpl implements Scenario { private static final List SEVERITY = asList(Result.Type.PASSED, Result.Type.SKIPPED, Result.Type.PENDING, Result.Type.UNDEFINED, Result.Type.FAILED); private final List stepResults = new ArrayList(); private final List tags; + private final String uri; private final String scenarioName; + private final String scenarioId; + private final List scenarioLines; private final EventBus bus; - public ScenarioImpl(EventBus bus, Pickle gherkinScenario) { + public ScenarioImpl(EventBus bus, PickleEvent pickleEvent) { this.bus = bus; - this.tags = gherkinScenario.getTags(); - this.scenarioName = gherkinScenario.getName(); + Pickle pickle = pickleEvent.pickle; + this.tags = pickle.getTags(); + this.uri = pickleEvent.uri; + this.scenarioName = pickle.getName(); + List locations = pickle.getLocations(); + this.scenarioId = pickleEvent.uri + ":" + Integer.toString(locations.get(0).getLine()); + ArrayList lines = new ArrayList(); + for (PickleLocation location : locations) { + lines.add(location.getLine()); + } + this.scenarioLines = Collections.unmodifiableList(lines); } public void add(Result result) { @@ -76,6 +91,21 @@ public String getName() { return scenarioName; } + @Override + public String getId() { + return scenarioId; + } + + @Override + public String getUri() { + return uri; + } + + @Override + public List getLines() { + return scenarioLines; + } + public Throwable getError() { Throwable error = null; int maxPos = 0; diff --git a/core/src/test/java/cucumber/api/ScenarioTest.java b/core/src/test/java/cucumber/api/ScenarioTest.java new file mode 100644 index 0000000000..fd73c30b63 --- /dev/null +++ b/core/src/test/java/cucumber/api/ScenarioTest.java @@ -0,0 +1,91 @@ +package cucumber.api; + +import cucumber.runner.EventBus; +import cucumber.runtime.ScenarioImpl; +import gherkin.events.PickleEvent; +import gherkin.pickles.Pickle; +import gherkin.pickles.PickleLocation; +import org.junit.Test; + +import java.util.List; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ScenarioTest { + + @Test + public void provides_the_uri_of_the_feature_file() { + Scenario scenario = createScenarioWithFeatureFileUri(uri("path/file.feature")); + + assertEquals("path/file.feature", scenario.getUri()); + } + + @Test + public void provides_the_scenario_line() { + List scenarioLocation = asList(new PickleLocation(line(3), column(2))); + Scenario scenario = createScenarioWithScenarioLocations(scenarioLocation); + + assertEquals(asList(3), scenario.getLines()); + } + + @Test + public void provides_both_the_example_row_line_and_scenario_outline_line_for_scenarios_from_scenario_outlines() { + List scenarioLocation = asList(new PickleLocation(line(8), column(4)), new PickleLocation(line(3), column(2))); + Scenario scenario = createScenarioWithScenarioLocations(scenarioLocation); + + assertEquals(asList(8, 3), scenario.getLines()); + } + + @Test + public void provides_the_uri_and_scenario_line_as_unique_id() { + List scenarioLocation = asList(new PickleLocation(line(3), column(2))); + Scenario scenario = createScenarioWithFeatureFileUriAndScenarioLocations(uri("path/file.feature"), scenarioLocation); + + assertEquals("path/file.feature:3", scenario.getId()); + } + + @Test + public void provides_the_uri_and_example_row_line_as_unique_id_for_scenarios_from_scenario_outlines() { + List scenarioLocation = asList(new PickleLocation(line(8), column(4)), new PickleLocation(line(3), column(2))); + Scenario scenario = createScenarioWithFeatureFileUriAndScenarioLocations(uri("path/file.feature"), scenarioLocation); + + assertEquals("path/file.feature:8", scenario.getId()); + } + + private Scenario createScenarioWithFeatureFileUri(String uri) { + return new ScenarioImpl(mock(EventBus.class), new PickleEvent(uri, mockPickle())); + } + + private Scenario createScenarioWithFeatureFileUriAndScenarioLocations(String uri, List locations) { + return new ScenarioImpl(mock(EventBus.class), new PickleEvent(uri, mockPickle(locations))); + } + + private Scenario createScenarioWithScenarioLocations(List locations) { + return new ScenarioImpl(mock(EventBus.class), new PickleEvent("uri", mockPickle(locations))); + } + + private Pickle mockPickle() { + return mockPickle(asList(new PickleLocation(1, 1))); + } + + private Pickle mockPickle(List locations) { + Pickle pickle = mock(Pickle.class); + when(pickle.getLocations()).thenReturn(locations); + return pickle; + } + + private String uri(String uri) { + return uri; + } + + private int line(int line) { + return line; + } + + private int column(int column) { + return column; + } +} diff --git a/core/src/test/java/cucumber/api/TestCaseTest.java b/core/src/test/java/cucumber/api/TestCaseTest.java index 5ae68e6d99..b7fc26bd58 100644 --- a/core/src/test/java/cucumber/api/TestCaseTest.java +++ b/core/src/test/java/cucumber/api/TestCaseTest.java @@ -9,6 +9,7 @@ import cucumber.runner.EventBus; import gherkin.events.PickleEvent; import gherkin.pickles.Pickle; +import gherkin.pickles.PickleLocation; import org.junit.Test; import org.mockito.InOrder; @@ -77,6 +78,7 @@ public void skip_steps_after_the_first_non_passed_result() throws Throwable { private PickleEvent pickleEvent() { Pickle pickle = mock(Pickle.class); when(pickle.getLanguage()).thenReturn(ENGLISH); + when(pickle.getLocations()).thenReturn(Arrays.asList(new PickleLocation(1, 1))); return new PickleEvent("uri", pickle); } diff --git a/core/src/test/java/cucumber/runtime/ScenarioResultTest.java b/core/src/test/java/cucumber/runtime/ScenarioResultTest.java index 0bc2c792e4..98cc8e73c2 100644 --- a/core/src/test/java/cucumber/runtime/ScenarioResultTest.java +++ b/core/src/test/java/cucumber/runtime/ScenarioResultTest.java @@ -4,21 +4,25 @@ import cucumber.api.event.EmbedEvent; import cucumber.api.event.WriteEvent; import cucumber.runner.EventBus; +import gherkin.events.PickleEvent; import gherkin.pickles.Pickle; +import gherkin.pickles.PickleLocation; import org.junit.Test; import org.mockito.ArgumentMatcher; +import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.mockito.Matchers.argThat; public class ScenarioResultTest { private EventBus bus = mock(EventBus.class); - private ScenarioImpl s = new ScenarioImpl(bus, mock(Pickle.class)); + private ScenarioImpl s = new ScenarioImpl(bus, pickleEvent()); @Test public void no_steps_is_passed() throws Exception { @@ -93,6 +97,13 @@ public void pending_followed_by_failed_yields_failed_error() { assertThat(s.getError(), sameInstance(failedError)); } + + private PickleEvent pickleEvent() { + Pickle pickle = mock(Pickle.class); + when(pickle.getLocations()).thenReturn(asList(new PickleLocation(1, 1))); + PickleEvent pickleEvent = new PickleEvent("uri", pickle); + return pickleEvent; + } } class EmbedEventMatcher extends ArgumentMatcher { diff --git a/scala/sources/src/test/scala/cucumber/api/scala/ScalaDslTest.scala b/scala/sources/src/test/scala/cucumber/api/scala/ScalaDslTest.scala index 58881f24bc..a92dc5b565 100644 --- a/scala/sources/src/test/scala/cucumber/api/scala/ScalaDslTest.scala +++ b/scala/sources/src/test/scala/cucumber/api/scala/ScalaDslTest.scala @@ -22,6 +22,11 @@ class ScalaDslTest { def getName = "" def getId = "" + + def getUri = "" + + def getLines = null + } @Test @@ -128,7 +133,7 @@ class ScalaDslTest { assertEquals(1, Dummy.stepDefinitions.size) val step = Dummy.stepDefinitions.head - assertEquals("ScalaDslTest.scala:126", step.getLocation(true)) // be careful with formatting or this test will break + assertEquals("ScalaDslTest.scala:131", step.getLocation(true)) // be careful with formatting or this test will break assertEquals("x", step.getPattern) step.execute("en", Array()) assertTrue(called)