Coverage Report - org.jbehave.core.embedder.StoryRunner
 
Classes in this File Line Coverage Branch Coverage Complexity
StoryRunner
90%
166/183
81%
75/92
2.265
StoryRunner$1
N/A
N/A
2.265
StoryRunner$FineSoFar
100%
14/14
70%
7/10
2.265
StoryRunner$RunContext
100%
31/31
100%
2/2
2.265
StoryRunner$SomethingHappened
100%
6/6
N/A
2.265
StoryRunner$State
N/A
N/A
2.265
 
 1  
 package org.jbehave.core.embedder;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.HashMap;
 5  
 import java.util.List;
 6  
 import java.util.Map;
 7  
 
 8  
 import org.jbehave.core.annotations.ScenarioType;
 9  
 import org.jbehave.core.configuration.Configuration;
 10  
 import org.jbehave.core.failures.FailureStrategy;
 11  
 import org.jbehave.core.failures.PendingStepFound;
 12  
 import org.jbehave.core.failures.PendingStepStrategy;
 13  
 import org.jbehave.core.failures.RestartingScenarioFailure;
 14  
 import org.jbehave.core.failures.UUIDExceptionWrapper;
 15  
 import org.jbehave.core.model.ExamplesTable;
 16  
 import org.jbehave.core.model.GivenStories;
 17  
 import org.jbehave.core.model.GivenStory;
 18  
 import org.jbehave.core.model.Meta;
 19  
 import org.jbehave.core.model.Scenario;
 20  
 import org.jbehave.core.model.Story;
 21  
 import org.jbehave.core.reporters.ConcurrentStoryReporter;
 22  
 import org.jbehave.core.reporters.StoryReporter;
 23  
 import org.jbehave.core.steps.CandidateSteps;
 24  
 import org.jbehave.core.steps.InjectableStepsFactory;
 25  
 import org.jbehave.core.steps.PendingStepMethodGenerator;
 26  
 import org.jbehave.core.steps.ProvidedStepsFactory;
 27  
 import org.jbehave.core.steps.Step;
 28  
 import org.jbehave.core.steps.StepCollector.Stage;
 29  
 import org.jbehave.core.steps.StepCreator.PendingStep;
 30  
 import org.jbehave.core.steps.StepResult;
 31  
 
 32  
 import static org.codehaus.plexus.util.StringUtils.capitalizeFirstLetter;
 33  
 
 34  
 /**
 35  
  * Runs a {@link Story}, given a {@link Configuration} and a list of
 36  
  * {@link CandidateSteps}, describing the results to the {@link StoryReporter}.
 37  
  * 
 38  
  * @author Elizabeth Keogh
 39  
  * @author Mauro Talevi
 40  
  * @author Paul Hammant
 41  
  */
 42  210
 public class StoryRunner {
 43  
 
 44  74
     private ThreadLocal<FailureStrategy> currentStrategy = new ThreadLocal<FailureStrategy>();
 45  74
     private ThreadLocal<FailureStrategy> failureStrategy = new ThreadLocal<FailureStrategy>();
 46  74
     private ThreadLocal<PendingStepStrategy> pendingStepStrategy = new ThreadLocal<PendingStepStrategy>();
 47  74
     private ThreadLocal<UUIDExceptionWrapper> storyFailure = new ThreadLocal<UUIDExceptionWrapper>();
 48  74
     private ThreadLocal<StoryReporter> reporter = new ThreadLocal<StoryReporter>();
 49  74
     private ThreadLocal<String> reporterStoryPath = new ThreadLocal<String>();
 50  74
     private ThreadLocal<State> storiesState = new ThreadLocal<State>();
 51  
 
 52  
     /**
 53  
      * Run steps before or after a collection of stories. Steps are execute only
 54  
      * <b>once</b> per collection of stories.
 55  
      * 
 56  
      * @param configuration the Configuration used to find the steps to run
 57  
      * @param candidateSteps the List of CandidateSteps containing the candidate
 58  
      *            steps methods
 59  
      * @param stage the Stage
 60  
      * @return The State after running the steps
 61  
      */
 62  
     public State runBeforeOrAfterStories(Configuration configuration, List<CandidateSteps> candidateSteps, Stage stage) {
 63  5
         String storyPath = capitalizeFirstLetter(stage.name().toLowerCase()) + "Stories";
 64  5
         reporter.set(configuration.storyReporter(storyPath));
 65  5
         reporter.get().beforeStory(new Story(storyPath), false);
 66  5
         RunContext context = new RunContext(configuration, candidateSteps, storyPath, MetaFilter.EMPTY);
 67  5
         if (stage == Stage.BEFORE ){
 68  3
             resetStoryFailure(context);
 69  
         }
 70  5
         if (stage == Stage.AFTER && storiesState.get() != null) {
 71  2
             context.stateIs(storiesState.get());
 72  
         }
 73  5
         runStepsWhileKeepingState(context,
 74  
                 configuration.stepCollector().collectBeforeOrAfterStoriesSteps(context.candidateSteps(), stage));
 75  5
         reporter.get().afterStory(false);
 76  5
         storiesState.set(context.state());
 77  
         // handle any after stories failure according to strategy
 78  5
         if (stage == Stage.AFTER) {
 79  
             try {
 80  2
                 handleStoryFailureByStrategy();
 81  1
             } catch (Throwable e) {
 82  1
                 return new SomethingHappened(storyFailure.get());
 83  
             } finally {
 84  2
                 if (reporter.get() instanceof ConcurrentStoryReporter) {
 85  0
                     ((ConcurrentStoryReporter) reporter.get()).invokeDelayed();
 86  
                 }
 87  
             }
 88  
         }
 89  4
         return context.state();
 90  
     }
 91  
 
 92  
     /**
 93  
      * Runs a Story with the given configuration and steps.
 94  
      * 
 95  
      * @param configuration the Configuration used to run story
 96  
      * @param candidateSteps the List of CandidateSteps containing the candidate
 97  
      *            steps methods
 98  
      * @param story the Story to run
 99  
      * @throws Throwable if failures occurred and FailureStrategy dictates it to
 100  
      *             be re-thrown.
 101  
      */
 102  
     public void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story) throws Throwable {
 103  15
         run(configuration, candidateSteps, story, MetaFilter.EMPTY);
 104  14
     }
 105  
 
 106  
     /**
 107  
      * Runs a Story with the given configuration and steps, applying the given
 108  
      * meta filter.
 109  
      * 
 110  
      * @param configuration the Configuration used to run story
 111  
      * @param candidateSteps the List of CandidateSteps containing the candidate
 112  
      *            steps methods
 113  
      * @param story the Story to run
 114  
      * @param filter the Filter to apply to the story Meta
 115  
      * @throws Throwable if failures occurred and FailureStrategy dictates it to
 116  
      *             be re-thrown.
 117  
      */
 118  
     public void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story, MetaFilter filter)
 119  
             throws Throwable {
 120  17
         run(configuration, candidateSteps, story, filter, null);
 121  16
     }
 122  
 
 123  
     /**
 124  
      * Runs a Story with the given configuration and steps, applying the given
 125  
      * meta filter, and staring from given state.
 126  
      * 
 127  
      * @param configuration the Configuration used to run story
 128  
      * @param candidateSteps the List of CandidateSteps containing the candidate
 129  
      *            steps methods
 130  
      * @param story the Story to run
 131  
      * @param filter the Filter to apply to the story Meta
 132  
      * @param beforeStories the State before running any of the stories, if not
 133  
      *            <code>null</code>
 134  
      * @throws Throwable if failures occurred and FailureStrategy dictates it to
 135  
      *             be re-thrown.
 136  
      */
 137  
     public void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story, MetaFilter filter,
 138  
             State beforeStories) throws Throwable {
 139  17
         run(configuration, new ProvidedStepsFactory(candidateSteps), story, filter, beforeStories);
 140  16
     }
 141  
 
 142  
     /**
 143  
      * Runs a Story with the given steps factory, applying the given meta
 144  
      * filter, and staring from given state.
 145  
      * 
 146  
      * @param configuration the Configuration used to run story
 147  
      * @param stepsFactory the InjectableStepsFactory used to created the
 148  
      *            candidate steps methods
 149  
      * @param story the Story to run
 150  
      * @param filter the Filter to apply to the story Meta
 151  
      * @param beforeStories the State before running any of the stories, if not
 152  
      *            <code>null</code>
 153  
      * 
 154  
      * @throws Throwable if failures occurred and FailureStrategy dictates it to
 155  
      *             be re-thrown.
 156  
      */
 157  
     public void run(Configuration configuration, InjectableStepsFactory stepsFactory, Story story, MetaFilter filter,
 158  
             State beforeStories) throws Throwable {
 159  17
         RunContext context = new RunContext(configuration, stepsFactory, story.getPath(), filter);
 160  17
         if (beforeStories != null) {
 161  0
             context.stateIs(beforeStories);
 162  
         }
 163  17
         Map<String, String> storyParameters = new HashMap<String, String>();
 164  17
         run(context, story, storyParameters);
 165  16
     }
 166  
 
 167  
     /**
 168  
      * Returns the parsed story from the given path
 169  
      * 
 170  
      * @param configuration the Configuration used to run story
 171  
      * @param storyPath the story path
 172  
      * @return The parsed Story
 173  
      */
 174  
     public Story storyOfPath(Configuration configuration, String storyPath) {
 175  2
         String storyAsText = configuration.storyLoader().loadStoryAsText(storyPath);
 176  2
         return configuration.storyParser().parseStory(storyAsText, storyPath);
 177  
     }
 178  
 
 179  
     private void run(RunContext context, Story story, Map<String, String> storyParameters) throws Throwable {
 180  
         try {
 181  19
             runIt(context, story, storyParameters);
 182  0
         } catch (InterruptedException interruptedException) {
 183  0
             reporter.get().cancelled();
 184  0
             throw interruptedException;
 185  18
         }
 186  18
     }
 187  
 
 188  
     private void runIt(RunContext context, Story story, Map<String, String> storyParameters) throws Throwable {
 189  19
         if (!context.givenStory) {
 190  17
             reporter.set(reporterFor(context, story));
 191  
         }
 192  19
         pendingStepStrategy.set(context.configuration().pendingStepStrategy());
 193  19
         failureStrategy.set(context.configuration().failureStrategy());
 194  
 
 195  
         try {
 196  19
             resetStoryFailure(context);
 197  
 
 198  19
             if (context.dryRun()) {
 199  2
                 reporter.get().dryRun();
 200  
             }
 201  
 
 202  19
             if (context.configuration().storyControls().resetStateBeforeStory()) {
 203  18
                 context.resetState();
 204  
             }
 205  
 
 206  
             // run before story steps, if any
 207  19
             reporter.get().beforeStory(story, context.givenStory());
 208  
 
 209  19
             boolean storyAllowed = true;
 210  
 
 211  19
             if (context.metaNotAllowed(story.getMeta())) {
 212  1
                 reporter.get().storyNotAllowed(story, context.metaFilterAsString());
 213  1
                 storyAllowed = false;
 214  
             }
 215  
 
 216  19
             if (storyAllowed) {
 217  
 
 218  18
                 reporter.get().narrative(story.getNarrative());
 219  
 
 220  18
                 runBeforeOrAfterStorySteps(context, story, Stage.BEFORE);
 221  
 
 222  
                 // determine if before and after scenario steps should be run
 223  18
                 boolean runBeforeAndAfterScenarioSteps = shouldRunBeforeOrAfterScenarioSteps(context);
 224  
 
 225  18
                 for (Scenario scenario : story.getScenarios()) {
 226  
                     // scenario also inherits meta from story
 227  24
                     boolean scenarioAllowed = true;
 228  24
                     if (failureOccurred(context) && context.configuration().storyControls().skipScenariosAfterFailure()) {
 229  1
                         continue;
 230  
                     }
 231  23
                     reporter.get().beforeScenario(scenario.getTitle());
 232  23
                     reporter.get().scenarioMeta(scenario.getMeta());
 233  
 
 234  23
                     Meta storyAndScenarioMeta = scenario.getMeta().inheritFrom(story.getMeta());
 235  23
                     if (context.metaNotAllowed(storyAndScenarioMeta)) {
 236  1
                         reporter.get().scenarioNotAllowed(scenario, context.metaFilterAsString());
 237  1
                         scenarioAllowed = false;
 238  
                     }
 239  
 
 240  23
                     if (scenarioAllowed) {
 241  22
                         if (context.configuration().storyControls().resetStateBeforeScenario()) {
 242  19
                             context.resetState();
 243  
                         }
 244  
                         // run before scenario steps, if allowed
 245  22
                         if (runBeforeAndAfterScenarioSteps) {
 246  21
                             runBeforeOrAfterScenarioSteps(context, scenario, storyAndScenarioMeta, Stage.BEFORE, ScenarioType.NORMAL);
 247  
                         }
 248  
 
 249  
                         // run given stories, if any
 250  22
                         runGivenStories(scenario, context);
 251  22
                         if (isParameterisedByExamples(scenario)) {
 252  
                             // run parametrised scenarios by examples
 253  1
                             runParametrisedScenariosByExamples(context, scenario, storyAndScenarioMeta);
 254  
                         } else { // run as plain old scenario
 255  21
                             addMetaParameters(storyParameters, storyAndScenarioMeta);
 256  21
                             runScenarioSteps(context, scenario, storyParameters);
 257  
                         }
 258  
 
 259  
                         // run after scenario steps, if allowed
 260  22
                         if (runBeforeAndAfterScenarioSteps) {
 261  21
                             runBeforeOrAfterScenarioSteps(context, scenario, storyAndScenarioMeta, Stage.AFTER, ScenarioType.NORMAL);
 262  
                         }
 263  
 
 264  
                     }
 265  
 
 266  23
                     reporter.get().afterScenario();
 267  23
                 }
 268  
 
 269  
                 // run after story steps, if any
 270  18
                 runBeforeOrAfterStorySteps(context, story, Stage.AFTER);
 271  
 
 272  
             }
 273  
 
 274  19
             reporter.get().afterStory(context.givenStory());
 275  
 
 276  
             // handle any failure according to strategy
 277  19
             if (!context.givenStory()) {
 278  17
                 handleStoryFailureByStrategy();
 279  
             }
 280  
         } finally {
 281  19
             if (!context.givenStory() && reporter.get() instanceof ConcurrentStoryReporter) {
 282  17
                 ((ConcurrentStoryReporter) reporter.get()).invokeDelayed();
 283  
             }
 284  
         }
 285  18
     }
 286  
 
 287  
     private void addMetaParameters(Map<String, String> storyParameters, Meta meta) {
 288  21
         for (String name : meta.getPropertyNames()) {
 289  0
             storyParameters.put(name, meta.getProperty(name));
 290  
         }
 291  21
     }
 292  
 
 293  
     private boolean shouldRunBeforeOrAfterScenarioSteps(RunContext context) {
 294  18
         Configuration configuration = context.configuration();
 295  18
         if (!configuration.storyControls().skipBeforeAndAfterScenarioStepsIfGivenStory()) {
 296  16
             return true;
 297  
         }
 298  
 
 299  2
         return !context.givenStory();
 300  
     }
 301  
 
 302  
     private boolean failureOccurred(RunContext context) {
 303  24
         return context.failureOccurred();
 304  
     }
 305  
 
 306  
     private StoryReporter reporterFor(RunContext context, Story story) {
 307  17
         Configuration configuration = context.configuration();
 308  17
         if (context.givenStory()) {
 309  0
             return configuration.storyReporter(reporterStoryPath.get());
 310  
         } else {
 311  
             // store parent story path for reporting
 312  17
             reporterStoryPath.set(story.getPath());
 313  17
             return configuration.storyReporter(reporterStoryPath.get());
 314  
         }
 315  
     }
 316  
 
 317  
     private void handleStoryFailureByStrategy() throws Throwable {
 318  19
         Throwable throwable = storyFailure.get();
 319  19
         if ( throwable != null ){
 320  11
             currentStrategy.get().handleFailure(throwable);
 321  
         }
 322  17
     }
 323  
 
 324  
     private void resetStoryFailure(RunContext context) {
 325  22
         if (context.givenStory()) {
 326  
             // do not reset failure for given stories
 327  2
             return;
 328  
         }
 329  20
         currentStrategy.set(context.configuration().failureStrategy());
 330  20
         storyFailure.set(null);
 331  20
     }
 332  
 
 333  
     private void runGivenStories(Scenario scenario, RunContext context) throws Throwable {
 334  22
         GivenStories givenStories = scenario.getGivenStories();
 335  22
         if (givenStories.getPaths().size() > 0) {
 336  2
             reporter.get().givenStories(givenStories);
 337  2
             for (GivenStory givenStory : givenStories.getStories()) {
 338  2
                 RunContext childContext = context.childContextFor(givenStory);
 339  
                 // run given story, using any parameters if provided
 340  2
                 Story story = storyOfPath(context.configuration(), childContext.path());
 341  2
                 run(childContext, story, givenStory.getParameters());
 342  2
             }
 343  
         }
 344  22
     }
 345  
 
 346  
     private boolean isParameterisedByExamples(Scenario scenario) {
 347  22
         return scenario.getExamplesTable().getRowCount() > 0 && !scenario.getGivenStories().requireParameters();
 348  
     }
 349  
 
 350  
     private void runParametrisedScenariosByExamples(RunContext context, Scenario scenario, Meta storyAndScenarioMeta) {
 351  1
         ExamplesTable table = scenario.getExamplesTable();
 352  1
         reporter.get().beforeExamples(scenario.getSteps(), table);
 353  1
         for (Map<String, String> scenarioParameters : table.getRows()) {
 354  1
             reporter.get().example(scenarioParameters);
 355  1
             if (context.configuration().storyControls().resetStateBeforeScenario()) {
 356  1
                 context.resetState();
 357  
             }
 358  1
             runBeforeOrAfterScenarioSteps(context, scenario, storyAndScenarioMeta, Stage.BEFORE, ScenarioType.EXAMPLE);
 359  1
             runScenarioSteps(context, scenario, scenarioParameters);
 360  1
             runBeforeOrAfterScenarioSteps(context, scenario, storyAndScenarioMeta, Stage.AFTER, ScenarioType.EXAMPLE);
 361  
         }
 362  1
         reporter.get().afterExamples();
 363  1
     }
 364  
 
 365  
     private void runBeforeOrAfterStorySteps(RunContext context, Story story, Stage stage) {
 366  36
         runStepsWhileKeepingState(context, context.collectBeforeOrAfterStorySteps(story, stage));
 367  36
     }
 368  
 
 369  
     private void runBeforeOrAfterScenarioSteps(RunContext context, Scenario scenario, Meta storyAndScenarioMeta, Stage stage, ScenarioType type) {
 370  44
         runStepsWhileKeepingState(context, context.collectBeforeOrAfterScenarioSteps(storyAndScenarioMeta, stage, type));
 371  44
     }
 372  
 
 373  
     private void runScenarioSteps(RunContext context, Scenario scenario, Map<String, String> scenarioParameters) {
 374  22
         boolean restart = true;
 375  45
         while (restart) {
 376  23
             restart = false;
 377  23
             List<Step> steps = context.collectScenarioSteps(scenario, scenarioParameters);
 378  
             try {
 379  23
                 runStepsWhileKeepingState(context, steps);
 380  1
             } catch (RestartingScenarioFailure e) {
 381  1
                 restart = true;
 382  1
                 continue;
 383  22
             }
 384  22
             generatePendingStepMethods(context, steps);
 385  22
         }
 386  22
     }
 387  
 
 388  
     private void generatePendingStepMethods(RunContext context, List<Step> steps) {
 389  22
         List<PendingStep> pendingSteps = new ArrayList<PendingStep>();
 390  22
         for (Step step : steps) {
 391  33
             if (step instanceof PendingStep) {
 392  0
                 pendingSteps.add((PendingStep) step);
 393  
             }
 394  
         }
 395  22
         if (!pendingSteps.isEmpty()) {
 396  0
             PendingStepMethodGenerator generator = new PendingStepMethodGenerator(context.configuration().keywords());
 397  0
             List<String> methods = new ArrayList<String>();
 398  0
             for (PendingStep pendingStep : pendingSteps) {
 399  0
                 if (!pendingStep.annotated()) {
 400  0
                     methods.add(generator.generateMethod(pendingStep));
 401  
                 }
 402  
             }
 403  0
             reporter.get().pendingMethods(methods);
 404  
         }
 405  22
     }
 406  
 
 407  
     private void runStepsWhileKeepingState(RunContext context, List<Step> steps) {
 408  108
         if (steps == null || steps.size() == 0) {
 409  76
             return;
 410  
         }
 411  32
         State state = context.state();
 412  32
         for (Step step : steps) {
 413  
             try {
 414  44
                 state = state.run(step);
 415  1
             } catch (RestartingScenarioFailure e) {
 416  1
                 reporter.get().restarted(step.toString(), e);
 417  1
                 throw e;
 418  43
             }
 419  
         }
 420  31
         context.stateIs(state);
 421  31
     }
 422  
 
 423  
     public interface State {
 424  
         State run(Step step);
 425  
     }
 426  
 
 427  124
     private final class FineSoFar implements State {
 428  
 
 429  
         public State run(Step step) {
 430  37
             UUIDExceptionWrapper storyFailureIfItHappened = storyFailure.get();
 431  37
             StepResult result = step.perform(storyFailureIfItHappened);
 432  36
             result.describeTo(reporter.get());
 433  36
             UUIDExceptionWrapper stepFailure = result.getFailure();
 434  36
             if (stepFailure == null) {
 435  22
                 return this;
 436  
             }
 437  
 
 438  14
             storyFailure.set(mostImportantOf(storyFailureIfItHappened, stepFailure));
 439  14
             currentStrategy.set(strategyFor(storyFailure.get()));
 440  14
             return new SomethingHappened(stepFailure);
 441  
         }
 442  
 
 443  
         private UUIDExceptionWrapper mostImportantOf(UUIDExceptionWrapper failure1, UUIDExceptionWrapper failure2) {
 444  14
             return failure1 == null ? failure2
 445  
                     : failure1.getCause() instanceof PendingStepFound ? (failure2 == null ? failure1 : failure2)
 446  
                             : failure1;
 447  
         }
 448  
 
 449  
         private FailureStrategy strategyFor(Throwable failure) {
 450  14
             if (failure instanceof PendingStepFound) {
 451  6
                 return pendingStepStrategy.get();
 452  
             } else {
 453  8
                 return failureStrategy.get();
 454  
             }
 455  
         }
 456  
     }
 457  
 
 458  
     private final class SomethingHappened implements State { 
 459  
         UUIDExceptionWrapper scenarioFailure;
 460  
         
 461  15
         public SomethingHappened(UUIDExceptionWrapper scenarioFailure) {
 462  15
             this.scenarioFailure = scenarioFailure;
 463  15
         }
 464  
 
 465  
         public State run(Step step) {
 466  7
             StepResult result = step.doNotPerform(scenarioFailure);
 467  7
             result.describeTo(reporter.get());
 468  7
             return this;
 469  
         }
 470  
     }
 471  
 
 472  
     @Override
 473  
     public String toString() {
 474  1
         return this.getClass().getSimpleName();
 475  
     }
 476  
 
 477  
     /**
 478  
      * The context for running a story.
 479  
      */
 480  74
     private class RunContext {
 481  
         private final Configuration configuration;
 482  
         private final List<CandidateSteps> candidateSteps;
 483  
         private final String path;
 484  
         private final MetaFilter filter;
 485  
         private final boolean givenStory;
 486  
         private State state;
 487  
 
 488  
         public RunContext(Configuration configuration, InjectableStepsFactory stepsFactory, String path,
 489  
                 MetaFilter filter) {
 490  17
             this(configuration, stepsFactory.createCandidateSteps(), path, filter);
 491  17
         }
 492  
 
 493  
         public RunContext(Configuration configuration, List<CandidateSteps> steps, String path, MetaFilter filter) {
 494  22
             this(configuration, steps, path, filter, false);
 495  22
         }
 496  
 
 497  
         private RunContext(Configuration configuration, List<CandidateSteps> steps, String path, MetaFilter filter,
 498  24
                 boolean givenStory) {
 499  24
             this.configuration = configuration;
 500  24
             this.candidateSteps = steps;
 501  24
             this.path = path;
 502  24
             this.filter = filter;
 503  24
             this.givenStory = givenStory;
 504  24
             resetState();
 505  24
         }
 506  
 
 507  
         public boolean dryRun() {
 508  19
             return configuration.storyControls().dryRun();
 509  
         }
 510  
 
 511  
         public Configuration configuration() {
 512  142
             return configuration;
 513  
         }
 514  
 
 515  
         public List<CandidateSteps> candidateSteps() {
 516  5
             return candidateSteps;
 517  
         }
 518  
 
 519  
         public boolean givenStory() {
 520  117
             return givenStory;
 521  
         }
 522  
 
 523  
         public String path() {
 524  2
             return path;
 525  
         }
 526  
 
 527  
         public boolean metaNotAllowed(Meta meta) {
 528  42
             return !filter.allow(meta);
 529  
         }
 530  
 
 531  
         public String metaFilterAsString() {
 532  2
             return filter.asString();
 533  
         }
 534  
 
 535  
         public List<Step> collectBeforeOrAfterStorySteps(Story story, Stage stage) {
 536  36
             return configuration.stepCollector().collectBeforeOrAfterStorySteps(candidateSteps, story, stage, givenStory);
 537  
         }
 538  
 
 539  
         public List<Step> collectBeforeOrAfterScenarioSteps(Meta storyAndScenarioMeta, Stage stage, ScenarioType type) {
 540  44
             return configuration.stepCollector().collectBeforeOrAfterScenarioSteps(candidateSteps, storyAndScenarioMeta, stage, type);
 541  
         }
 542  
 
 543  
         public List<Step> collectScenarioSteps(Scenario scenario, Map<String, String> parameters) {
 544  23
             return configuration.stepCollector().collectScenarioSteps(candidateSteps, scenario, parameters);
 545  
         }
 546  
 
 547  
         public RunContext childContextFor(GivenStory givenStory) {
 548  2
             String actualPath = configuration.pathCalculator().calculate(path, givenStory.getPath());
 549  2
             return new RunContext(configuration, candidateSteps, actualPath, filter, true);
 550  
         }
 551  
 
 552  
         public State state() {
 553  41
             return state;
 554  
         }
 555  
 
 556  
         public void stateIs(State state) {
 557  33
             this.state = state;
 558  33
         }
 559  
 
 560  
         public boolean failureOccurred() {
 561  24
             return failed(state);
 562  
         }
 563  
 
 564  
         public void resetState() {
 565  62
             this.state = new FineSoFar();
 566  62
         }
 567  
 
 568  
     }
 569  
 
 570  
     public boolean failed(State state) {
 571  24
         return !state.getClass().equals(FineSoFar.class);
 572  
     }
 573  
     
 574  
     public Throwable failure(State state){
 575  0
         if ( failed(state ) ){
 576  0
             return ((SomethingHappened)state).scenarioFailure.getCause();
 577  
         }
 578  0
         return null;
 579  
     }
 580  
 }