package org.jbehave.core.parsers.gherkin; import gherkin.formatter.Formatter; import gherkin.formatter.model.Background; import gherkin.formatter.model.Examples; import gherkin.formatter.model.Feature; import gherkin.formatter.model.Row; import gherkin.formatter.model.Scenario; import gherkin.formatter.model.ScenarioOutline; import gherkin.formatter.model.Step; import gherkin.formatter.model.Tag; import gherkin.parser.Parser; import java.util.List; import java.util.regex.Matcher; import org.jbehave.core.i18n.LocalizedKeywords; import org.jbehave.core.parsers.RegexStoryParser; import org.jbehave.core.parsers.StoryParser; import org.jbehave.core.parsers.StoryTransformer; import org.jbehave.core.parsers.TransformingStoryParser; import static java.util.regex.Pattern.DOTALL; import static java.util.regex.Pattern.compile; public class GherkinStoryParser extends TransformingStoryParser { public GherkinStoryParser(){ this(new RegexStoryParser()); } public GherkinStoryParser(StoryParser delegate){ super(delegate, new GherkinTransformer()); } public static class GherkinTransformer implements StoryTransformer { private LocalizedKeywords keywords; public GherkinTransformer() { this(new LocalizedKeywords()); } public GherkinTransformer(LocalizedKeywords keywords) { this.keywords = keywords; } public String transform(String storyAsText) { final StringBuffer out = new StringBuffer(); Formatter formatter = new Formatter(){ public void uri(String uri) { out.append(uri).append("\n"); } public void feature(Feature feature) { out.append(feature.getName()).append("\n\n"); writeNarrative(feature.getDescription()); writeMeta(feature.getTags()); } private void writeMeta(List<Tag> tags) { if (tags.isEmpty()) { return; } out.append(keywords.meta()).append(" "); for (Tag tag : tags) { out.append(tag.getName()).append(" "); } out.append("\n"); } private void writeNarrative(String description) { boolean matches = false; Matcher findingNarrative = compile(".*" + keywords.narrative() + "(.*?)", DOTALL).matcher(description); if (findingNarrative.matches()) { String narrative = findingNarrative.group(1).trim(); matches = writeNarrativeWithDefaultSyntax(out, narrative); if (!matches){ matches = writeNarrativeWithAlternativeSyntax(out, narrative); } } if (!matches){ // if narrative format does not match, write description as part of story description out.append(description); } } private boolean writeNarrativeWithDefaultSyntax(final StringBuffer out, String narrative) { boolean matches = false; Matcher findingElements = compile(".*" + keywords.inOrderTo() + "(.*)\\s*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo() + "(.*)", DOTALL).matcher(narrative); if (findingElements.matches()) { String inOrderTo = findingElements.group(1).trim(); String asA = findingElements.group(2).trim(); String iWantTo = findingElements.group(3).trim(); out.append(keywords.narrative()).append("\n"); out.append(keywords.inOrderTo()).append(" ").append(inOrderTo).append("\n"); out.append(keywords.asA()).append(" ").append(asA).append("\n"); out.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n"); matches = true; } return matches; } private boolean writeNarrativeWithAlternativeSyntax(final StringBuffer out, String narrative) { boolean matches = false; Matcher findingElements = compile(".*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo() + "(.*)\\s*" + keywords.soThat() + "(.*)", DOTALL).matcher(narrative); if (findingElements.matches()) { String asA = findingElements.group(1).trim(); String iWantTo = findingElements.group(2).trim(); String soThat = findingElements.group(3).trim(); out.append(keywords.narrative()).append("\n"); out.append(keywords.asA()).append(" ").append(asA).append("\n"); out.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n"); out.append(keywords.soThat()).append(" ").append(soThat).append("\n"); matches = true; } return matches; } public void background(Background background) { out.append(keywords.lifecycle()+background.getName()).append("\n") .append(keywords.before()+"\n"); } public void scenario(Scenario scenario) { out.append("\n").append(keywords.scenario()+scenario.getName()).append("\n\n"); writeMeta(scenario.getTags()); } public void scenarioOutline(ScenarioOutline scenarioOutline) { out.append("\n").append(keywords.scenario()+scenarioOutline.getName()).append("\n\n"); writeMeta(scenarioOutline.getTags()); } public void examples(Examples examples) { out.append("\n").append(keywords.examplesTable()+examples.getName()).append("\n"); writeRows(examples.getRows()); } public void step(Step step) { out.append(step.getKeyword()+step.getName()).append("\n"); writeRows(step.getRows()); } public void eof() { } public void syntaxError(String state, String event, List<String> legalEvents, String uri, Integer line) { } public void done() { } public void close() { } private void writeRows(List<? extends Row> rows) { if ( rows != null && rows.size() > 0 ){ for ( Row row : rows ){ out.append("|"); for ( String c : row.getCells() ){ out.append(c).append("|"); } out.append("\n"); } } } }; new Parser(formatter).parse(storyAsText, "", 0); return out.toString(); } } }