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