GherkinStoryParser.java

  1. package org.jbehave.core.parsers.gherkin;

  2. import static java.util.regex.Pattern.DOTALL;
  3. import static java.util.regex.Pattern.compile;

  4. import java.util.List;
  5. import java.util.regex.Matcher;

  6. import org.jbehave.core.i18n.LocalizedKeywords;
  7. import org.jbehave.core.parsers.RegexStoryParser;
  8. import org.jbehave.core.parsers.StoryParser;
  9. import org.jbehave.core.parsers.StoryTransformer;
  10. import org.jbehave.core.parsers.TransformingStoryParser;

  11. import gherkin.formatter.Formatter;
  12. import gherkin.formatter.model.Background;
  13. import gherkin.formatter.model.Examples;
  14. import gherkin.formatter.model.Feature;
  15. import gherkin.formatter.model.Row;
  16. import gherkin.formatter.model.Scenario;
  17. import gherkin.formatter.model.ScenarioOutline;
  18. import gherkin.formatter.model.Step;
  19. import gherkin.formatter.model.Tag;
  20. import gherkin.parser.Parser;

  21. public class GherkinStoryParser extends TransformingStoryParser {

  22.     public GherkinStoryParser() {
  23.         this(new RegexStoryParser());
  24.     }

  25.     public GherkinStoryParser(StoryParser delegate) {
  26.         super(delegate, new GherkinTransformer());
  27.     }

  28.     public static class GherkinTransformer implements StoryTransformer {

  29.         private LocalizedKeywords keywords;
  30.        
  31.         public GherkinTransformer() {
  32.             this(new LocalizedKeywords());
  33.         }

  34.         public GherkinTransformer(LocalizedKeywords keywords) {
  35.             this.keywords = keywords;
  36.         }

  37.         @Override
  38.         public String transform(String storyAsText) {
  39.             final StringBuffer out = new StringBuffer();

  40.             Formatter formatter = new Formatter() {
  41.                 @Override
  42.                 public void uri(String uri) {
  43.                     out.append(uri).append("\n");
  44.                 }

  45.                 @Override
  46.                 public void feature(Feature feature) {
  47.                     out.append(feature.getName()).append("\n\n");
  48.                     writeNarrative(feature.getDescription());
  49.                     writeMeta(feature.getTags());
  50.                 }

  51.                 private void writeMeta(List<Tag> tags) {
  52.                     if (tags.isEmpty()) {
  53.                         return;
  54.                     }
  55.                     out.append(keywords.meta()).append(" ");
  56.                     for (Tag tag : tags) {
  57.                         out.append(tag.getName()).append(" ");
  58.                     }
  59.                     out.append("\n");
  60.                 }

  61.                 private void writeNarrative(String description) {
  62.                     boolean matches = false;
  63.                     Matcher findingNarrative = compile(".*" + keywords.narrative() + "(.*?)", DOTALL).matcher(
  64.                             description);
  65.                     if (findingNarrative.matches()) {
  66.                         String narrative = findingNarrative.group(1).trim();
  67.                         matches = writeNarrativeWithDefaultSyntax(out, narrative);
  68.                         if (!matches) {
  69.                             matches = writeNarrativeWithAlternativeSyntax(out, narrative);
  70.                         }
  71.                     }
  72.                     if (!matches) {
  73.                         // if narrative format does not match, write description as part of story description
  74.                         out.append(description);
  75.                     }                  
  76.                 }

  77.                 @SuppressWarnings("checkstyle:LocalVariableName")
  78.                 private boolean writeNarrativeWithDefaultSyntax(final StringBuffer out, String narrative) {
  79.                     boolean matches = false;
  80.                     Matcher findingElements = compile(
  81.                             ".*" + keywords.inOrderTo() + "(.*)\\s*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo()
  82.                                     + "(.*)", DOTALL).matcher(narrative);
  83.                     if (findingElements.matches()) {
  84.                         String inOrderTo = findingElements.group(1).trim();
  85.                         String asA = findingElements.group(2).trim();
  86.                         String iWantTo = findingElements.group(3).trim();
  87.                         out.append(keywords.narrative()).append("\n");
  88.                         out.append(keywords.inOrderTo()).append(" ").append(inOrderTo).append("\n");
  89.                         out.append(keywords.asA()).append(" ").append(asA).append("\n");
  90.                         out.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n");
  91.                         matches = true;
  92.                     }
  93.                     return matches;
  94.                 }

  95.                 @SuppressWarnings("checkstyle:LocalVariableName")
  96.                 private boolean writeNarrativeWithAlternativeSyntax(final StringBuffer out, String narrative) {
  97.                     boolean matches = false;
  98.                         Matcher findingElements = compile(
  99.                                 ".*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo() + "(.*)\\s*" + keywords.soThat()
  100.                                         + "(.*)", DOTALL).matcher(narrative);
  101.                     if (findingElements.matches()) {
  102.                         String asA = findingElements.group(1).trim();
  103.                         String iWantTo = findingElements.group(2).trim();
  104.                         String soThat = findingElements.group(3).trim();
  105.                         out.append(keywords.narrative()).append("\n")
  106.                                 .append(keywords.asA()).append(" ").append(asA).append("\n")
  107.                                 .append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n")
  108.                                 .append(keywords.soThat()).append(" ").append(soThat).append("\n");
  109.                         matches = true;
  110.                     }
  111.                     return matches;
  112.                 }

  113.                 @Override
  114.                 public void background(Background background) {
  115.                     out.append(keywords.lifecycle())
  116.                             .append(background.getName())
  117.                             .append("\n")
  118.                             .append(keywords.before())
  119.                             .append("\n");
  120.                 }

  121.                 @Override
  122.                 public void scenario(Scenario scenario) {
  123.                     out.append("\n")
  124.                             .append(keywords.scenario())
  125.                             .append(scenario.getName())
  126.                             .append("\n\n");
  127.                     writeMeta(scenario.getTags());
  128.                 }

  129.                 @Override
  130.                 public void scenarioOutline(ScenarioOutline scenarioOutline) {
  131.                     out.append("\n")
  132.                             .append(keywords.scenario())
  133.                             .append(scenarioOutline.getName())
  134.                             .append("\n\n");
  135.                     writeMeta(scenarioOutline.getTags());
  136.                 }

  137.                 @Override
  138.                 public void examples(Examples examples) {
  139.                     out.append("\n")
  140.                             .append(keywords.examplesTable())
  141.                             .append(examples.getName())
  142.                             .append("\n");
  143.                     writeRows(examples.getRows());
  144.                 }

  145.                 @Override
  146.                 public void step(Step step) {
  147.                     out.append(step.getKeyword())
  148.                             .append(step.getName())
  149.                             .append("\n");
  150.                     writeRows(step.getRows());
  151.                 }

  152.                 @Override
  153.                 public void eof() {
  154.                 }

  155.                 @Override
  156.                 public void syntaxError(String state, String event,
  157.                         List<String> legalEvents, String uri, Integer line) {
  158.                 }

  159.                 @Override
  160.                 public void done() {
  161.                 }

  162.                 @Override
  163.                 public void close() {
  164.                 }
  165.                
  166.                 private void writeRows(List<? extends Row> rows) {
  167.                     if (rows != null && rows.size() > 0) {
  168.                         for (Row row : rows) {
  169.                             out.append("|");
  170.                             for (String c : row.getCells()) {
  171.                                 out.append(c).append("|");
  172.                             }
  173.                             out.append("\n");
  174.                         }
  175.                     }
  176.                 }

  177.             };
  178.             new Parser(formatter).parse(storyAsText, "", 0);
  179.             return out.toString();
  180.         }
  181.     }

  182. }