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