Coverage Report - org.jbehave.core.steps.StepCandidate
 
Classes in this File Line Coverage Branch Coverage Complexity
StepCandidate
100%
70/70
96%
25/26
1.593
 
 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  105
     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  105
             ParameterConverters parameterConverters, ParameterControls parameterControls) {
 43  105
         this.patternAsString = patternAsString;
 44  105
         this.priority = priority;
 45  105
         this.stepType = stepType;
 46  105
         this.method = method;
 47  105
         this.stepsType = stepsType;
 48  105
         this.stepsFactory = stepsFactory;
 49  105
         this.keywords = keywords;
 50  105
         this.stepMatcher = stepPatternParser.parseStep(stepType, patternAsString);
 51  105
         this.stepCreator = new StepCreator(stepsType, stepsFactory, parameterConverters, parameterControls,
 52  
                 stepMatcher, stepMonitor);
 53  105
     }
 54  
 
 55  
     public Method getMethod() {
 56  7
         return method;
 57  
     }
 58  
 
 59  
     public Integer getPriority() {
 60  1
         return priority;
 61  
     }
 62  
 
 63  
     public String getPatternAsString() {
 64  114
         return patternAsString;
 65  
     }
 66  
 
 67  
     public Object getStepsInstance() {
 68  7
         return stepsFactory.createInstanceOfType(stepsType);
 69  
     }
 70  
 
 71  
     public StepType getStepType() {
 72  145
         return stepType;
 73  
     }
 74  
 
 75  
     public String getStartingWord() {
 76  76
         return keywords.startingWordFor(stepType);
 77  
     }
 78  
 
 79  
     public void useStepMonitor(StepMonitor stepMonitor) {
 80  74
         this.stepMonitor = stepMonitor;
 81  74
         this.stepCreator.useStepMonitor(stepMonitor);
 82  74
     }
 83  
 
 84  
     public void doDryRun(boolean dryRun) {
 85  74
         this.stepCreator.doDryRun(dryRun);
 86  74
     }
 87  
 
 88  
     public void useParanamer(Paranamer paranamer) {
 89  77
         this.stepCreator.useParanamer(paranamer);
 90  77
     }
 91  
 
 92  
     public void composedOf(String[] steps) {
 93  8
         this.composedSteps = steps;
 94  8
     }
 95  
 
 96  
     public boolean isComposite() {
 97  21
         return composedSteps != null && composedSteps.length > 0;
 98  
     }
 99  
 
 100  
     public String[] composedSteps() {
 101  3
         return composedSteps;
 102  
     }
 103  
 
 104  
     public boolean ignore(String stepAsString) {
 105  
         try {
 106  4
             String ignoreWord = keywords.startingWordFor(StepType.IGNORABLE);
 107  3
             return keywords.stepStartsWithWord(stepAsString, ignoreWord);
 108  1
         } catch (StartingWordNotFound e) {
 109  1
             return false;
 110  
         }
 111  
     }
 112  
 
 113  
     public boolean isPending() {
 114  4
         return method.isAnnotationPresent(Pending.class);
 115  
     }
 116  
 
 117  
     public boolean matches(String stepAsString) {
 118  60
         return matches(stepAsString, null);
 119  
     }
 120  
 
 121  
     public boolean matches(String step, String previousNonAndStep) {
 122  
         try {
 123  62
             boolean matchesType = true;
 124  62
             if (isAndStep(step)) {
 125  2
                 if (previousNonAndStep == null) {
 126  
                     // cannot handle AND step with no previous step
 127  1
                     matchesType = false;
 128  
                 } else {
 129  
                     // previous step type should match candidate step type
 130  1
                     matchesType = keywords.startingWordFor(stepType).equals(findStartingWord(previousNonAndStep));
 131  
                 }
 132  
             }
 133  61
             stepMonitor.stepMatchesType(step, previousNonAndStep, matchesType, stepType, method, stepsType);
 134  61
             boolean matchesPattern = stepMatcher.matches(stripStartingWord(step));
 135  55
             stepMonitor.stepMatchesPattern(step, matchesPattern, stepMatcher.pattern(), method, stepsType);
 136  
             // must match both type and pattern
 137  55
             return matchesType && matchesPattern;
 138  7
         } catch (StartingWordNotFound e) {
 139  7
             return false;
 140  
         }
 141  
     }
 142  
 
 143  
     public Step createMatchedStep(String stepAsString, Map<String, String> namedParameters) {
 144  77
         return stepCreator.createParametrisedStep(method, stepAsString, stripStartingWord(stepAsString),
 145  
                 namedParameters);
 146  
     }
 147  
 
 148  
     public void addComposedSteps(List<Step> steps, String stepAsString, Map<String, String> namedParameters,
 149  
             List<StepCandidate> allCandidates) {
 150  5
         addComposedStepsRecursively(steps, stepAsString, namedParameters, allCandidates, composedSteps);
 151  5
     }
 152  
 
 153  
     private void addComposedStepsRecursively(List<Step> steps, String stepAsString,
 154  
             Map<String, String> namedParameters, List<StepCandidate> allCandidates, String[] composedSteps) {
 155  8
         Map<String, String> matchedParameters = stepCreator.matchedParameters(method, stepAsString,
 156  
                 stripStartingWord(stepAsString), namedParameters);
 157  8
         matchedParameters.putAll(namedParameters);
 158  25
         for (String composedStep : composedSteps) {
 159  17
             addComposedStep(steps, composedStep, matchedParameters, allCandidates);
 160  
         }
 161  8
     }
 162  
 
 163  
     private void addComposedStep(List<Step> steps, String composedStep, Map<String, String> matchedParameters,
 164  
             List<StepCandidate> allCandidates) {
 165  17
         StepCandidate candidate = findComposedCandidate(composedStep, allCandidates);
 166  17
         if (candidate != null) {
 167  14
             steps.add(candidate.createMatchedStep(composedStep, matchedParameters));
 168  14
             if (candidate.isComposite()) {
 169  
                 // candidate is itself composite: recursively add composed steps
 170  3
                 addComposedStepsRecursively(steps, composedStep, matchedParameters, allCandidates,
 171  
                         candidate.composedSteps());
 172  
             }
 173  
         } else {
 174  3
             steps.add(StepCreator.createPendingStep(composedStep, null));
 175  
         }
 176  17
     }
 177  
 
 178  
     private StepCandidate findComposedCandidate(String composedStep, List<StepCandidate> allCandidates) {
 179  17
         for (StepCandidate candidate : allCandidates) {
 180  69
             if (StringUtils.startsWith(composedStep, candidate.getStartingWord())
 181  
                     && (StringUtils.endsWith(composedStep, candidate.getPatternAsString()) || candidate
 182  
                             .matches(composedStep))) {
 183  14
                 return candidate;
 184  
             }
 185  
         }
 186  3
         return null;
 187  
     }
 188  
 
 189  
     public boolean isAndStep(String stepAsString) {
 190  64
         return keywords.isAndStep(stepAsString);
 191  
     }
 192  
 
 193  
     public boolean isIgnorableStep(String stepAsString) {
 194  2
         return keywords.isIgnorableStep(stepAsString);
 195  
     }
 196  
 
 197  
     private String findStartingWord(String stepAsString) {
 198  1
         return keywords.startingWord(stepAsString, stepType);
 199  
     }
 200  
 
 201  
     private String stripStartingWord(String stepAsString) {
 202  146
         return keywords.stepWithoutStartingWord(stepAsString, stepType);
 203  
     }
 204  
 
 205  
     @Override
 206  
     public String toString() {
 207  93
         return stepType + " " + patternAsString;
 208  
     }
 209  
 
 210  
 }