##### Coverage Report - org.jbehave.core.reporters.TemplateableOutput

Classes in this File | Line Coverage | Branch Coverage | Complexity
TemplateableOutput |
84% | 77/91
43% | 7/16
| 1.3627450980392157;1.363
TemplateableOutput$OutputKeywords |
62% | 18/29
N/A | N/A
| 1.3627450980392157;1.363
TemplateableOutput$OutputMeta |
100% | 7/7
100% | 2/2
| 1.3627450980392157;1.363
TemplateableOutput$OutputNarrative |
100% | 6/6
N/A | N/A
| 1.3627450980392157;1.363
TemplateableOutput$OutputParameter |
100% | 7/7
N/A | N/A
| 1.3627450980392157;1.363
TemplateableOutput$OutputRestart |
100% | 2/2
N/A | N/A
| 1.3627450980392157;1.363
TemplateableOutput$OutputScenario |
91% | 22/24
83% | 5/6
| 1.3627450980392157;1.363
TemplateableOutput$OutputStep |
78% | 45/57
66% | 16/24
| 1.3627450980392157;1.363
TemplateableOutput$OutputStep$StepFormattingFailed |
0% | 0/2
N/A | N/A
| 1.3627450980392157;1.363
TemplateableOutput$OutputStory |
90% | 10/11
N/A | N/A
| 1.3627450980392157;1.363

1 |  |
     package org.jbehave.core.reporters;
2 |  |
3 |  |
     import java.io.File;
4 |  |
     import java.io.FileWriter;
5 |  |
     import java.io.Writer;
6 |  |
     import java.text.MessageFormat;
7 |  |
     import java.util.ArrayList;
8 |  |
     import java.util.HashMap;
9 |  |
     import java.util.List;
10 |  |
     import java.util.Map;
11 |  |
     import java.util.regex.Matcher;
12 |  |
     import java.util.regex.Pattern;
13 |  |
14 |  |
     import org.apache.commons.lang.StringEscapeUtils;
15 |  |
     import org.apache.commons.lang.StringUtils;
16 |  |
     import org.jbehave.core.configuration.Keywords;
17 |  |
     import org.jbehave.core.model.ExamplesTable;
18 |  |
     import org.jbehave.core.model.GivenStories;
19 |  |
     import org.jbehave.core.model.Meta;
20 |  |
     import org.jbehave.core.model.Narrative;
21 |  |
     import org.jbehave.core.model.OutcomesTable;
22 |  |
     import org.jbehave.core.model.Scenario;
23 |  |
     import org.jbehave.core.model.Story;
24 |  |
     import org.jbehave.core.model.StoryDuration;
25 |  |
26 |  |
     import freemarker.ext.beans.BeansWrapper;
27 |  |
     import freemarker.template.TemplateHashModel;
28 |  |
     import freemarker.template.TemplateModelException;
29 |  |
30 |  |
     import static org.jbehave.core.steps.StepCreator.PARAMETER_TABLE_END;
31 |  |
     import static org.jbehave.core.steps.StepCreator.PARAMETER_TABLE_START;
32 |  |
     import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_END;
33 |  |
     import static org.jbehave.core.steps.StepCreator.PARAMETER_VALUE_START;
34 |  |
35 |  |
     /**
36 |  |
      * <p>
37 |  |
      * Story reporter that outputs to a template.
38 |  |
      * </p>
39 |  |
      */
40 |  |
     public class TemplateableOutput implements StoryReporter {
41 |  |
42 |  |
         private final File file;
43 |  |
         private final Keywords keywords;
44 |  |
         private final TemplateProcessor processor;
45 |  |
         private final String templatePath;
46 | 2 |
         private OutputStory outputStory = new OutputStory();
47 | 2 |
         private OutputScenario outputScenario = new OutputScenario();
48 |  |
         private OutputStep failedStep;
49 |  |
50 | 2 |
         public TemplateableOutput(File file, Keywords keywords, TemplateProcessor processor, String templatePath) {
51 | 2 |
             this.file = file;
52 | 2 |
             this.keywords = keywords;
53 | 2 |
             this.processor = processor;
54 | 2 |
             this.templatePath = templatePath;
55 | 2 |
         }
56 |  |
57 |  |
         public void storyNotAllowed(Story story, String filter) {
58 | 0 |
             this.outputStory.notAllowedBy = filter;
59 | 0 |
         }
60 |  |
61 |  |
         public void beforeStory(Story story, boolean givenStory) {
62 | 2 |
             if (!givenStory) {
63 | 2 |
                 this.outputStory = new OutputStory();
64 | 2 |
                 this.outputStory.description = story.getDescription().asString();
65 | 2 |
                 this.outputStory.path = story.getPath();
66 |  |
             }
67 | 2 |
             if (!story.getMeta().isEmpty()) {
68 | 2 |
                 this.outputStory.meta = new OutputMeta(story.getMeta());
69 |  |
             }
70 | 2 |
         }
71 |  |
72 |  |
         public void narrative(Narrative narrative) {
73 | 2 |
             if (!narrative.isEmpty()) {
74 | 2 |
                 this.outputStory.narrative = new OutputNarrative(narrative);
75 |  |
             }
76 | 2 |
         }
77 |  |
78 |  |
         public void scenarioNotAllowed(Scenario scenario, String filter) {
79 | 0 |
             this.outputScenario.notAllowedBy = filter;
80 | 0 |
         }
81 |  |
82 |  |
         public void beforeScenario(String title) {
83 | 4 |
             if (this.outputScenario.currentExample == null) {
84 | 4 |
                 this.outputScenario = new OutputScenario();
85 |  |
             }
86 | 4 |
             this.outputScenario.title = title;
87 | 4 |
         }
88 |  |
89 |  |
         public void beforeStep(String step) {
90 | 0 |
         }
91 |  |
92 |  |
         public void successful(String step) {
93 | 22 |
             this.outputScenario.addStep(new OutputStep(step, "successful"));
94 | 22 |
         }
95 |  |
96 |  |
         public void ignorable(String step) {
97 | 2 |
             this.outputScenario.addStep(new OutputStep(step, "ignorable"));
98 | 2 |
         }
99 |  |
100 |  |
         public void pending(String step) {
101 | 0 |
             this.outputScenario.addStep(new OutputStep(step, "pending"));
102 | 0 |
         }
103 |  |
104 |  |
         public void notPerformed(String step) {
105 | 2 |
             this.outputScenario.addStep(new OutputStep(step, "notPerformed"));
106 | 2 |
         }
107 |  |
108 |  |
         public void failed(String step, Throwable storyFailure) {
109 | 6 |
             this.failedStep = new OutputStep(step, "failed");
110 | 6 |
             failedStep.failure = storyFailure;
111 | 6 |
             this.outputScenario.addStep(failedStep);
112 | 6 |
         }
113 |  |
114 |  |
         public void failedOutcomes(String step, OutcomesTable table) {
115 | 2 |
             failed(step, table.failureCause());
116 | 2 |
             this.failedStep.outcomes = table;
117 | 2 |
         }
118 |  |
119 |  |
         public void givenStories(GivenStories givenStories) {
120 | 2 |
             if (!givenStories.getStories().isEmpty()) {
121 | 2 |
                 this.outputScenario.givenStories = givenStories;
122 |  |
             }
123 | 2 |
         }
124 |  |
125 |  |
         public void givenStories(List<String> storyPaths) {
126 | 2 |
             givenStories(new GivenStories(StringUtils.join(storyPaths, ",")));
127 | 2 |
         }
128 |  |
129 |  |
         public void scenarioMeta(Meta meta) {
130 | 0 |
             if (!meta.isEmpty()) {
131 | 0 |
                 this.outputScenario.meta = new OutputMeta(meta);
132 |  |
             }
133 | 0 |
         }
134 |  |
135 |  |
         public void beforeExamples(List<String> steps, ExamplesTable table) {
136 | 2 |
             this.outputScenario.examplesSteps = steps;
137 | 2 |
             this.outputScenario.examplesTable = table;
138 | 2 |
         }
139 |  |
140 |  |
         public void example(Map<String, String> parameters) {
141 | 4 |
             this.outputScenario.examples.add(parameters);
142 | 4 |
             this.outputScenario.currentExample = parameters;
143 | 4 |
         }
144 |  |
145 |  |
         public void afterExamples() {
146 | 2 |
             this.outputScenario.currentExample = null;
147 | 2 |
         }
148 |  |
149 |  |
         public void dryRun() {
150 | 2 |
         }
151 |  |
152 |  |
         public void afterScenario() {
153 | 4 |
             if (this.outputScenario.currentExample == null) {
154 | 4 |
                 this.outputStory.scenarios.add(outputScenario);
155 |  |
             }
156 | 4 |
         }
157 |  |
158 |  |
         public void pendingMethods(List<String> methods) {
159 | 2 |
             this.outputStory.pendingMethods = methods;
160 | 2 |
         }
161 |  |
162 |  |
         public void restarted(String step, Throwable cause) {
163 | 2 |
             this.outputScenario.addStep(new OutputRestart(step, cause.getMessage()));
164 | 2 |
         }
165 |  |
166 |  |
         public void storyCancelled(Story story, StoryDuration storyDuration) {
167 | 2 |
             this.outputStory.cancelled = true;
168 | 2 |
             this.outputStory.storyDuration = storyDuration;
169 | 2 |
         }
170 |  |
171 |  |
         public void afterStory(boolean givenStory) {
172 | 2 |
             if (!givenStory) {
173 | 2 |
                 Map<String, Object> model = newDataModel();
174 | 2 |
                 model.put("story", outputStory);
175 | 2 |
                 model.put("keywords", new OutputKeywords(keywords));
176 |  |
177 | 2 |
                 BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
178 | 2 |
                 TemplateHashModel enumModels = wrapper.getEnumModels();
179 |  |
                 TemplateHashModel escapeEnums;
180 |  |
                 try {
181 | 2 |
                     String escapeModeEnum = EscapeMode.class.getCanonicalName();
182 | 2 |
                     escapeEnums = (TemplateHashModel) enumModels.get(escapeModeEnum);
183 | 2 |
                     model.put("EscapeMode", escapeEnums);
184 | 0 |
                 } catch (TemplateModelException e) {
185 | 0 |
                     throw new IllegalArgumentException(e);
186 | 2 |
                 }
187 |  |
188 | 2 |
                 write(file, templatePath, model);
189 |  |
             }
190 | 2 |
         }
191 |  |
192 |  |
         private File write(File file, String resource, Map<String, Object> dataModel) {
193 |  |
             try {
194 | 2 |
                 file.getParentFile().mkdirs();
195 | 2 |
                 Writer writer = new FileWriter(file);
196 | 2 |
                 processor.process(resource, dataModel, writer);
197 | 2 |
                 writer.close();
198 | 2 |
                 return file;
199 | 0 |
             } catch (Exception e) {
200 | 0 |
                 throw new RuntimeException(resource, e);
201 |  |
             }
202 |  |
         }
203 |  |
204 |  |
         private Map<String, Object> newDataModel() {
205 | 2 |
             return new HashMap<String, Object>();
206 |  |
         }
207 |  |
208 |  |
         public static class OutputKeywords {
209 |  |
210 |  |
             private final Keywords keywords;
211 |  |
212 | 2 |
             public OutputKeywords(Keywords keywords) {
213 | 2 |
                 this.keywords = keywords;
214 | 2 |
             }
215 |  |
216 |  |
             public String getMeta() {
217 | 1 |
                 return keywords.meta();
218 |  |
             }
219 |  |
220 |  |
             public String getMetaProperty() {
221 | 4 |
                 return keywords.metaProperty();
222 |  |
             }
223 |  |
224 |  |
             public String getNarrative() {
225 | 2 |
                 return keywords.narrative();
226 |  |
             }
227 |  |
228 |  |
             public String getInOrderTo() {
229 | 2 |
                 return keywords.inOrderTo();
230 |  |
             }
231 |  |
232 |  |
             public String getAsA() {
233 | 2 |
                 return keywords.asA();
234 |  |
             }
235 |  |
236 |  |
             public String getiWantTo() {
237 | 2 |
                 return keywords.iWantTo();
238 |  |
             }
239 |  |
240 |  |
             public String getScenario() {
241 | 4 |
                 return keywords.scenario();
242 |  |
             }
243 |  |
244 |  |
             public String getGivenStories() {
245 | 2 |
                 return keywords.givenStories();
246 |  |
             }
247 |  |
248 |  |
             public String getExamplesTable() {
249 | 2 |
                 return keywords.examplesTable();
250 |  |
             }
251 |  |
252 |  |
             public String getExamplesTableRow() {
253 | 4 |
                 return keywords.examplesTableRow();
254 |  |
             }
255 |  |
256 |  |
             public String getExamplesTableHeaderSeparator() {
257 | 0 |
                 return keywords.examplesTableHeaderSeparator();
258 |  |
             }
259 |  |
260 |  |
             public String getExamplesTableValueSeparator() {
261 | 0 |
                 return keywords.examplesTableValueSeparator();
262 |  |
             }
263 |  |
264 |  |
             public String getExamplesTableIgnorableSeparator() {
265 | 0 |
                 return keywords.examplesTableIgnorableSeparator();
266 |  |
             }
267 |  |
268 |  |
             public String getGiven() {
269 | 0 |
                 return keywords.given();
270 |  |
             }
271 |  |
272 |  |
             public String getWhen() {
273 | 0 |
                 return keywords.when();
274 |  |
             }
275 |  |
276 |  |
             public String getThen() {
277 | 0 |
                 return keywords.then();
278 |  |
             }
279 |  |
280 |  |
             public String getAnd() {
281 | 0 |
                 return keywords.and();
282 |  |
             }
283 |  |
284 |  |
             public String getIgnorable() {
285 | 0 |
                 return keywords.ignorable();
286 |  |
             }
287 |  |
288 |  |
             public String getPending() {
289 | 0 |
                 return keywords.pending();
290 |  |
             }
291 |  |
292 |  |
             public String getNotPerformed() {
293 | 1 |
                 return keywords.notPerformed();
294 |  |
             }
295 |  |
296 |  |
             public String getFailed() {
297 | 3 |
                 return keywords.failed();
298 |  |
             }
299 |  |
300 |  |
             public String getDryRun() {
301 | 0 |
                 return keywords.dryRun();
302 |  |
             }
303 |  |
304 |  |
             public String getStoryCancelled() {
305 | 2 |
                 return keywords.storyCancelled();
306 |  |
             }
307 |  |
308 |  |
             public String getDuration() {
309 | 2 |
                 return keywords.duration();
310 |  |
             }
311 |  |
312 |  |
             public String getYes() {
313 | 0 |
                 return keywords.yes();
314 |  |
             }
315 |  |
316 |  |
             public String getNo() {
317 | 4 |
                 return keywords.no();
318 |  |
             }
319 |  |
         }
320 |  |
321 | 22 |
         public static class OutputStory {
322 |  |
             private String description;
323 |  |
             private String path;
324 |  |
             private OutputMeta meta;
325 |  |
             private OutputNarrative narrative;
326 |  |
             private String notAllowedBy;
327 |  |
             private List<String> pendingMethods;
328 | 4 |
             private List<OutputScenario> scenarios = new ArrayList<OutputScenario>();
329 |  |
             private boolean cancelled;
330 |  |
             private StoryDuration storyDuration;
331 |  |
332 |  |
             public String getDescription() {
333 | 2 |
                 return description;
334 |  |
             }
335 |  |
336 |  |
             public String getPath() {
337 | 2 |
                 return path;
338 |  |
             }
339 |  |
340 |  |
             public OutputMeta getMeta() {
341 | 4 |
                 return meta;
342 |  |
             }
343 |  |
344 |  |
             public OutputNarrative getNarrative() {
345 | 4 |
                 return narrative;
346 |  |
             }
347 |  |
348 |  |
             public String getNotAllowedBy() {
349 | 0 |
                 return notAllowedBy;
350 |  |
             }
351 |  |
352 |  |
             public List<String> getPendingMethods() {
353 | 4 |
                 return pendingMethods;
354 |  |
             }
355 |  |
356 |  |
             public List<OutputScenario> getScenarios() {
357 | 2 |
                 return scenarios;
358 |  |
             }
359 |  |
360 |  |
             public boolean isCancelled() {
361 | 2 |
                 return cancelled;
362 |  |
             }
363 |  |
364 |  |
             public StoryDuration getStoryDuration() {
365 | 2 |
                 return storyDuration;
366 |  |
             }
367 |  |
         }
368 |  |
369 |  |
         public static class OutputMeta {
370 |  |
371 |  |
             private final Meta meta;
372 |  |
373 | 2 |
             public OutputMeta(Meta meta) {
374 | 2 |
                 this.meta = meta;
375 | 2 |
             }
376 |  |
377 |  |
             public Map<String, String> getProperties() {
378 | 2 |
                 Map<String, String> properties = new HashMap<String, String>();
379 | 2 |
                 for (String name : meta.getPropertyNames()) {
380 | 4 |
                     properties.put(name, meta.getProperty(name));
381 |  |
                 }
382 | 2 |
                 return properties;
383 |  |
             }
384 |  |
385 |  |
         }
386 |  |
387 |  |
         public static class OutputNarrative {
388 |  |
             private final Narrative narrative;
389 |  |
390 | 2 |
             public OutputNarrative(Narrative narrative) {
391 | 2 |
                 this.narrative = narrative;
392 | 2 |
             }
393 |  |
394 |  |
             public String getInOrderTo() {
395 | 2 |
                 return narrative.inOrderTo();
396 |  |
             }
397 |  |
398 |  |
             public String getAsA() {
399 | 2 |
                 return narrative.asA();
400 |  |
             }
401 |  |
402 |  |
             public String getiWantTo() {
403 | 2 |
                 return narrative.iWantTo();
404 |  |
             }
405 |  |
406 |  |
         }
407 |  |
408 | 34 |
         public static class OutputScenario {
409 |  |
             private String title;
410 | 6 |
             private List<OutputStep> steps = new ArrayList<OutputStep>();
411 |  |
             private OutputMeta meta;
412 |  |
             private GivenStories givenStories;
413 |  |
             private String notAllowedBy;
414 |  |
             private List<String> examplesSteps;
415 |  |
             private ExamplesTable examplesTable;
416 |  |
             private Map<String, String> currentExample;
417 | 6 |
             private List<Map<String, String>> examples = new ArrayList<Map<String, String>>();
418 | 6 |
             private Map<Map<String, String>, List<OutputStep>> stepsByExample = new HashMap<Map<String, String>, List<OutputStep>>();
419 |  |
420 |  |
             public String getTitle() {
421 | 4 |
                 return title;
422 |  |
             }
423 |  |
424 |  |
             public void addStep(OutputStep outputStep) {
425 | 34 |
                 if (examplesTable == null) {
426 | 24 |
                     steps.add(outputStep);
427 |  |
                 } else {
428 | 10 |
                     List<OutputStep> currentExampleSteps = stepsByExample.get(currentExample);
429 | 10 |
                     if (currentExampleSteps == null) {
430 | 4 |
                         currentExampleSteps = new ArrayList<OutputStep>();
431 | 4 |
                         stepsByExample.put(currentExample, currentExampleSteps);
432 |  |
                     }
433 | 10 |
                     currentExampleSteps.add(outputStep);
434 |  |
                 }
435 | 34 |
             }
436 |  |
437 |  |
             public List<OutputStep> getSteps() {
438 | 2 |
                 return steps;
439 |  |
             }
440 |  |
441 |  |
             public List<OutputStep> getStepsByExample(Map<String, String> example) {
442 | 4 |
                 List<OutputStep> steps = stepsByExample.get(example);
443 | 4 |
                 if (steps == null) {
444 | 0 |
                     return new ArrayList<OutputStep>();
445 |  |
                 }
446 | 4 |
                 return steps;
447 |  |
             }
448 |  |
449 |  |
             public OutputMeta getMeta() {
450 | 4 |
                 return meta;
451 |  |
             }
452 |  |
453 |  |
             public GivenStories getGivenStories() {
454 | 6 |
                 return givenStories;
455 |  |
             }
456 |  |
457 |  |
             public String getNotAllowedBy() {
458 | 0 |
                 return notAllowedBy;
459 |  |
             }
460 |  |
461 |  |
             public List<String> getExamplesSteps() {
462 | 2 |
                 return examplesSteps;
463 |  |
             }
464 |  |
465 |  |
             public ExamplesTable getExamplesTable() {
466 | 6 |
                 return examplesTable;
467 |  |
             }
468 |  |
469 |  |
             public List<Map<String, String>> getExamples() {
470 | 4 |
                 return examples;
471 |  |
             }
472 |  |
         }
473 |  |
474 |  |
         public static class OutputRestart extends OutputStep {
475 |  |
476 |  |
             public OutputRestart(String step, String outcome) {
477 | 2 |
                 super(step, outcome);
478 | 2 |
             }
479 |  |
480 |  |
         }
481 |  |
482 | 8 |
         public static class OutputStep {
483 |  |
             private final String step;
484 |  |
             private final String outcome;
485 |  |
             private Throwable failure;
486 |  |
             private OutcomesTable outcomes;
487 |  |
             private List<OutputParameter> parameters;
488 |  |
             private String stepPattern;
489 |  |
             private String tableAsString;
490 |  |
             private ExamplesTable table;
491 |  |
492 | 34 |
             public OutputStep(String step, String outcome) {
493 | 34 |
                 this.step = step;
494 | 34 |
                 this.outcome = outcome;
495 | 34 |
                 parseTableAsString();
496 | 34 |
                 parseParameters();
497 | 34 |
                 createStepPattern();
498 | 34 |
             }
499 |  |
500 |  |
             public String getStep() {
501 | 0 |
                 return step;
502 |  |
             }
503 |  |
504 |  |
             public String getStepPattern() {
505 | 0 |
                 return stepPattern;
506 |  |
             }
507 |  |
508 |  |
             public List<OutputParameter> getParameters() {
509 | 0 |
                 return parameters;
510 |  |
             }
511 |  |
512 |  |
             public String getOutcome() {
513 | 51 |
                 return outcome;
514 |  |
             }
515 |  |
516 |  |
             public Throwable getFailure() {
517 | 34 |
                 return failure;
518 |  |
             }
519 |  |
520 |  |
             public String getFailureCause() {
521 | 6 |
                 if (failure != null) {
522 | 6 |
                     return new StackTraceFormatter(true).stackTrace(failure);
523 |  |
                 }
524 | 0 |
                 return "";
525 |  |
             }
526 |  |
527 |  |
             public ExamplesTable getTable() {
528 | 34 |
                 return table;
529 |  |
             }
530 |  |
531 |  |
             public OutcomesTable getOutcomes() {
532 | 36 |
                 return outcomes;
533 |  |
             }
534 |  |
535 |  |
             public String getOutcomesFailureCause() {
536 | 2 |
                 if (outcomes.failureCause() != null) {
537 | 2 |
                     return new StackTraceFormatter(true).stackTrace(outcomes.failureCause());
538 |  |
                 }
539 | 0 |
                 return "";
540 |  |
             }
541 |  |
542 |  |
             /*
543 |  |
              * formatting without escaping doesn't make sense unless
544 |  |
              * we do a ftl text output format
545 |  |
              */
546 |  |
             @Deprecated
547 |  |
             public String getFormattedStep(String parameterPattern) {
548 | 0 |
                 return getFormattedStep(EscapeMode.NONE, parameterPattern);
549 |  |
             }
550 |  |
551 |  |
             public String getFormattedStep(EscapeMode outputFormat, String parameterPattern) {
552 |  |
                 // note that escaping the stepPattern string only works
553 |  |
                 // because placeholders for parameters do not contain
554 |  |
                 // special chars (the placeholder is {0} etc)
555 | 34 |
                 String escapedStep = escapeString(outputFormat, stepPattern);
556 | 34 |
                 if (!parameters.isEmpty()) {
557 |  |
                     try {
558 | 6 |
                         return MessageFormat.format(escapedStep, formatParameters(outputFormat, parameterPattern));
559 | 0 |
                     } catch (RuntimeException e) {
560 | 0 |
                         throw new StepFormattingFailed(stepPattern, parameterPattern, parameters, e);
561 |  |
                     }
562 |  |
                 }
563 | 28 |
                 return escapedStep;
564 |  |
             }
565 |  |
566 |  |
             private String escapeString(EscapeMode outputFormat, String string) {
567 | 42 |
                 if(outputFormat==EscapeMode.HTML) {
568 | 21 |
                     return StringEscapeUtils.escapeHtml(string);
569 | 21 |
                 } else if(outputFormat==EscapeMode.XML) {
570 | 21 |
                     return StringEscapeUtils.escapeXml(string);
571 |  |
                 } else {
572 | 0 |
                     return string;
573 |  |
                 }
574 |  |
             }
575 |  |
576 |  |
             private Object[] formatParameters(EscapeMode outputFormat, String parameterPattern) {
577 | 6 |
                 Object[] arguments = new Object[parameters.size()];
578 | 14 |
                 for (int a = 0; a < parameters.size(); a++) {
579 | 8 |
                     arguments[a] = MessageFormat.format(parameterPattern, escapeString(outputFormat, parameters.get(a).getValue()));
580 |  |
                 }
581 | 6 |
                 return arguments;
582 |  |
             }
583 |  |
584 |  |
             private void parseParameters() {
585 |  |
                 // first, look for parameterized scenarios
586 | 34 |
                 parameters = findParameters(PARAMETER_VALUE_START + PARAMETER_VALUE_START, PARAMETER_VALUE_END
587 |  |
                         + PARAMETER_VALUE_END);
588 |  |
                 // second, look for normal scenarios
589 | 34 |
                 if (parameters.isEmpty()) {
590 | 34 |
                     parameters = findParameters(PARAMETER_VALUE_START, PARAMETER_VALUE_END);
591 |  |
                 }
592 | 34 |
             }
593 |  |
594 |  |
             private List<OutputParameter> findParameters(String start, String end) {
595 | 68 |
                 List<OutputParameter> parameters = new ArrayList<OutputParameter>();
596 | 68 |
                 Matcher matcher = Pattern.compile("(" + start + ".*?" + end + ")(\\W|\\Z)",
597 |  |
                         Pattern.DOTALL).matcher(step);
598 | 76 |
                 while (matcher.find()) {
599 | 8 |
                     parameters.add(new OutputParameter(step, matcher.start(), matcher.end()));
600 |  |
                 }
601 | 68 |
                 return parameters;
602 |  |
             }
603 |  |
604 |  |
             private void parseTableAsString() {
605 | 34 |
                 if (step.contains(PARAMETER_TABLE_START) && step.contains(PARAMETER_TABLE_END)) {
606 | 0 |
                     tableAsString = StringUtils.substringBetween(step, PARAMETER_TABLE_START, PARAMETER_TABLE_END);
607 | 0 |
                     table = new ExamplesTable(tableAsString);
608 |  |
                 }
609 | 34 |
             }
610 |  |
611 |  |
             private void createStepPattern() {
612 | 34 |
                 this.stepPattern = step;
613 | 34 |
                 if (tableAsString != null) {
614 | 0 |
                     this.stepPattern = StringUtils.replaceOnce(stepPattern, PARAMETER_TABLE_START + tableAsString
615 |  |
                             + PARAMETER_TABLE_END, "");
616 |  |
                 }
617 | 42 |
                 for (int count = 0; count < parameters.size(); count++) {
618 | 8 |
                     String value = parameters.get(count).toString();
619 | 8 |
                     this.stepPattern = stepPattern.replace(value, "{" + count + "}");
620 |  |
                 }
621 | 34 |
             }
622 |  |
623 |  |
             @SuppressWarnings("serial")
624 |  |
             public static class StepFormattingFailed extends RuntimeException {
625 |  |
626 |  |
                 public StepFormattingFailed(String stepPattern, String parameterPattern, List<OutputParameter> parameters,
627 |  |
                         RuntimeException cause) {
628 | 0 |
                     super("Failed to format step '" + stepPattern + "' with parameter pattern '" + parameterPattern
629 |  |
                             + "' and parameters: " + parameters, cause);
630 | 0 |
                 }
631 |  |
632 |  |
             }
633 |  |
634 |  |
         }
635 |  |
636 |  |
         public static class OutputParameter {
637 |  |
             private final String parameter;
638 |  |
639 | 8 |
             public OutputParameter(String pattern, int start, int end) {
640 | 8 |
                 this.parameter = pattern.substring(start, end).trim();
641 | 8 |
             }
642 |  |
643 |  |
             public String getValue() {
644 | 8 |
                 String value = StringUtils.remove(parameter, PARAMETER_VALUE_START);
645 | 8 |
                 value = StringUtils.remove(value, PARAMETER_VALUE_END);
646 | 8 |
                 return value;
647 |  |
             }
648 |  |
649 |  |
             @Override
650 |  |
             public String toString() {
651 | 8 |
                 return parameter;
652 |  |
             }
653 |  |
         }
654 |  |
655 |  |
     }