GherkinStoryParser.java
package org.jbehave.core.parsers.gherkin;
import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
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 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;
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;
}
@Override
public String transform(String storyAsText) {
final StringBuffer out = new StringBuffer();
Formatter formatter = new Formatter() {
@Override
public void uri(String uri) {
out.append(uri).append("\n");
}
@Override
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);
}
}
@SuppressWarnings("checkstyle:LocalVariableName")
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;
}
@SuppressWarnings("checkstyle:LocalVariableName")
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")
.append(keywords.asA()).append(" ").append(asA).append("\n")
.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n")
.append(keywords.soThat()).append(" ").append(soThat).append("\n");
matches = true;
}
return matches;
}
@Override
public void background(Background background) {
out.append(keywords.lifecycle())
.append(background.getName())
.append("\n")
.append(keywords.before())
.append("\n");
}
@Override
public void scenario(Scenario scenario) {
out.append("\n")
.append(keywords.scenario())
.append(scenario.getName())
.append("\n\n");
writeMeta(scenario.getTags());
}
@Override
public void scenarioOutline(ScenarioOutline scenarioOutline) {
out.append("\n")
.append(keywords.scenario())
.append(scenarioOutline.getName())
.append("\n\n");
writeMeta(scenarioOutline.getTags());
}
@Override
public void examples(Examples examples) {
out.append("\n")
.append(keywords.examplesTable())
.append(examples.getName())
.append("\n");
writeRows(examples.getRows());
}
@Override
public void step(Step step) {
out.append(step.getKeyword())
.append(step.getName())
.append("\n");
writeRows(step.getRows());
}
@Override
public void eof() {
}
@Override
public void syntaxError(String state, String event,
List<String> legalEvents, String uri, Integer line) {
}
@Override
public void done() {
}
@Override
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();
}
}
}