1 | |
package org.jbehave.core.parsers.gherkin; |
2 | |
|
3 | |
import gherkin.formatter.Formatter; |
4 | |
import gherkin.formatter.model.Background; |
5 | |
import gherkin.formatter.model.Examples; |
6 | |
import gherkin.formatter.model.Feature; |
7 | |
import gherkin.formatter.model.Row; |
8 | |
import gherkin.formatter.model.Scenario; |
9 | |
import gherkin.formatter.model.ScenarioOutline; |
10 | |
import gherkin.formatter.model.Step; |
11 | |
import gherkin.formatter.model.Tag; |
12 | |
import gherkin.parser.Parser; |
13 | |
|
14 | |
import java.util.List; |
15 | |
import java.util.regex.Matcher; |
16 | |
|
17 | |
import org.jbehave.core.i18n.LocalizedKeywords; |
18 | |
import org.jbehave.core.parsers.RegexStoryParser; |
19 | |
import org.jbehave.core.parsers.StoryParser; |
20 | |
import org.jbehave.core.parsers.StoryTransformer; |
21 | |
import org.jbehave.core.parsers.TransformingStoryParser; |
22 | |
|
23 | |
import static java.util.regex.Pattern.DOTALL; |
24 | |
import static java.util.regex.Pattern.compile; |
25 | |
|
26 | |
public class GherkinStoryParser extends TransformingStoryParser { |
27 | |
|
28 | |
public GherkinStoryParser(){ |
29 | 6 | this(new RegexStoryParser()); |
30 | 6 | } |
31 | |
|
32 | |
public GherkinStoryParser(StoryParser delegate){ |
33 | 6 | super(delegate, new GherkinTransformer()); |
34 | 6 | } |
35 | |
|
36 | 37 | public static class GherkinTransformer implements StoryTransformer { |
37 | |
|
38 | |
private LocalizedKeywords keywords; |
39 | |
|
40 | |
public GherkinTransformer() { |
41 | 6 | this(new LocalizedKeywords()); |
42 | 6 | } |
43 | |
|
44 | 6 | public GherkinTransformer(LocalizedKeywords keywords) { |
45 | 6 | this.keywords = keywords; |
46 | 6 | } |
47 | |
|
48 | |
public String transform(String storyAsText) { |
49 | 6 | final StringBuffer out = new StringBuffer(); |
50 | |
|
51 | 6 | Formatter formatter = new Formatter(){ |
52 | |
public void uri(String uri) { |
53 | 6 | out.append(uri).append("\n"); |
54 | 6 | } |
55 | |
|
56 | |
public void feature(Feature feature) { |
57 | 6 | out.append(feature.getName()).append("\n\n"); |
58 | 6 | writeNarrative(feature.getDescription()); |
59 | 6 | writeMeta(feature.getTags()); |
60 | 6 | } |
61 | |
|
62 | |
private void writeMeta(List<Tag> tags) { |
63 | 12 | if (tags.isEmpty()) { |
64 | 9 | return; |
65 | |
} |
66 | 3 | out.append(keywords.meta()).append(" "); |
67 | 3 | for (Tag tag : tags) { |
68 | 3 | out.append(tag.getName()).append(" "); |
69 | 3 | } |
70 | 3 | out.append("\n"); |
71 | 3 | } |
72 | |
|
73 | |
private void writeNarrative(String description) { |
74 | 6 | boolean matches = false; |
75 | 6 | Matcher findingNarrative = compile(".*" + keywords.narrative() + "(.*?)", DOTALL).matcher(description); |
76 | 6 | if (findingNarrative.matches()) { |
77 | 2 | String narrative = findingNarrative.group(1).trim(); |
78 | 2 | matches = writeNarrativeWithDefaultSyntax(out, narrative); |
79 | 2 | if (!matches){ |
80 | 1 | matches = writeNarrativeWithAlternativeSyntax(out, narrative); |
81 | |
} |
82 | |
} |
83 | 6 | if (!matches){ |
84 | |
|
85 | 4 | out.append(description); |
86 | |
} |
87 | 6 | } |
88 | |
|
89 | |
private boolean writeNarrativeWithDefaultSyntax(final StringBuffer out, String narrative) { |
90 | 2 | boolean matches = false; |
91 | 2 | Matcher findingElements = compile(".*" + keywords.inOrderTo() + "(.*)\\s*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo() |
92 | |
+ "(.*)", DOTALL).matcher(narrative); |
93 | 2 | if (findingElements.matches()) { |
94 | 1 | String inOrderTo = findingElements.group(1).trim(); |
95 | 1 | String asA = findingElements.group(2).trim(); |
96 | 1 | String iWantTo = findingElements.group(3).trim(); |
97 | 1 | out.append(keywords.narrative()).append("\n"); |
98 | 1 | out.append(keywords.inOrderTo()).append(" ").append(inOrderTo).append("\n"); |
99 | 1 | out.append(keywords.asA()).append(" ").append(asA).append("\n"); |
100 | 1 | out.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n"); |
101 | 1 | matches = true; |
102 | |
} |
103 | 2 | return matches; |
104 | |
} |
105 | |
|
106 | |
private boolean writeNarrativeWithAlternativeSyntax(final StringBuffer out, String narrative) { |
107 | 1 | boolean matches = false; |
108 | 1 | Matcher findingElements = compile(".*" + keywords.asA() + "(.*)\\s*" + keywords.iWantTo() + "(.*)\\s*" + keywords.soThat() |
109 | |
+ "(.*)", DOTALL).matcher(narrative); |
110 | 1 | if (findingElements.matches()) { |
111 | 1 | String asA = findingElements.group(1).trim(); |
112 | 1 | String iWantTo = findingElements.group(2).trim(); |
113 | 1 | String soThat = findingElements.group(3).trim(); |
114 | 1 | out.append(keywords.narrative()).append("\n"); |
115 | 1 | out.append(keywords.asA()).append(" ").append(asA).append("\n"); |
116 | 1 | out.append(keywords.iWantTo()).append(" ").append(iWantTo).append("\n\n"); |
117 | 1 | out.append(keywords.soThat()).append(" ").append(soThat).append("\n"); |
118 | 1 | matches = true; |
119 | |
} |
120 | 1 | return matches; |
121 | |
} |
122 | |
|
123 | |
public void background(Background background) { |
124 | 2 | out.append(keywords.lifecycle()+background.getName()).append("\n") |
125 | |
.append(keywords.before()+"\n"); |
126 | 2 | } |
127 | |
|
128 | |
public void scenario(Scenario scenario) { |
129 | 5 | out.append("\n").append(keywords.scenario()+scenario.getName()).append("\n\n"); |
130 | 5 | writeMeta(scenario.getTags()); |
131 | 5 | } |
132 | |
|
133 | |
public void scenarioOutline(ScenarioOutline scenarioOutline) { |
134 | 1 | out.append("\n").append(keywords.scenario()+scenarioOutline.getName()).append("\n\n"); |
135 | 1 | writeMeta(scenarioOutline.getTags()); |
136 | 1 | } |
137 | |
|
138 | |
public void examples(Examples examples) { |
139 | 1 | out.append("\n").append(keywords.examplesTable()+examples.getName()).append("\n"); |
140 | 1 | writeRows(examples.getRows()); |
141 | 1 | } |
142 | |
|
143 | |
public void step(Step step) { |
144 | 15 | out.append(step.getKeyword()+step.getName()).append("\n"); |
145 | 15 | writeRows(step.getRows()); |
146 | 15 | } |
147 | |
|
148 | |
public void eof() { |
149 | 6 | } |
150 | |
|
151 | |
public void syntaxError(String state, String event, |
152 | |
List<String> legalEvents, String uri, Integer line) { |
153 | 0 | } |
154 | |
|
155 | |
public void done() { |
156 | 0 | } |
157 | |
|
158 | |
public void close() { |
159 | 0 | } |
160 | |
|
161 | |
private void writeRows(List<? extends Row> rows) { |
162 | 16 | if ( rows != null && rows.size() > 0 ){ |
163 | 2 | for ( Row row : rows ){ |
164 | 10 | out.append("|"); |
165 | 10 | for ( String c : row.getCells() ){ |
166 | 20 | out.append(c).append("|"); |
167 | 20 | } |
168 | 10 | out.append("\n"); |
169 | 10 | } |
170 | |
} |
171 | 16 | } |
172 | |
|
173 | |
}; |
174 | 6 | new Parser(formatter).parse(storyAsText, "", 0); |
175 | 6 | return out.toString(); |
176 | |
} |
177 | |
} |
178 | |
|
179 | |
} |