Coverage Report - org.jbehave.core.steps.StepCandidate
 
Classes in this File Line Coverage Branch Coverage Complexity
StepCandidate
97%
68/70
87%
21/24
1.556
 
 1  
 package org.jbehave.core.steps;
 2  
 
 3  
 import java.lang.reflect.Method;
 4  
 import java.util.List;
 5  
 import java.util.Map;
 6  
 
 7  
 import org.apache.commons.lang.StringUtils;
 8  
 import org.jbehave.core.annotations.Given;
 9  
 import org.jbehave.core.annotations.Pending;
 10  
 import org.jbehave.core.annotations.Then;
 11  
 import org.jbehave.core.annotations.When;
 12  
 import org.jbehave.core.configuration.Keywords;
 13  
 import org.jbehave.core.configuration.Keywords.StartingWordNotFound;
 14  
 import org.jbehave.core.parsers.StepMatcher;
 15  
 import org.jbehave.core.parsers.StepPatternParser;
 16  
 
 17  
 import com.thoughtworks.paranamer.Paranamer;
 18  
 
 19  
 /**
 20  
  * A StepCandidate is associated to a Java method annotated with {@link Given},
 21  
  * {@link When}, {@link Then} in a steps instance class. The StepCandidate is
 22  
  * responsible for matching the textual step against the pattern contained in
 23  
  * the method annotation via the {@link StepMatcher} and for the creation of the
 24  
  * matched executable step via the {@link StepCreator}.
 25  
  */
 26  
 public class StepCandidate {
 27  
 
 28  
     private final String patternAsString;
 29  
     private final Integer priority;
 30  
     private final StepType stepType;
 31  
     private final Method method;
 32  
     private final Class<?> stepsType;
 33  
     private final InjectableStepsFactory stepsFactory;
 34  
     private final Keywords keywords;
 35  
     private final StepMatcher stepMatcher;
 36  
     private final StepCreator stepCreator;
 37  
     private String[] composedSteps;
 38  94
     private StepMonitor stepMonitor = new SilentStepMonitor();
 39  
 
 40  
     public StepCandidate(String patternAsString, int priority, StepType stepType, Method method, Class<?> stepsType,
 41  
             InjectableStepsFactory stepsFactory, Keywords keywords, StepPatternParser stepPatternParser,
 42  94
             ParameterConverters parameterConverters) {
 43  94
         this.patternAsString = patternAsString;
 44  94
         this.priority = priority;
 45  94
         this.stepType = stepType;
 46  94
         this.method = method;
 47  94
         this.stepsType = stepsType;
 48  94
         this.stepsFactory = stepsFactory;
 49  94
         this.keywords = keywords;
 50  94
         this.stepMatcher = stepPatternParser.parseStep(stepType, patternAsString);
 51  94
         this.stepCreator = new StepCreator(stepsType, stepsFactory, parameterConverters, stepMatcher, stepMonitor);
 52  94
     }
 53  
 
 54  
     public Method getMethod() {
 55  7
         return method;
 56  
     }
 57  
 
 58  
     public Integer getPriority() {
 59  1
         return priority;
 60  
     }
 61  
 
 62  
     public String getPatternAsString() {
 63  80
         return patternAsString;
 64  
     }
 65  
 
 66  
     public Object getStepsInstance() {
 67  7
         return stepsFactory.createInstanceOfType(stepsType);
 68  
     }
 69  
 
 70  
     public StepType getStepType() {
 71  123
         return stepType;
 72  
     }
 73  
 
 74  
     public String getStartingWord() {
 75  44
         return keywords.startingWordFor(stepType);
 76  
     }
 77  
 
 78  
     public void useStepMonitor(StepMonitor stepMonitor) {
 79  64
         this.stepMonitor = stepMonitor;
 80  64
         this.stepCreator.useStepMonitor(stepMonitor);
 81  64
     }
 82  
 
 83  
     public void doDryRun(boolean dryRun) {
 84  64
         this.stepCreator.doDryRun(dryRun);
 85  64
     }
 86  
 
 87  
     public void useParanamer(Paranamer paranamer) {
 88  67
         this.stepCreator.useParanamer(paranamer);
 89  67
     }
 90  
 
 91  
     public void composedOf(String[] steps) {
 92  5
         this.composedSteps = steps;
 93  5
     }
 94  
 
 95  
     public boolean isComposite() {
 96  15
         return composedSteps != null && composedSteps.length > 0;
 97  
     }
 98  
 
 99  
     public String[] composedSteps() {
 100  2
         return composedSteps;
 101  
     }
 102  
 
 103  
     public boolean ignore(String stepAsString) {
 104  
         try {
 105  4
             String ignoreWord = keywords.startingWordFor(StepType.IGNORABLE);
 106  3
             return keywords.stepStartsWithWord(stepAsString, ignoreWord);
 107  1
         } catch (StartingWordNotFound e) {
 108  1
             return false;
 109  
         }
 110  
     }
 111  
 
 112  
     public boolean isPending() {
 113  4
         return method.isAnnotationPresent(Pending.class);
 114  
     }
 115  
 
 116  
     public boolean matches(String stepAsString) {
 117  16
         return matches(stepAsString, null);
 118  
     }
 119  
 
 120  
     public boolean matches(String step, String previousNonAndStep) {
 121  
         try {
 122  18
             boolean matchesType = true;
 123  18
             if (isAndStep(step)) {
 124  2
                 if (previousNonAndStep == null) {
 125  
                     // cannot handle AND step with no previous step
 126  1
                     matchesType = false;
 127  
                 } else {
 128  
                     // previous step type should match candidate step type
 129  1
                     matchesType = keywords.startingWordFor(stepType).equals(findStartingWord(previousNonAndStep));
 130  
                 }
 131  
             }
 132  17
             stepMonitor.stepMatchesType(step, previousNonAndStep, matchesType, stepType, method, stepsType);
 133  17
             boolean matchesPattern = stepMatcher.matches(stripStartingWord(step));
 134  13
             stepMonitor.stepMatchesPattern(step, matchesPattern, stepMatcher.pattern(), method, stepsType);
 135  
             // must match both type and pattern
 136  13
             return matchesType && matchesPattern;
 137  5
         } catch (StartingWordNotFound e) {
 138  5
             return false;
 139  
         }
 140  
     }
 141  
 
 142  
     public Step createMatchedStep(String stepAsString, Map<String, String> namedParameters) {
 143  72
         return stepCreator.createParametrisedStep(method, stepAsString, stripStartingWord(stepAsString),
 144  
                 namedParameters);
 145  
     }
 146  
 
 147  
     public void addComposedSteps(List<Step> steps, String stepAsString, Map<String, String> namedParameters,
 148  
             List<StepCandidate> allCandidates) {
 149  3
         addComposedStepsRecursively(steps, stepAsString, namedParameters, allCandidates, composedSteps);
 150  3
     }
 151  
 
 152  
     private void addComposedStepsRecursively(List<Step> steps, String stepAsString,
 153  
             Map<String, String> namedParameters, List<StepCandidate> allCandidates, String[] composedSteps) {
 154  5
         Map<String, String> matchedParameters = stepCreator.matchedParameters(method, stepAsString,
 155  
                 stripStartingWord(stepAsString), namedParameters);
 156  5
         matchedParameters.putAll(namedParameters);
 157  15
         for (String composedStep : composedSteps) {
 158  10
             addComposedStep(steps, composedStep, matchedParameters, allCandidates);
 159  
         }
 160  5
     }
 161  
 
 162  
     private void addComposedStep(List<Step> steps, String composedStep, Map<String, String> matchedParameters,
 163  
             List<StepCandidate> allCandidates) {
 164  10
         StepCandidate candidate = findComposedCandidate(composedStep, allCandidates);
 165  10
         if (candidate != null) {
 166  10
             steps.add(candidate.createMatchedStep(composedStep, matchedParameters));
 167  10
             if (candidate.isComposite()) {
 168  
                 // candidate is itself composite: recursively add composed steps
 169  2
                 addComposedStepsRecursively(steps, composedStep, matchedParameters, allCandidates,
 170  
                         candidate.composedSteps());
 171  
             }
 172  
         } else {
 173  0
             steps.add(StepCreator.createPendingStep(composedStep, null));
 174  
         }
 175  10
     }
 176  
 
 177  
     private StepCandidate findComposedCandidate(String composedStep, List<StepCandidate> allCandidates) {
 178  10
         for (StepCandidate candidate : allCandidates) {
 179  37
             if (StringUtils.startsWith(composedStep, candidate.getStartingWord())
 180  
                     && StringUtils.endsWith(composedStep, candidate.getPatternAsString())) {
 181  10
                 return candidate;
 182  
             }
 183  
         }
 184  0
         return null;
 185  
     }
 186  
 
 187  
     public boolean isAndStep(String stepAsString) {
 188  20
         return keywords.isAndStep(stepAsString);
 189  
     }
 190  
 
 191  
     public boolean isIgnorableStep(String stepAsString) {
 192  2
         return keywords.isIgnorableStep(stepAsString);
 193  
     }
 194  
 
 195  
     private String findStartingWord(String stepAsString) {
 196  1
         return keywords.startingWord(stepAsString, stepType);
 197  
     }
 198  
 
 199  
     private String stripStartingWord(String stepAsString) {
 200  94
         return keywords.stepWithoutStartingWord(stepAsString, stepType);
 201  
     }
 202  
 
 203  
     @Override
 204  
     public String toString() {
 205  93
         return stepType + " " + patternAsString;
 206  
     }
 207  
 
 208  
 }