@Test
  public void shouldAllowToNotResetStateBeforeStory() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step failedStep = mock(Step.class, "failedStep");
    when(failedStep.perform(null))
        .thenReturn(
            failed(
                "before stories",
                new UUIDExceptionWrapper(new RuntimeException("BeforeStories fail"))));
    Step pendingStep = mock(Step.class, "pendingStep");
    when(pendingStep.perform(null)).thenReturn(pending("pendingStep"));
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario1 = new Scenario();
    List<CandidateSteps> candidateSteps = asList(mySteps);
    when(collector.collectBeforeOrAfterStoriesSteps(candidateSteps, Stage.BEFORE))
        .thenReturn(asList(failedStep));
    when(collector.collectScenarioSteps(candidateSteps, scenario1, parameters))
        .thenReturn(asList(pendingStep));
    Story story = new Story(asList(scenario1));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration = configurationWith(reporter, collector);
    configuration.storyControls().doResetStateBeforeStory(false).doResetStateBeforeScenario(false);
    runner.runBeforeOrAfterStories(configuration, candidateSteps, Stage.BEFORE);
    runner.run(configuration, candidateSteps, story);

    // Then
    verify(failedStep).perform(Matchers.<UUIDExceptionWrapper>any());
    verify(pendingStep).perform(Matchers.<UUIDExceptionWrapper>any());
  }
  @Test
  public void shouldNotRunScenariosNotAllowedByFilter() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy strategy = mock(FailureStrategy.class);
    CandidateSteps mySteps = new Steps();
    when(collector.collectScenarioSteps(
            eq(asList(mySteps)), (Scenario) anyObject(), eq(parameters)))
        .thenReturn(Arrays.<Step>asList());
    Meta meta = new Meta(asList("some property"));
    Story story =
        new Story(
            "",
            Description.EMPTY,
            Meta.EMPTY,
            Narrative.EMPTY,
            asList(new Scenario("", meta, GivenStories.EMPTY, ExamplesTable.EMPTY, asList(""))));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);
    String filterAsString = "-some property";
    MetaFilter filter = new MetaFilter(filterAsString);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configurationWith(reporter, collector, strategy), asList(mySteps), story, filter);

    // Then
    verify(reporter).beforeStory(story, givenStory);
    verify(reporter).beforeScenario("");
    verify(reporter).scenarioNotAllowed(story.getScenarios().get(0), filterAsString);
    verify(reporter).afterScenario();
  }
  @Test
  public void shouldNotRunStoriesNotAllowedByFilterOnStoryElement() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy strategy = mock(FailureStrategy.class);
    CandidateSteps mySteps = new Steps();
    when(collector.collectScenarioSteps(
            eq(asList(mySteps)), (Scenario) anyObject(), eq(parameters)))
        .thenReturn(Arrays.<Step>asList());
    Story story =
        new Story(
            "excluded_path",
            Description.EMPTY,
            Meta.EMPTY,
            Narrative.EMPTY,
            asList(new Scenario()));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);
    String filterAsString = "-story_path excluded_path";
    MetaFilter filter = new MetaFilter(filterAsString);

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration = configurationWith(reporter, collector, strategy);
    configuration.storyControls().useStoryMetaPrefix("story_");
    runner.run(configuration, asList(mySteps), story, filter);

    // Then
    verify(reporter).beforeStory(story, givenStory);
    verify(reporter).storyNotAllowed(story, filterAsString);
    verify(reporter).afterStory(givenStory);
  }
  @Test
  public void shouldAllowToNotResetStateBeforeScenario() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step pendingStep = mock(Step.class);
    when(pendingStep.perform(null)).thenReturn(pending("pendingStep"));
    Step secondStep = mockSuccessfulStep("secondStep");
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario1 = new Scenario();
    Scenario scenario2 = new Scenario();
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, parameters))
        .thenReturn(asList(pendingStep));
    when(collector.collectScenarioSteps(asList(mySteps), scenario2, parameters))
        .thenReturn(asList(secondStep));
    Story story = new Story(asList(scenario1, scenario2));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration = configurationWith(reporter, collector);
    configuration.storyControls().doResetStateBeforeScenario(false);
    runner.run(configuration, asList(mySteps), story);

    // Then
    verify(pendingStep).perform(Matchers.<UUIDExceptionWrapper>any());
    verify(secondStep).doNotPerform(Matchers.<UUIDExceptionWrapper>any());
    verify(secondStep, never()).perform(Matchers.<UUIDExceptionWrapper>any());
  }
  @Test
  public void shouldAllowToSkipScenariosAfterFailedScenario() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step failedStep = mock(Step.class);
    Step neverExecutedStep = mock(Step.class);
    StepResult failed =
        failed("When I fail", new UUIDExceptionWrapper(new IllegalStateException()));
    when(failedStep.perform(null)).thenReturn(failed);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario1 = new Scenario();
    when(collector.collectScenarioSteps(eq(asList(mySteps)), eq(scenario1), eq(parameters)))
        .thenReturn(asList(failedStep));
    Scenario scenario2 = new Scenario();
    when(collector.collectScenarioSteps(eq(asList(mySteps)), eq(scenario2), eq(parameters)))
        .thenReturn(asList(neverExecutedStep));
    Story story = new Story(asList(scenario1, scenario2));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration = configurationWith(reporter, collector, failureStrategy);
    configuration.storyControls().doSkipScenariosAfterFailure(true);
    runner.run(configuration, asList(mySteps), story);

    // Then
    verify(failedStep).perform(null);
    verify(neverExecutedStep, never()).perform(null);
  }
  @Test
  public void shouldReportStoryCancellation() {
    // Given
    Configuration configuration = mock(Configuration.class, Mockito.RETURNS_DEEP_STUBS);
    when(configuration.storyControls().dryRun()).thenReturn(false);
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    when(configuration.storyReporter(Matchers.anyString())).thenReturn(reporter);

    Story story = mock(Story.class);
    String storyPath = "story/path";
    when(story.getPath()).thenReturn(storyPath);
    RuntimeException expected = new RuntimeException();
    when(story.getMeta()).thenThrow(expected);

    InjectableStepsFactory stepsFactory = mock(InjectableStepsFactory.class);
    MetaFilter metaFilter = mock(MetaFilter.class);
    State state = mock(State.class);

    // When
    long durationInSecs = 2;
    long timeoutInSecs = 1;
    StoryDuration storyDuration = new StoryDuration(durationInSecs, timeoutInSecs);
    try {
      StoryRunner runner = new StoryRunner();
      runner.cancelStory(story, storyDuration);
      runner.run(configuration, stepsFactory, story, metaFilter, state);
      fail("A exception should be thrown");
    } catch (Throwable e) {
      // Then
      assertThat(e.equals(expected), is(true));
    }
    verify(reporter).storyCancelled(story, storyDuration);
  }
  @Test
  public void shouldRunStepsInDryRunMode() throws Throwable {
    // Given
    Scenario scenario1 = new Scenario("my title 1", asList("failingStep", "successfulStep"));
    Scenario scenario2 = new Scenario("my title 2", asList("successfulStep"));
    Scenario scenario3 = new Scenario("my title 3", asList("successfulStep", "pendingStep"));
    Story story =
        new Story(
            new Description("my blurb"), Narrative.EMPTY, asList(scenario1, scenario2, scenario3));
    Step step = mock(Step.class);
    StepResult result = mock(StepResult.class, "result");
    when(step.perform(null)).thenReturn(result);
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);
    Configuration configuration = configurationWith(reporter, collector, failureStrategy);
    configuration.doDryRun(true);
    CandidateSteps mySteps = new Steps(configuration);
    UUIDExceptionWrapper failure = new UUIDExceptionWrapper(new IllegalArgumentException());
    Step successfulStep = mockSuccessfulStep("successfulStep");
    Step pendingStep = mock(Step.class, "pendingStep");
    Step failingStep = mock(Step.class, "failingStep");
    when(pendingStep.perform(Matchers.<UUIDExceptionWrapper>any()))
        .thenReturn(pending("pendingStep"));
    when(pendingStep.doNotPerform(failure)).thenReturn(pending("pendingStep"));
    when(failingStep.perform(Matchers.<UUIDExceptionWrapper>any()))
        .thenReturn(failed("failingStep", failure));
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, parameters))
        .thenReturn(asList(failingStep, successfulStep));
    when(collector.collectScenarioSteps(asList(mySteps), scenario2, parameters))
        .thenReturn(asList(successfulStep));
    when(collector.collectScenarioSteps(asList(mySteps), scenario3, parameters))
        .thenReturn(asList(successfulStep, pendingStep));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configuration, asList(mySteps), story);

    // Then
    InOrder inOrder = inOrder(reporter, failureStrategy);
    inOrder.verify(reporter).beforeStory(story, givenStory);
    inOrder.verify(reporter).beforeScenario("my title 1");
    inOrder.verify(reporter).failed("failingStep", failure);
    inOrder.verify(reporter).notPerformed("successfulStep");
    inOrder.verify(reporter).afterScenario();
    inOrder.verify(reporter).beforeScenario("my title 2");
    inOrder.verify(reporter).successful("successfulStep");
    inOrder.verify(reporter).afterScenario();
    inOrder.verify(reporter).beforeScenario("my title 3");
    inOrder.verify(reporter).successful("successfulStep");
    inOrder.verify(reporter).pending("pendingStep");
    inOrder.verify(reporter).afterScenario();
    inOrder.verify(reporter).afterStory(givenStory);
    inOrder.verify(failureStrategy).handleFailure(failure);
  }
  @Test
  public void shouldRunScenarioAndLifecycleStepsInCorrectOrderWithExamplesTable() throws Throwable {
    // Given
    ExamplesTable examplesTable = new ExamplesTable("|one|two|\n|1|2|\n");
    Map<String, String> tableRow = examplesTable.getRow(0);
    Scenario scenario1 =
        new Scenario(
            "my title 1",
            Meta.EMPTY,
            GivenStories.EMPTY,
            examplesTable,
            asList("step <one>", "step <two>"));
    Story story = new Story(new Description("my blurb"), Narrative.EMPTY, asList(scenario1));
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);
    Configuration configuration = configurationWith(reporter, collector, failureStrategy);
    configuration.storyControls().doDryRun(true);
    CandidateSteps mySteps = new Steps(configuration);
    Step firstStep = mockSuccessfulStep("step <one>");
    Step secondStep = mockSuccessfulStep("step <two>");
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, tableRow))
        .thenReturn(asList(firstStep, secondStep));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);

    Step beforeExampleStep = mockSuccessfulStep("beforeExampleStep");
    Step afterExampleStep = mockSuccessfulStep("afterExampleStep");
    when(collector.collectBeforeOrAfterScenarioSteps(
            eq(asList(mySteps)), Matchers.<Meta>any(), eq(Stage.BEFORE), eq(ScenarioType.EXAMPLE)))
        .thenReturn(asList(beforeExampleStep));
    when(collector.collectBeforeOrAfterScenarioSteps(
            eq(asList(mySteps)), Matchers.<Meta>any(), eq(Stage.AFTER), eq(ScenarioType.EXAMPLE)))
        .thenReturn(asList(afterExampleStep));

    Step beforeStep = mockSuccessfulStep("lifecycleBeforeStep");
    Step afterStep = mockSuccessfulStep("lifecycleAfterStep");
    when(collector.collectLifecycleSteps(
            eq(asList(mySteps)), eq(Lifecycle.EMPTY), any(Meta.class), eq(Stage.BEFORE)))
        .thenReturn(asList(beforeStep));
    when(collector.collectLifecycleSteps(
            eq(asList(mySteps)), eq(Lifecycle.EMPTY), any(Meta.class), eq(Stage.AFTER)))
        .thenReturn(asList(afterStep));

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configuration, asList(mySteps), story);

    // Then
    InOrder inOrder = inOrder(reporter, failureStrategy);
    inOrder.verify(reporter).successful("beforeExampleStep");
    inOrder.verify(reporter).successful("lifecycleBeforeStep");
    inOrder.verify(reporter).successful("step <one>");
    inOrder.verify(reporter).successful("step <two>");
    inOrder.verify(reporter).successful("lifecycleAfterStep");
    inOrder.verify(reporter).successful("afterExampleStep");
  }
  @Test
  public void shouldNotPerformStepsAfterRestaringScenarioFailure() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step firstStepNormal = mockSuccessfulStep("Given I succeed");
    final RestartingScenarioFailure hi = new RestartingScenarioFailure("hi");
    Step restartStep =
        new AbstractStep() {
          private int count = 0;

          public StepResult perform(UUIDExceptionWrapper storyFailureIfItHappened) {
            if (count == 0) {
              count++;
              throw hi;
            }
            return new AbstractStepResult.Successful("When happened on second attempt");
          }

          public StepResult doNotPerform(UUIDExceptionWrapper storyFailureIfItHappened) {
            return null;
          }

          @Override
          public String toString() {
            return "<fooStep>";
          }
        };
    Step lastStepNormal = mockSuccessfulStep("Then I succeeded");

    StepCollector collector = mock(StepCollector.class);
    FailureStrategy strategy = mock(FailureStrategy.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario = new Scenario();
    when(collector.collectScenarioSteps(eq(asList(mySteps)), eq(scenario), eq(parameters)))
        .thenReturn(asList(firstStepNormal, restartStep, lastStepNormal));
    Story story = new Story(asList(scenario));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configurationWith(reporter, collector, strategy), asList(mySteps), story);

    verify(reporter, times(2)).successful("Given I succeed");
    verify(reporter).restarted(eq("<fooStep>"), isA(RestartingScenarioFailure.class));
    verify(reporter).successful("When happened on second attempt");
    verify(reporter).successful("Then I succeeded");
  }
  @Test
  public void shouldRunScenarioWithExamplesTable() throws Throwable {
    // Given
    ExamplesTable examplesTable = new ExamplesTable("|one|two|\n|1|2|\n");
    Map<String, String> tableRow = examplesTable.getRow(0);
    Scenario scenario1 =
        new Scenario(
            "my title 1",
            Meta.EMPTY,
            GivenStories.EMPTY,
            examplesTable,
            asList("step <one>", "step <two>"));
    Story story = new Story(new Description("my blurb"), Narrative.EMPTY, asList(scenario1));
    Step step = mock(Step.class);
    StepResult result = mock(StepResult.class);
    when(step.perform(null)).thenReturn(result);
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);
    Configuration configuration = configurationWith(reporter, collector, failureStrategy);
    configuration.storyControls().doDryRun(true);
    CandidateSteps mySteps = new Steps(configuration);
    Step firstStep = mockSuccessfulStep("step <one>");
    Step secondStep = mockSuccessfulStep("step <two>");
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, tableRow))
        .thenReturn(asList(firstStep, secondStep));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configuration, asList(mySteps), story);

    // Then
    InOrder inOrder = inOrder(reporter, failureStrategy);
    inOrder.verify(reporter).beforeStory(story, givenStory);
    inOrder.verify(reporter).beforeScenario("my title 1");
    inOrder.verify(reporter).successful("step <one>");
    inOrder.verify(reporter).successful("step <two>");
    inOrder.verify(reporter).afterScenario();
    inOrder.verify(reporter).afterStory(givenStory);
  }
  @Test
  public void shouldReportAnyFailuresAndHandleThemAfterStory() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step firstStepExceptional = mock(Step.class);
    Step secondStepNotPerformed = mock(Step.class);
    StepResult failed =
        failed("When I fail", new UUIDExceptionWrapper(new IllegalStateException()));
    StepResult notPerformed = notPerformed("Then I should not be performed");
    when(firstStepExceptional.perform(null)).thenReturn(failed);
    when(secondStepNotPerformed.doNotPerform(Matchers.<UUIDExceptionWrapper>any()))
        .thenReturn(notPerformed);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario = new Scenario();
    when(collector.collectScenarioSteps(eq(asList(mySteps)), eq(scenario), eq(parameters)))
        .thenReturn(asList(firstStepExceptional, secondStepNotPerformed));
    Story story = new Story(asList(scenario));
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story, givenStory, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configurationWith(reporter, collector, failureStrategy), asList(mySteps), story);

    // Then
    verify(firstStepExceptional).perform(null);
    verify(secondStepNotPerformed).doNotPerform(Matchers.<UUIDExceptionWrapper>any());

    InOrder inOrder = inOrder(reporter, failureStrategy);
    inOrder.verify(reporter).beforeStory((Story) anyObject(), eq(givenStory));
    inOrder.verify(reporter).beforeScenario((String) anyObject());
    inOrder.verify(reporter).failed("When I fail", failed.getFailure());
    inOrder.verify(reporter).notPerformed("Then I should not be performed");
    inOrder.verify(reporter).afterScenario();
    inOrder.verify(reporter).afterStory(givenStory);
    inOrder.verify(failureStrategy).handleFailure(failed.getFailure());
  }
  @Test(expected = PendingStepFound.class)
  public void shouldFailWithFailingUpongPendingStepsStrategy() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step pendingStep = mock(Step.class);
    StepResult pendingResult = pending("My step isn't defined!");
    when(pendingStep.perform(null)).thenReturn(pendingResult);
    PendingStepStrategy strategy = new FailingUponPendingStep();
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    when(collector.collectScenarioSteps(
            eq(asList(mySteps)), (Scenario) anyObject(), eq(parameters)))
        .thenReturn(asList(pendingStep));
    Story story = new Story(asList(new Scenario()));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(
        configurationWithPendingStrategy(collector, reporter, strategy), asList(mySteps), story);

    // Then ... fail as expected
  }
  @Test
  public void shouldNotPerformStepsAfterFailedOrPendingSteps() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step firstStepNormal = mockSuccessfulStep("Given I succeed");
    Step secondStepPending = mock(Step.class, "secondStepPending");
    Step thirdStepNormal = mock(Step.class, "thirdStepNormal");
    Step fourthStepAlsoPending = mock(Step.class, "fourthStepAlsoPending");
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Scenario scenario = new Scenario();
    when(collector.collectScenarioSteps(eq(asList(mySteps)), eq(scenario), eq(parameters)))
        .thenReturn(
            asList(firstStepNormal, secondStepPending, thirdStepNormal, fourthStepAlsoPending));
    when(secondStepPending.perform(null)).thenReturn(pending("When I am pending"));
    when(thirdStepNormal.doNotPerform(Matchers.<UUIDExceptionWrapper>any()))
        .thenReturn(notPerformed("Then I should not be performed"));
    when(fourthStepAlsoPending.doNotPerform(Matchers.<UUIDExceptionWrapper>any()))
        .thenReturn(notPerformed("Then I should not be performed either"));
    Story story = new Story(asList(scenario));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configurationWith(reporter, collector), asList(mySteps), story);

    // Then
    verify(firstStepNormal).perform(null);
    verify(secondStepPending).perform(null);
    verify(thirdStepNormal).doNotPerform(Matchers.<UUIDExceptionWrapper>any());
    verify(fourthStepAlsoPending).doNotPerform(Matchers.<UUIDExceptionWrapper>any());

    verify(reporter).successful("Given I succeed");
    verify(reporter).pending("When I am pending");
    verify(reporter).notPerformed("Then I should not be performed");
    verify(reporter).notPerformed("Then I should not be performed either");
  }
  @Test
  public void shouldHandlePendingStepsAccordingToStrategy() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step pendingStep = mock(Step.class);
    StepResult pendingResult = pending("My step isn't defined!");
    when(pendingStep.perform(null)).thenReturn(pendingResult);
    PendingStepStrategy strategy = mock(PendingStepStrategy.class);
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    when(collector.collectScenarioSteps(
            eq(asList(mySteps)), (Scenario) anyObject(), eq(parameters)))
        .thenReturn(asList(pendingStep));
    Story story = new Story(asList(new Scenario()));
    givenStoryWithNoBeforeOrAfterSteps(story, false, collector, mySteps);

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(
        configurationWithPendingStrategy(collector, reporter, strategy), asList(mySteps), story);

    // Then
    verify(strategy).handleFailure(pendingResult.getFailure());
  }
  @Test
  public void shouldRunBeforeAndAfterStorySteps() throws Throwable {
    // Given
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    Step beforeStep = mockSuccessfulStep("beforeStep");
    Step afterStep = mockSuccessfulStep("secondStep");
    StepCollector collector = mock(StepCollector.class);
    FailureStrategy strategy = mock(FailureStrategy.class);
    CandidateSteps mySteps = new Steps();
    Story story = new Story();
    boolean givenStory = false;
    when(collector.collectBeforeOrAfterStorySteps(asList(mySteps), story, Stage.BEFORE, givenStory))
        .thenReturn(asList(beforeStep));
    when(collector.collectBeforeOrAfterStorySteps(asList(mySteps), story, Stage.AFTER, givenStory))
        .thenReturn(asList(afterStep));

    // When
    StoryRunner runner = new StoryRunner();
    runner.run(configurationWith(reporter, collector, strategy), asList(mySteps), story);

    // Then
    verify(beforeStep).perform(null);
    verify(afterStep).perform(null);
  }
  @Test
  public void shouldRunGivenStoriesAtStoryAndScenarioLevel() throws Throwable {
    // Given
    GivenStories storyGivenStories = new GivenStories("/path/to/given/story1");
    GivenStories scenarioGivenStories = new GivenStories("/path/to/given/story1");
    Scenario scenario1 = new Scenario("scenario 1", asList("successfulStep"));
    Scenario scenario2 =
        new Scenario(
            "scenario 2",
            Meta.EMPTY,
            scenarioGivenStories,
            ExamplesTable.EMPTY,
            asList("anotherSuccessfulStep"));
    Story story1 = new Story(new Description("story 1"), Narrative.EMPTY, asList(scenario1));
    Story story2 =
        new Story(
            "",
            new Description("story 2"),
            Meta.EMPTY,
            Narrative.EMPTY,
            storyGivenStories,
            asList(scenario2));

    Step step = mock(Step.class);
    StepResult result = mock(StepResult.class);
    when(step.perform(null)).thenReturn(result);

    StoryParser storyParser = mock(StoryParser.class);
    StoryLoader storyLoader = mock(StoryLoader.class);
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Step successfulStep = mockSuccessfulStep("successfulStep");
    Step anotherSuccessfulStep = mockSuccessfulStep("anotherSuccessfulStep");
    boolean givenStory = false;
    givenStoryWithNoBeforeOrAfterSteps(story1, givenStory, collector, mySteps);
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, parameters))
        .thenReturn(asList(successfulStep));
    givenStoryWithNoBeforeOrAfterSteps(story2, givenStory, collector, mySteps);
    when(collector.collectScenarioSteps(asList(mySteps), scenario2, parameters))
        .thenReturn(asList(anotherSuccessfulStep));
    when(storyLoader.loadStoryAsText("/path/to/given/story1")).thenReturn("storyContent");
    when(storyParser.parseStory("storyContent", "/path/to/given/story1")).thenReturn(story1);
    givenStoryWithNoBeforeOrAfterSteps(story1, givenStory, collector, mySteps);
    givenStoryWithNoBeforeOrAfterSteps(story2, givenStory, collector, mySteps);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration =
        configurationWith(storyParser, storyLoader, reporter, collector, failureStrategy);
    runner.run(configuration, asList(mySteps), story2);

    // Then
    InOrder inOrder = inOrder(reporter);
    inOrder.verify(reporter).beforeStory(story2, givenStory);
    inOrder.verify(reporter).givenStories(storyGivenStories);
    inOrder.verify(reporter).givenStories(scenarioGivenStories);
    inOrder.verify(reporter).successful("successfulStep");
    inOrder.verify(reporter).successful("anotherSuccessfulStep");
    inOrder.verify(reporter).afterStory(givenStory);
    verify(reporter, never()).beforeStory(story1, givenStory);
  }
  @Test
  public void shouldAllowToSkipBeforeAndAfterScenarioStepsIfGivenStory() throws Throwable {
    // Given
    Scenario scenario1 = new Scenario("scenario 1", asList("successfulStep"));
    GivenStories givenStories = new GivenStories("/path/to/given/story1");
    Scenario scenario2 =
        new Scenario(
            "scenario 2",
            Meta.EMPTY,
            givenStories,
            ExamplesTable.EMPTY,
            asList("anotherSuccessfulStep"));
    Story story1 = new Story(new Description("story 1"), Narrative.EMPTY, asList(scenario1));
    Story story2 = new Story(new Description("story 2"), Narrative.EMPTY, asList(scenario2));

    Step step = mock(Step.class);
    StepResult result = mock(StepResult.class);
    when(step.perform(null)).thenReturn(result);

    StoryParser storyParser = mock(StoryParser.class);
    StoryLoader storyLoader = mock(StoryLoader.class);
    StoryReporter reporter = mock(ConcurrentStoryReporter.class);
    StepCollector collector = mock(StepCollector.class);
    CandidateSteps mySteps = new Steps();
    Step successfulStep = mockSuccessfulStep("successfulStep");
    Step anotherSuccessfulStep = mockSuccessfulStep("anotherSuccessfulStep");
    givenStoryWithNoBeforeOrAfterSteps(story1, false, collector, mySteps);
    when(collector.collectScenarioSteps(asList(mySteps), scenario1, parameters))
        .thenReturn(asList(successfulStep));
    givenStoryWithNoBeforeOrAfterSteps(story2, true, collector, mySteps);
    when(collector.collectScenarioSteps(asList(mySteps), scenario2, parameters))
        .thenReturn(asList(anotherSuccessfulStep));
    when(storyLoader.loadStoryAsText("/path/to/given/story1")).thenReturn("storyContent");
    when(storyParser.parseStory("storyContent", "/path/to/given/story1")).thenReturn(story1);
    FailureStrategy failureStrategy = mock(FailureStrategy.class);

    Step beforeStep = mockSuccessfulStep("SuccessfulBeforeScenarioStep");
    Step afterStep = mockSuccessfulStep("SuccessfulAfterScenarioStep");
    when(collector.collectBeforeOrAfterScenarioSteps(
            eq(asList(mySteps)), Matchers.<Meta>any(), eq(Stage.BEFORE), eq(ScenarioType.NORMAL)))
        .thenReturn(asList(beforeStep));
    when(collector.collectBeforeOrAfterScenarioSteps(
            eq(asList(mySteps)), Matchers.<Meta>any(), eq(Stage.AFTER), eq(ScenarioType.NORMAL)))
        .thenReturn(asList(afterStep));

    // When
    StoryRunner runner = new StoryRunner();
    Configuration configuration =
        configurationWith(storyParser, storyLoader, reporter, collector, failureStrategy);
    configuration.storyControls().doSkipBeforeAndAfterScenarioStepsIfGivenStory(true);
    runner.run(configuration, asList(mySteps), story2);

    // Then
    verify(collector).collectScenarioSteps(asList(mySteps), scenario1, parameters);
    verify(collector).collectScenarioSteps(asList(mySteps), scenario2, parameters);

    InOrder inOrder = inOrder(beforeStep, successfulStep, anotherSuccessfulStep, afterStep);

    inOrder.verify(beforeStep).perform(null);
    inOrder.verify(successfulStep).perform(null);
    inOrder.verify(anotherSuccessfulStep).perform(null);
    inOrder.verify(afterStep).perform(null);
  }