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