Coverage Report - org.jbehave.core.embedder.StoryRunner
 
Classes in this File Line Coverage Branch Coverage Complexity
StoryRunner
100%
75/75
96%
31/32
2.368
StoryRunner$1
N/A
N/A
2.368
StoryRunner$FineSoFar
100%
13/13
70%
7/10
2.368
StoryRunner$SomethingHappened
100%
4/4
N/A
2.368
StoryRunner$State
N/A
N/A
2.368
 
 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  143
 public class StoryRunner {
 31  
 
 32  61
     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  
      * @param filter the Filter to apply to the story Meta
 60  
          * @throws Throwable if failures occurred and FailureStrategy dictates it to be re-thrown.
 61  
          */
 62  
     public void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story, MetaFilter filter) throws Throwable {
 63  12
         run(configuration, candidateSteps, story, filter, false);
 64  11
     }
 65  
 
 66  
     private void run(Configuration configuration, List<CandidateSteps> candidateSteps, Story story, MetaFilter filter, boolean givenStory) throws Throwable {
 67  13
         stepCollector = configuration.stepCollector();
 68  13
         reporter = reporterFor(configuration, story, givenStory);
 69  13
         pendingStepStrategy = configuration.pendingStepStrategy();
 70  13
         failureStrategy = configuration.failureStrategy();
 71  
 
 72  13
         if ( !filter.allow(story.getMeta()) ){
 73  1
             reporter.storyNotAllowed(story, filter.asString());
 74  1
             return;
 75  
         }
 76  
 
 77  12
         resetFailureState(givenStory);
 78  
 
 79  12
                 if (isDryRun(candidateSteps)) {
 80  2
                         reporter.dryRun();
 81  
                 }
 82  
 
 83  12
         reporter.beforeStory(story, givenStory);
 84  12
         runStorySteps(candidateSteps, story, givenStory, StepCollector.Stage.BEFORE);
 85  12
         for (Scenario scenario : story.getScenarios()) {
 86  
             // scenario also inherits meta from story
 87  16
             if ( !filter.allow(scenario.getMeta().inheritFrom(story.getMeta())) ){
 88  1
                 reporter.scenarioNotAllowed(scenario, filter.asString());
 89  1
                 continue;
 90  
             }
 91  15
             reporter.beforeScenario(scenario.getTitle());
 92  15
             reporter.scenarioMeta(scenario.getMeta());
 93  15
             runGivenStories(configuration, candidateSteps, scenario, filter); // first run any given stories, if any
 94  15
             if (isExamplesTableScenario(scenario)) { // run as examples table scenario
 95  1
                 runExamplesTableScenario(candidateSteps, scenario);
 96  
             } else { // run as plain old scenario
 97  14
                 runScenarioSteps(candidateSteps, scenario, new HashMap<String, String>());
 98  
             }
 99  15
             reporter.afterScenario();
 100  
         }
 101  12
         runStorySteps(candidateSteps, story, givenStory, StepCollector.Stage.AFTER);
 102  12
         reporter.afterStory(givenStory);
 103  12
         currentStrategy.handleFailure(storyFailure);
 104  11
     }
 105  
     
 106  
     public Story storyOfPath(Configuration configuration, String storyPath) {
 107  1
         String storyAsText = configuration.storyLoader().loadStoryAsText(storyPath);
 108  1
         return configuration.storyParser().parseStory(storyAsText, storyPath);
 109  
     }
 110  
 
 111  
         private boolean isDryRun(List<CandidateSteps> candidateSteps) {
 112  12
                 for (CandidateSteps steps : candidateSteps) {
 113  12
                         if (steps.configuration().dryRun()) {
 114  2
                                 return true;
 115  
                         }
 116  
                 }
 117  10
                 return false;
 118  
         }
 119  
 
 120  
         private StoryReporter reporterFor(Configuration configuration,
 121  
                         Story story, boolean givenStory) {
 122  13
                 if ( givenStory ){                        
 123  1
                         return configuration.storyReporter(reporterStoryPath);
 124  
                 } else {
 125  
                         // store parent story path for reporting
 126  12
                         reporterStoryPath = story.getPath();
 127  12
                         return configuration.storyReporter(reporterStoryPath);
 128  
                 }
 129  
         }
 130  
 
 131  
         private void resetFailureState(boolean givenStory) {
 132  12
                 if ( givenStory ) {
 133  
                         // do not reset failure state for given stories
 134  1
                         return;
 135  
                 }
 136  11
                 currentStrategy = new SilentlyAbsorbingFailure();
 137  11
                 storyFailure = null;
 138  11
         }
 139  
         
 140  
     private void runGivenStories(Configuration configuration,
 141  
                                  List<CandidateSteps> candidateSteps, Scenario scenario, MetaFilter filter)
 142  
             throws Throwable {
 143  15
         List<String> storyPaths = scenario.getGivenStoryPaths();
 144  15
         if (storyPaths.size() > 0) {
 145  1
             reporter.givenStories(storyPaths);
 146  1
             for (String storyPath : storyPaths) {
 147  
                 // run given story 
 148  1
                 Story story = storyOfPath(configuration, storyPath);
 149  1
                 run(configuration, candidateSteps, story, filter, true);
 150  1
             }
 151  
         }
 152  15
     }
 153  
 
 154  
     private boolean isExamplesTableScenario(Scenario scenario) {
 155  15
         return scenario.getExamplesTable().getRowCount() > 0;
 156  
     }
 157  
 
 158  
     private void runExamplesTableScenario(
 159  
             List<CandidateSteps> candidateSteps, Scenario scenario) {
 160  1
         ExamplesTable table = scenario.getExamplesTable();
 161  1
         reporter.beforeExamples(scenario.getSteps(), table);
 162  1
         for (Map<String, String> tableRow : table.getRows()) {
 163  1
             reporter.example(tableRow);
 164  1
             runScenarioSteps(candidateSteps, scenario, tableRow);
 165  
         }
 166  1
         reporter.afterExamples();
 167  1
     }
 168  
 
 169  
     private void runStorySteps(List<CandidateSteps> candidateSteps, Story story, boolean givenStory, Stage stage) {
 170  24
         runSteps(stepCollector.collectBeforeOrAfterStorySteps(candidateSteps, story, stage, givenStory));
 171  24
     }
 172  
 
 173  
     private void runScenarioSteps(
 174  
             List<CandidateSteps> candidateSteps, Scenario scenario, Map<String, String> tableRow) {
 175  15
         runSteps(stepCollector.collectScenarioSteps(candidateSteps, scenario, tableRow));
 176  15
     }
 177  
 
 178  
     /**
 179  
      * Runs a list of steps, while keeping state
 180  
      *
 181  
      * @param steps the Steps to run
 182  
      */
 183  
     private void runSteps(List<Step> steps) {
 184  41
         if (steps == null || steps.size() == 0) return;
 185  19
         state = new FineSoFar();
 186  19
         for (Step step : steps) {
 187  28
             state.run(step);
 188  
         }
 189  19
     }
 190  
 
 191  18
     private class SomethingHappened implements State {
 192  
         public void run(Step step) {
 193  5
             StepResult result = step.doNotPerform();
 194  5
             result.describeTo(reporter);
 195  5
         }
 196  
     }
 197  
 
 198  160
     private final class FineSoFar implements State {
 199  
 
 200  
         public void run(Step step) {
 201  
 
 202  23
             StepResult result = step.perform();
 203  23
             result.describeTo(reporter);
 204  23
             Throwable scenarioFailure = result.getFailure();
 205  23
             if (scenarioFailure != null) {
 206  9
                 state = new SomethingHappened();
 207  9
                 storyFailure = mostImportantOf(storyFailure, scenarioFailure);
 208  9
                 currentStrategy = strategyFor(storyFailure);
 209  
             }
 210  23
         }
 211  
 
 212  
         private Throwable mostImportantOf(
 213  
                 Throwable failure1,
 214  
                 Throwable failure2) {
 215  9
             return failure1 == null ? failure2 :
 216  
                     failure1 instanceof PendingStepFound ? (failure2 == null ? failure1 : failure2) :
 217  
                             failure1;
 218  
         }
 219  
 
 220  
         private FailureStrategy strategyFor(Throwable failure) {
 221  9
             if (failure instanceof PendingStepFound) {
 222  4
                 return pendingStepStrategy;
 223  
             } else {
 224  5
                 return failureStrategy;
 225  
             }
 226  
         }
 227  
     }
 228  
 
 229  61
     private interface State {
 230  
         void run(Step step);
 231  
     }
 232  
     
 233  
         @Override
 234  
         public String toString() {
 235  1
                 return this.getClass().getSimpleName();
 236  
         }
 237  
 
 238  
 
 239  
 }