##### Coverage Report - org.jbehave.core.steps.StepCandidate

Classes in this File | Line Coverage | Branch Coverage | Complexity
StepCandidate |
98% | 70/71
96% | 25/26
| 1.5714285714285714;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 | 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 Class<?> getStepsType() {
72 | 0 |
             return stepsType;
73 |  |
         }
74 |  |
75 |  |
         public StepType getStepType() {
76 | 145 |
             return stepType;
77 |  |
         }
78 |  |
79 |  |
         public String getStartingWord() {
80 | 76 |
             return keywords.startingWordFor(stepType);
81 |  |
         }
82 |  |
83 |  |
         public void useStepMonitor(StepMonitor stepMonitor) {
84 | 74 |
             this.stepMonitor = stepMonitor;
85 | 74 |
             this.stepCreator.useStepMonitor(stepMonitor);
86 | 74 |
         }
87 |  |
88 |  |
         public void doDryRun(boolean dryRun) {
89 | 74 |
             this.stepCreator.doDryRun(dryRun);
90 | 74 |
         }
91 |  |
92 |  |
         public void useParanamer(Paranamer paranamer) {
93 | 77 |
             this.stepCreator.useParanamer(paranamer);
94 | 77 |
         }
95 |  |
96 |  |
         public void composedOf(String[] steps) {
97 | 8 |
             this.composedSteps = steps;
98 | 8 |
         }
99 |  |
100 |  |
         public boolean isComposite() {
101 | 21 |
             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 | 4 |
                 String ignoreWord = keywords.startingWordFor(StepType.IGNORABLE);
111 | 3 |
                 return keywords.stepStartsWithWord(stepAsString, ignoreWord);
112 | 1 |
             } catch (StartingWordNotFound e) {
113 | 1 |
                 return false;
114 |  |
             }
115 |  |
         }
116 |  |
117 |  |
         public boolean isPending() {
118 | 4 |
             return method.isAnnotationPresent(Pending.class);
119 |  |
         }
120 |  |
121 |  |
         public boolean matches(String stepAsString) {
122 | 60 |
             return matches(stepAsString, null);
123 |  |
         }
124 |  |
125 |  |
         public boolean matches(String step, String previousNonAndStep) {
126 |  |
             try {
127 | 62 |
                 boolean matchesType = true;
128 | 62 |
                 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 | 61 |
                 stepMonitor.stepMatchesType(step, previousNonAndStep, matchesType, stepType, method, stepsType);
138 | 61 |
                 boolean matchesPattern = stepMatcher.matches(stripStartingWord(step));
139 | 55 |
                 stepMonitor.stepMatchesPattern(step, matchesPattern, stepMatcher.pattern(), method, stepsType);
140 |  |
                 // must match both type and pattern
141 | 55 |
                 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 | 77 |
             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 | 69 |
                 if (StringUtils.startsWith(composedStep, candidate.getStartingWord())
185 |  |
                         && (StringUtils.endsWith(composedStep, candidate.getPatternAsString()) || candidate
186 |  |
                                 .matches(composedStep))) {
187 | 14 |
                     return candidate;
188 |  |
                 }
189 |  |
             }
190 | 3 |
             return null;
191 |  |
         }
192 |  |
193 |  |
         public boolean isAndStep(String stepAsString) {
194 | 64 |
             return keywords.isAndStep(stepAsString);
195 |  |
         }
196 |  |
197 |  |
         public boolean isIgnorableStep(String stepAsString) {
198 | 2 |
             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 | 146 |
             return keywords.stepWithoutStartingWord(stepAsString, stepType);
207 |  |
         }
208 |  |
209 |  |
         @Override
210 |  |
         public String toString() {
211 | 93 |
             return stepType + " " + patternAsString;
212 |  |
         }
213 |  |
214 |  |
     }