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