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