From 268c0efa4945cd32721fc8dd9c904de393e1b99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Rasmusson?= Date: Fri, 30 Jun 2017 21:54:25 +0200 Subject: [PATCH] [Core] Provide a unique id of the current scenario to the hooks. Provide methods to access the pickle uri and the pickle lines, which uniquely identify the current scenario. In addition also put back the getId() method. Even though it is not possible to provide the same id string as when using Gherkin v2.12.2, hooks using Scenario.getId() will still compile and still get a unique id for the scenario through that method. --- core/src/main/java/cucumber/api/Scenario.java | 17 ++++ core/src/main/java/cucumber/api/TestCase.java | 2 +- .../java/cucumber/runtime/ScenarioImpl.java | 36 +++++++- .../test/java/cucumber/api/ScenarioTest.java | 91 +++++++++++++++++++ .../test/java/cucumber/api/TestCaseTest.java | 2 + .../cucumber/runtime/ScenarioResultTest.java | 13 ++- .../cucumber/api/scala/ScalaDslTest.scala | 7 +- 7 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 core/src/test/java/cucumber/api/ScenarioTest.java 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)