Coverage Report - org.jbehave.core.embedder.StoryRunner
 
Classes in this File Line Coverage Branch Coverage Complexity
StoryRunner
100%
68/68
96%
27/28
2.211
StoryRunner$1
N/A
N/A
2.211
StoryRunner$FineSoFar
100%
13/13
70%
7/10
2.211
StoryRunner$SomethingHappened
100%
4/4
N/A
2.211
StoryRunner$State
N/A
N/A
2.211
 
 1  
 package org.jbehave.core.embedder;
 2  
 
 3  
 import java.util.HashMap;
 4  
 import java.util.List;
 5  
 import java.util.Map;
 6  
 
 7  
 import org.jbehave.core.configuration.Configuration;
 8  
 import org.jbehave.core.failures.FailureStrategy;
 9  
 import org.jbehave.core.failures.PendingStepFound;
 10  
 import org.jbehave.core.failures.PendingStepStrategy;
 11  
 import org.jbehave.core.failures.SilentlyAbsorbingFailure;
 12  
 import org.jbehave.core.model.ExamplesTable;
 13  
 import org.jbehave.core.model.Scenario;
 14  
 import org.jbehave.core.model.Story;
 15  
 import org.jbehave.core.reporters.StoryReporter;
 16  
 import org.jbehave.core.steps.CandidateSteps;
 17  
 import org.jbehave.core.steps.Step;
 18  
 import org.jbehave.core.steps.StepCollector;
 19  
 import org.jbehave.core.steps.StepResult;
 20  
 import org.jbehave.core.steps.StepCollector.Stage;
 21  
 
 22  
 /**
 23  
  * Runs a {@link Story}, given a {@link Configuration} and a list of {@link CandidateSteps}, 
 24  
  * describing the results to the {@link StoryReporter}.
 25  
  *
 26  
  * @author Elizabeth Keogh
 27  
  * @author Mauro Talevi
 28  
  * @author Paul Hammant
 29  
  */
 30  141
 public class StoryRunner {
 31  
 
 32  59
     private State state = new FineSoFar();
 33  
     private FailureStrategy currentStrategy;
 34  
     private PendingStepStrategy pendingStepStrategy;
 35  
     private StoryReporter reporter;
 36  
     private FailureStrategy failureStrategy;
 37  
     private Throwable storyFailure;
 38  
     private StepCollector stepCollector;
 39  
         private String reporterStoryPath;
 40  
 
 41  
         /**
 42  
          * Run steps before or after a collection of stories.  Steps are execute only <b>once</b> per collection
 43  
          * of stories.
 44  
          * 
 45  
      * @param configuration the Configuration used to find the steps to run
 46  
          * @param candidateSteps List of CandidateSteps containing the candidate steps methods
 47  
          * @param stage the Stage
 48  
          */
 49  
     public void runBeforeOrAfterStories(Configuration configuration, List<CandidateSteps> candidateSteps, Stage stage) {
 50  2
         runSteps(configuration.stepCollector().collectBeforeOrAfterStoriesSteps(candidateSteps, stage));        
 51  2
     }
 52  
 
 53  
     /**
 54  
          * Runs a Story with the given configuration and steps.  
 55  
          * 
 56  
          * @param configuration the Configuration used to run story
 57  
          * @param candidateSteps the List of CandidateSteps containing the candidate steps methods
 58  
          * @param story the Story to run
 59  
          * @throws Throwable if failures occurred and FailureStrategy dictates it to be re-thrown.
 60  
          */
 61  
     public void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story) throws Throwable {
 62  10
         run(configuration, candidateSteps, story, false);
 63  9
     }
 64  
 
 65  
     private void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story, boolean givenStory) throws Throwable {
 66  11
         stepCollector = configuration.stepCollector();
 67  11
         reporter = reporterFor(configuration, story, givenStory);
 68  11
         pendingStepStrategy = configuration.pendingStepStrategy();
 69  11
         failureStrategy = configuration.failureStrategy();
 70  11
         resetFailureState(givenStory);
 71  
 
 72  11
                 if (isDryRun(candidateSteps)) {
 73  2
                         reporter.dryRun();
 74  
                 }
 75  
 
 76  11
         reporter.beforeStory(story, givenStory);
 77  11
         runStorySteps(candidateSteps, story, givenStory, StepCollector.Stage.BEFORE);
 78  11
         for (Scenario scenario : story.getScenarios()) {
 79  15
             reporter.beforeScenario(scenario.getTitle());
 80  15
             runGivenStories(configuration, candidateSteps, scenario); // first run any given stories, if any
 81  15
             if (isExamplesTableScenario(scenario)) { // run as examples table scenario
 82  1
                 runExamplesTableScenario(candidateSteps, scenario);
 83  
             } else { // run as plain old scenario
 84  14
                 runScenarioSteps(candidateSteps, scenario, new HashMap<String, String>());
 85  
             }
 86  15
             reporter.afterScenario();
 87  
         }
 88  11
         runStorySteps(candidateSteps, story, givenStory, StepCollector.Stage.AFTER);
 89  11
         reporter.afterStory(givenStory);
 90  11
         currentStrategy.handleFailure(storyFailure);
 91  10
     }
 92  
     
 93  
     public Story storyOfPath(Configuration configuration, String storyPath) {
 94  1
         String storyAsText = configuration.storyLoader().loadStoryAsText(storyPath);
 95  1
         return configuration.storyParser().parseStory(storyAsText, storyPath);
 96  
     }
 97  
 
 98  
         private boolean isDryRun(List<CandidateSteps> candidateSteps) {
 99  11
                 for (CandidateSteps steps : candidateSteps) {
 100  11
                         if (steps.configuration().dryRun()) {
 101  2
                                 return true;
 102  
                         }
 103  
                 }
 104  9
                 return false;
 105  
         }
 106  
 
 107  
         private StoryReporter reporterFor(Configuration configuration,
 108  
                         Story story, boolean givenStory) {
 109  11
                 if ( givenStory ){                        
 110  1
                         return configuration.storyReporter(reporterStoryPath);
 111  
                 } else {
 112  
                         // store parent story path for reporting
 113  10
                         reporterStoryPath = story.getPath();
 114  10
                         return configuration.storyReporter(reporterStoryPath);
 115  
                 }
 116  
         }
 117  
 
 118  
         private void resetFailureState(boolean givenStory) {
 119  11
                 if ( givenStory ) {
 120  
                         // do not reset failure state for given stories
 121  1
                         return;
 122  
                 }
 123  10
                 currentStrategy = new SilentlyAbsorbingFailure();
 124  10
                 storyFailure = null;
 125  10
         }
 126  
         
 127  
     private void runGivenStories(Configuration configuration,
 128  
                                  List<CandidateSteps> candidateSteps, Scenario scenario)
 129  
             throws Throwable {
 130  15
         List<String> storyPaths = scenario.getGivenStoryPaths();
 131  15
         if (storyPaths.size() > 0) {
 132  1
             reporter.givenStories(storyPaths);
 133  1
             for (String storyPath : storyPaths) {
 134  
                 // run given story 
 135  1
                 Story story = storyOfPath(configuration, storyPath);
 136  1
                 run(configuration, candidateSteps, story, true);
 137  1
             }
 138  
         }
 139  15
     }
 140  
 
 141  
     private boolean isExamplesTableScenario(Scenario scenario) {
 142  15
         return scenario.getExamplesTable().getRowCount() > 0;
 143  
     }
 144  
 
 145  
     private void runExamplesTableScenario(
 146  
             List<CandidateSteps> candidateSteps, Scenario scenario) {
 147  1
         ExamplesTable table = scenario.getExamplesTable();
 148  1
         reporter.beforeExamples(scenario.getSteps(), table);
 149  1
         for (Map<String, String> tableRow : table.getRows()) {
 150  1
             reporter.example(tableRow);
 151  1
             runScenarioSteps(candidateSteps, scenario, tableRow);
 152  
         }
 153  1
         reporter.afterExamples();
 154  1
     }
 155  
 
 156  
     private void runStorySteps(List<CandidateSteps> candidateSteps, Story story, boolean givenStory, Stage stage) {
 157  22
         runSteps(stepCollector.collectBeforeOrAfterStorySteps(candidateSteps, story, stage, givenStory));
 158  22
     }
 159  
 
 160  
     private void runScenarioSteps(
 161  
             List<CandidateSteps> candidateSteps, Scenario scenario, Map<String, String> tableRow) {
 162  15
         runSteps(stepCollector.collectScenarioSteps(candidateSteps, scenario, tableRow));
 163  15
     }
 164  
 
 165  
     /**
 166  
      * Runs a list of steps, while keeping state
 167  
      *
 168  
      * @param steps the Steps to run
 169  
      */
 170  
     private void runSteps(List<Step> steps) {
 171  39
         if (steps == null || steps.size() == 0) return;
 172  19
         state = new FineSoFar();
 173  19
         for (Step step : steps) {
 174  28
             state.run(step);
 175  
         }
 176  19
     }
 177  
 
 178  18
     private class SomethingHappened implements State {
 179  
         public void run(Step step) {
 180  5
             StepResult result = step.doNotPerform();
 181  5
             result.describeTo(reporter);
 182  5
         }
 183  
     }
 184  
 
 185  156
     private final class FineSoFar implements State {
 186  
 
 187  
         public void run(Step step) {
 188  
 
 189  23
             StepResult result = step.perform();
 190  23
             result.describeTo(reporter);
 191  23
             Throwable scenarioFailure = result.getFailure();
 192  23
             if (scenarioFailure != null) {
 193  9
                 state = new SomethingHappened();
 194  9
                 storyFailure = mostImportantOf(storyFailure, scenarioFailure);
 195  9
                 currentStrategy = strategyFor(storyFailure);
 196  
             }
 197  23
         }
 198  
 
 199  
         private Throwable mostImportantOf(
 200  
                 Throwable failure1,
 201  
                 Throwable failure2) {
 202  9
             return failure1 == null ? failure2 :
 203  
                     failure1 instanceof PendingStepFound ? (failure2 == null ? failure1 : failure2) :
 204  
                             failure1;
 205  
         }
 206  
 
 207  
         private FailureStrategy strategyFor(Throwable failure) {
 208  9
             if (failure instanceof PendingStepFound) {
 209  4
                 return pendingStepStrategy;
 210  
             } else {
 211  5
                 return failureStrategy;
 212  
             }
 213  
         }
 214  
     }
 215  
 
 216  59
     private interface State {
 217  
         void run(Step step);
 218  
     }
 219  
     
 220  
         @Override
 221  
         public String toString() {
 222  1
                 return this.getClass().getSimpleName();
 223  
         }
 224  
 
 225  
 
 226  
 }