aslakhellesoy-gherkin 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ require 'gherkin/parser/table'
2
+ require 'gherkin/parser/misc'
3
+
4
+ module Gherkin
5
+ module Parser
6
+ def self.[](lang)
7
+ require "gherkin/parser/feature_#{lang}"
8
+ Feature
9
+ end
10
+ end
11
+ end
File without changes
@@ -0,0 +1,117 @@
1
+ module Gherkin
2
+ module Parser
3
+ class Feature
4
+ %%{
5
+ machine feature;
6
+
7
+ action begin_content {
8
+ @content_start = p
9
+ }
10
+
11
+ action store_feature_content {
12
+ if !@backup or (p==eof)
13
+ con = data[@content_start...p].pack("c*")
14
+ else
15
+ con = data[@content_start...@backup].pack("c*")
16
+ end
17
+ con.strip!
18
+ @listener.feature(@keyword, con, @current_line)
19
+ if @backup
20
+ p = @backup-1
21
+ end
22
+ @backup = nil
23
+ }
24
+
25
+ action store_background_content {
26
+ if !@backup or (p==eof)
27
+ con = data[@content_start...p].pack("c*")
28
+ else
29
+ con = data[@content_start...@backup].pack("c*")
30
+ end
31
+ @listener.background(@keyword, multiline_strip(con), @current_line)
32
+ if @backup
33
+ p = @backup-1
34
+ end
35
+ @backup = nil
36
+ }
37
+
38
+ action store_scenario_content {
39
+ if !@backup or (p==eof)
40
+ con = data[@content_start...p].pack("c*")
41
+ else
42
+ con = data[@content_start...@backup].pack("c*")
43
+ end
44
+ @listener.scenario(@keyword, multiline_strip(con), @current_line)
45
+ if @backup
46
+ p = @backup-1
47
+ end
48
+ @backup = nil
49
+ }
50
+
51
+ action store_step_content {
52
+ con = data[@content_start...p].pack("c*")
53
+ con.strip!
54
+ @listener.step(@keyword, con, @current_line)
55
+ }
56
+
57
+ action store_comment_content {
58
+ con = data[@content_start...p].pack("c*")
59
+ con.strip!
60
+ @listener.comment(con, @line_number)
61
+ }
62
+
63
+ action store_tag_content {
64
+ con = data[@content_start...p].pack("c*")
65
+ con.strip!
66
+ @listener.tag(con, @current_line)
67
+ }
68
+
69
+ action inc_line_number {
70
+ @line_number += 1
71
+ }
72
+
73
+ action current_line {
74
+ @current_line = @line_number
75
+ }
76
+
77
+ action start_keyword {
78
+ @keyword_start ||= p
79
+ }
80
+
81
+ action end_keyword {
82
+ @keyword = data[@keyword_start...p].pack("c*").sub(/:$/,'').strip
83
+ @keyword_start = nil
84
+ }
85
+
86
+ action backup {
87
+ @backup = p
88
+ }
89
+
90
+ action end_table {
91
+ table_to_parse = '|' + data[@content_start...p].pack("c*").strip
92
+ Gherkin::Parser::Table.new(@listener, @current_line).scan(table_to_parse)
93
+ p = p-1
94
+ }
95
+
96
+ include feature_common "feature_common.<%= lang %>.rl";
97
+ }%%
98
+
99
+ def initialize(listener)
100
+ @listener = listener
101
+ %% write data;
102
+ end
103
+
104
+ def scan(data)
105
+ data = data.unpack("c*") if data.is_a?(String)
106
+ @line_number = 1
107
+ eof = data.size
108
+ %% write init;
109
+ %% write exec;
110
+ end
111
+
112
+ def multiline_strip(text)
113
+ text.split("\n").map{|s| s.strip!}.join("\n")
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,37 @@
1
+ %%{
2
+ machine feature_common;
3
+
4
+ # Language specific
5
+ FEATURE = '<%= i18n['feature'] %>:' >start_keyword %end_keyword;
6
+ BACKGROUND = '<%= i18n['background'] %>:' >start_keyword %end_keyword;
7
+ SCENARIO = '<%= i18n['scenario'] %>:' >start_keyword %end_keyword;
8
+ STEP = ('<%= i18n['given'] %> ' | '<%= i18n['when'] %> ' | '<%= i18n['and'] %> ' | '<%= i18n['then'] %> ' | '<%= i18n['but'] %> ') >start_keyword %end_keyword;
9
+
10
+ EOL = ('\r'? '\n') @inc_line_number;
11
+ BAR = '|' >start_keyword %end_keyword;
12
+
13
+ # Terminators
14
+ EndFeatureHeading = EOL+ space* (BACKGROUND | SCENARIO | '@' | '#');
15
+ EndScenarioHeading = EOL+ space* ( SCENARIO | STEP | '@' | '#' );
16
+ EndBackgroundHeading = EOL+ space* ( SCENARIO | STEP | '@' | '#' );
17
+ StartTable = space* '|';
18
+ EndTable = EOL space* ^('|' | space);
19
+
20
+ FeatureHeading = space* FEATURE %begin_content %current_line ^EndFeatureHeading* %/store_feature_content :>> EndFeatureHeading >backup @store_feature_content;
21
+ BackgroundHeading = space* BACKGROUND %begin_content %current_line ^EndBackgroundHeading* %/store_background_content :>> EndBackgroundHeading >backup @store_background_content;
22
+ ScenarioHeading = space* SCENARIO %begin_content %current_line ^EndScenarioHeading* %/store_scenario_content :>> EndScenarioHeading >backup @store_scenario_content;
23
+
24
+ Step = space* STEP %begin_content %current_line ^EOL+ %store_step_content %/store_step_content EOL+;
25
+ Comment = space* '#' >begin_content ^EOL+ %store_comment_content %/store_comment_content EOL+;
26
+ Tag = ( '@' [^@\r\n\t ]+ >begin_content ) %store_tag_content;
27
+ Tags = space* (Tag @current_line space*)+ EOL+;
28
+ Table = StartTable %begin_content %current_line any+ %/end_table :>> EndTable >backup @end_table;
29
+
30
+ MultilineStep = Step Table?;
31
+ Scenario = ScenarioHeading (Comment | MultilineStep)*;
32
+ Background = BackgroundHeading (Comment | MultilineStep)*;
33
+
34
+ Feature = (Tags | Comment)* FeatureHeading (Tags | Comment)* Background? ((Tags | Comment)* Scenario)*;
35
+
36
+ main := Feature;
37
+ }%%
data/ragel/misc.c.rl ADDED
@@ -0,0 +1,4 @@
1
+ int main() {
2
+ printf("hello, world");
3
+ return 0;
4
+ }
data/ragel/misc.rb.rl ADDED
@@ -0,0 +1,52 @@
1
+ module Gherkin
2
+ module Parser
3
+ class Misc
4
+ %%{
5
+ machine misc;
6
+
7
+ action start {
8
+ start_col = p - @last_newline
9
+ start = p + 4
10
+ }
11
+
12
+ action start_line {
13
+ line_col = p - @last_newline
14
+ line_start = p
15
+ }
16
+
17
+ action end_line {
18
+ line = data[line_start...p].pack("U*")
19
+ offset = line_col - start_col
20
+ @lines << (offset >= 0 ? line.gsub(/^/, ' ' * offset) : line)
21
+ }
22
+
23
+ newline = ('\r'? '\n') @{ @last_newline = p + 1} ;
24
+
25
+ PyStringStart = '"""' >start space* newline ;
26
+ PyStringEnd = '"""' ;
27
+ PyStringLine = space* ^newline* >start_line %end_line newline;
28
+
29
+ PyString = PyStringStart PyStringLine* PyStringEnd ;
30
+
31
+ main := space* PyString ;
32
+ }%%
33
+
34
+ def initialize(listener)
35
+ @listener = listener
36
+ @last_newline = 0
37
+ @lines = []
38
+ %% write data;
39
+ end
40
+
41
+ def scan(data)
42
+ data = data.unpack("U*") if data.is_a?(String)
43
+ eof = data.length
44
+
45
+ %% write init;
46
+ %% write exec;
47
+
48
+ @listener.pystring(@lines.join("\n"))
49
+ end
50
+ end
51
+ end
52
+ end
data/ragel/table.rb.rl ADDED
@@ -0,0 +1,54 @@
1
+ module Gherkin
2
+ module Parser
3
+ class Table
4
+ %%{
5
+ machine table;
6
+
7
+ action initialize {
8
+ current_row = []
9
+ }
10
+
11
+ action begin_content {
12
+ @content_start = p
13
+ }
14
+
15
+ action store_row {
16
+ @rows << current_row
17
+ }
18
+
19
+ action store_cell_content {
20
+ con = data[@content_start...p].pack("U*")
21
+ con.strip!
22
+ current_row << (con.empty? ? nil : con)
23
+ }
24
+
25
+ action no_content {
26
+ current_row << nil
27
+ }
28
+
29
+ include table_common "table_common.rl";
30
+ }%%
31
+
32
+ def initialize(listener,line=nil)
33
+ @line = line
34
+ @listener = listener
35
+ %% write data;
36
+ end
37
+
38
+ def scan(data)
39
+ @rows = []
40
+ data = data.unpack("U*") if data.is_a?(String)
41
+ eof = data.size
42
+
43
+ %% write init;
44
+ %% write exec;
45
+
46
+ if @line
47
+ @listener.table(@rows, @line)
48
+ else
49
+ @listener.table(@rows)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ %%{
2
+ machine table_common;
3
+
4
+ EOL = '\r'? '\n';
5
+ BAR = '|';
6
+ cell_content = ^('|' | EOL);
7
+
8
+ cell = cell_content+ >begin_content BAR >store_cell_content | BAR >no_content;
9
+ table_row = space* BAR >initialize cell+ space* %/store_row space* :>> EOL;
10
+ table = table_row+ @store_row;
11
+ main := table;
12
+ }%%
@@ -0,0 +1,439 @@
1
+ #encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ module Gherkin
5
+ module Parser
6
+ describe "parsing" do
7
+ before do
8
+ @listener = Gherkin::SexpRecorder.new
9
+ @feature = Parser['en'].new(@listener)
10
+ end
11
+
12
+ def scan_file(file)
13
+ Feature.new(@listener).scan(File.new(File.dirname(__FILE__) + "/gherkin_parser/" + file).read)
14
+ end
15
+
16
+ describe "Comments" do
17
+ it "should parse a file with only a one line comment" do
18
+ @feature.scan("# My comment\nFeature: hi")
19
+ @listener.to_sexp.should == [
20
+ [:comment, "# My comment", 1],
21
+ [:feature, "Feature", "hi", 2],
22
+ ]
23
+ end
24
+
25
+ it "should parse a one line comment" do
26
+ @feature.scan("# My comment")
27
+ @listener.to_sexp.should == [[:comment, "# My comment", 1]]
28
+ end
29
+
30
+ it "should parse a file with only a multiline comment" do
31
+ @feature.scan("#Hello\n#World\nFeature: hi")
32
+ @listener.to_sexp.should == [
33
+ [:comment, "#Hello", 1],
34
+ [:comment, "#World", 2],
35
+ [:feature, "Feature", "hi", 3]
36
+ ]
37
+ end
38
+
39
+ it "should parse a file with only a multiline comment" do
40
+ pending("TODO: Do multiline comments need to be compressed into a single message?")
41
+ @feature.scan("# Hello\n# World\nFeature: hi")
42
+ @listener.to_sexp.should == [
43
+ [:comment, "# Hello\n# World", 1],
44
+ [:feature, "hi", 3]
45
+ ]
46
+ end
47
+
48
+ it "should parse a file with no comments" do
49
+ @feature.scan("Feature: hi\n")
50
+ @listener.to_sexp.should == [[:feature, "Feature", "hi", 1]]
51
+ end
52
+
53
+ it "should parse a file with only a multiline comment with newlines" do
54
+ pending("TODO: Do multiline comments need to be compressed into a single message?")
55
+ @feature.scan("# Hello\n\n# World\n")
56
+ @listener.to_sexp.should == [[:comment, "# Hello\n\n# World\n"]]
57
+ end
58
+
59
+ it "should not consume comments as part of a multiline name" do
60
+ @feature.scan("Feature: hi\n Scenario: test\n\n#hello\n Scenario: another")
61
+ @listener.to_sexp.should == [
62
+ [:feature, "Feature", "hi", 1],
63
+ [:scenario, "Scenario", "test", 2],
64
+ [:comment, "#hello", 4],
65
+ [:scenario, "Scenario", "another", 5]
66
+ ]
67
+ end
68
+ end
69
+
70
+ describe "Tags" do
71
+ it "should parse a file with tags on a feature" do
72
+ @feature.scan("# My comment\n@hello @world\nFeature: hi\n")
73
+ @listener.to_sexp.should == [
74
+ [:comment, "# My comment", 1],
75
+ [:tag, "hello", 2],
76
+ [:tag, "world", 2],
77
+ [:feature, "Feature", "hi", 3]
78
+ ]
79
+ end
80
+
81
+ it "should not take the tags as part of a multiline name feature element" do
82
+ @feature.scan("Feature: hi\n Scenario: test\n\n@hello\n Scenario: another")
83
+ @listener.to_sexp.should == [
84
+ [:feature, "Feature", "hi", 1],
85
+ [:scenario, "Scenario", "test", 2],
86
+ [:tag, "hello", 4],
87
+ [:scenario, "Scenario", "another", 5]
88
+ ]
89
+ end
90
+
91
+ it "should parse a file with tags on a scenario" do
92
+ @feature.scan(%{# FC
93
+ @ft
94
+ Feature: hi
95
+
96
+ @st1 @st2
97
+ Scenario: First
98
+ Given Pepper
99
+
100
+ @st3
101
+ @st4 @ST5 @#^%&ST6**!
102
+ Scenario: Second})
103
+ @listener.to_sexp.should == [
104
+ [:comment, "# FC", 1],
105
+ [:tag, "ft",2],
106
+ [:feature, "Feature", "hi", 3],
107
+ [:tag, "st1", 5],
108
+ [:tag, "st2", 5],
109
+ [:scenario, "Scenario", "First", 6],
110
+ [:step, "Given", "Pepper", 7],
111
+ [:tag, "st3", 9],
112
+ [:tag, "st4", 10],
113
+ [:tag, "ST5", 10],
114
+ [:tag, "#^%&ST6**!", 10],
115
+ [:scenario, "Scenario", "Second", 11]
116
+ ]
117
+ end
118
+ end
119
+
120
+ describe "Background" do
121
+ it "should allow an empty background description" do
122
+ @feature.scan("Feature: Hi\nBackground:\nGiven I am a step\n")
123
+ @listener.to_sexp.should == [
124
+ [:feature, "Feature", "Hi", 1],
125
+ [:background, "Background", "", 2],
126
+ [:step, "Given", "I am a step", 3]
127
+ ]
128
+ end
129
+
130
+ it "should allow multiline names ending at eof" do
131
+ @feature.scan("Feature: Feature Text\n Background: I have several\n Lines to look at\n None starting with Given")
132
+ @listener.to_sexp.should == [
133
+ [:feature, "Feature", "Feature Text", 1],
134
+ [:background, "Background", "I have several\nLines to look at\nNone starting with Given", 2]
135
+ ]
136
+ end
137
+
138
+ it "should have steps" do
139
+ @feature.scan("Feature: Hi\nBackground: Run this first\nGiven I am a step\n")
140
+ @listener.to_sexp.should == [
141
+ [:feature, "Feature", "Hi", 1],
142
+ [:background, "Background", "Run this first", 2],
143
+ [:step, "Given", "I am a step", 3]
144
+ ]
145
+ end
146
+
147
+ it "should find scenarios after background" do
148
+ @feature.scan("Feature: Hi\n#This needs to run first\nBackground: Run this first\nGiven I am a step\n\n Scenario: A Scenario\nGiven I am a step")
149
+ @listener.to_sexp.should == [
150
+ [:feature, "Feature", "Hi", 1],
151
+ [:comment, "#This needs to run first", 2],
152
+ [:background, "Background", "Run this first", 3],
153
+ [:step, "Given", "I am a step", 4],
154
+ [:scenario, "Scenario", "A Scenario", 6],
155
+ [:step, "Given", "I am a step", 7]
156
+ ]
157
+ end
158
+
159
+ it "should allow multiline names" do
160
+ @feature.scan(%{Feature: Hi
161
+ Background: It is my ambition to say
162
+ in ten sentences
163
+ what others say
164
+ in a whole book.
165
+ Given I am a step})
166
+ @listener.to_sexp.should == [
167
+ [:feature, "Feature", "Hi", 1],
168
+ [:background, "Background", "It is my ambition to say\nin ten sentences\nwhat others say\nin a whole book.",2],
169
+ [:step, "Given", "I am a step", 6]
170
+ ]
171
+ end
172
+ end
173
+
174
+ describe "Scenarios" do
175
+ it "can be empty" do
176
+ @feature.scan("Feature: Hi\n\nScenario: Hello\n")
177
+ @listener.to_sexp.should == [
178
+ [:feature, "Feature", "Hi", 1],
179
+ [:scenario, "Scenario", "Hello", 3]
180
+ ]
181
+ end
182
+
183
+ it "should allow whitespace lines after the Scenario line" do
184
+ @feature.scan(%{Feature: Foo
185
+
186
+ Scenario: bar
187
+
188
+ Given baz})
189
+ @listener.to_sexp.should == [
190
+ [:feature, "Feature", "Foo", 1],
191
+ [:scenario, "Scenario", "bar", 3],
192
+ [:step, "Given", "baz", 5]
193
+ ]
194
+ end
195
+
196
+ it "should have steps" do
197
+ @feature.scan("Feature: Hi\nScenario: Hello\nGiven I am a step\n")
198
+ @listener.to_sexp.should == [
199
+ [:feature, "Feature", "Hi", 1],
200
+ [:scenario, "Scenario", "Hello", 2],
201
+ [:step, "Given", "I am a step", 3]
202
+ ]
203
+ end
204
+
205
+ it "should have steps with inline table" do
206
+ @feature.scan(%{Feature: Hi
207
+ Scenario: Hello
208
+ Given I have a table
209
+ |a|b|
210
+ })
211
+ @listener.to_sexp.should == [
212
+ [:feature, "Feature", "Hi", 1],
213
+ [:scenario, "Scenario", "Hello", 2],
214
+ [:step, "Given", "I have a table", 3],
215
+ [:table, [['a','b']], 4]
216
+ ]
217
+ end
218
+
219
+ it "should allow multiple steps each with tables" do
220
+ @feature.scan(%{Feature: Hi
221
+ Scenario: Hello
222
+ Given I have a table
223
+ |a|b|
224
+ |c|d|
225
+ |e|f|
226
+ And I am still testing things
227
+ |g|h|
228
+ |e|r|
229
+ |k|i|
230
+ |n||
231
+ And I am done testing these tables
232
+ })
233
+ @listener.to_sexp.should == [
234
+ [:feature, "Feature", "Hi", 1],
235
+ [:scenario, "Scenario", "Hello", 2],
236
+ [:step, "Given", "I have a table", 3],
237
+ [:table, [['a','b'],['c','d'],['e','f']], 4],
238
+ [:step, "And", "I am still testing things", 7],
239
+ [:table, [['g','h'],['e','r'],['k','i'],['n',nil]], 8],
240
+ [:step, "And", "I am done testing these tables", 12],
241
+ ]
242
+ end
243
+
244
+ it "should have steps with inline py_string" do
245
+ pending
246
+ @feature.scan(%{Feature: Hi
247
+ Scenario: Hello
248
+ Given I have a string
249
+
250
+
251
+ """
252
+ hello
253
+ world
254
+ """
255
+
256
+ })
257
+ @listener.to_sexp.should == [
258
+ [:feature, "Feature", "Hi", 1],
259
+ [:scenario, "Scenario", "Hello", 2],
260
+ [:step, "Given", "I have a string", 3],
261
+ [:py_string, "hello\nworld"]
262
+ ]
263
+ end
264
+
265
+ it "should allow multiline names" do
266
+ @feature.scan(%{Feature: Hi
267
+ Scenario: It is my ambition to say
268
+ in ten sentences
269
+ what others say
270
+ in a whole book.
271
+ Given I am a step
272
+
273
+ })
274
+ @listener.to_sexp.should == [
275
+ [:feature, "Feature", "Hi", 1],
276
+ [:scenario, "Scenario", "It is my ambition to say\nin ten sentences\nwhat others say\nin a whole book.", 2],
277
+ [:step, "Given", "I am a step", 6]
278
+ ]
279
+ end
280
+
281
+ it "should allow multiline names ending at eof" do
282
+ @feature.scan("Feature: Feature Text\n And some more text\n\n Scenario: I have several\n Lines to look at\n None starting with Given")
283
+ @listener.to_sexp.should == [
284
+ [:feature, "Feature", "Feature Text\n And some more text", 1],
285
+ [:scenario, "Scenario", "I have several\nLines to look at\nNone starting with Given", 4]
286
+ ]
287
+ end
288
+
289
+ it "should ignore gherkin keywords which are parts of other words in the name" do
290
+ @feature.scan(%{Feature: Parser bug
291
+ Scenario: I have a Button
292
+ Buttons are great
293
+ Given I have it
294
+ })
295
+ @listener.to_sexp.should == [
296
+ [:feature, "Feature", "Parser bug", 1],
297
+ [:scenario, "Scenario", "I have a Button\nButtons are great", 2],
298
+ [:step, "Given", "I have it", 4]
299
+ ]
300
+ end
301
+ end
302
+
303
+ describe "A single feature, single scenario, single step" do
304
+
305
+ it "should find the feature, scenario, and step" do
306
+ @feature.scan("Feature: Feature Text\n Scenario: Reading a Scenario\n Given there is a step\n")
307
+ @listener.to_sexp.should == [
308
+ [:feature, "Feature", "Feature Text", 1],
309
+ [:scenario, "Scenario", "Reading a Scenario", 2],
310
+ [:step, "Given", "there is a step", 3]
311
+ ]
312
+ end
313
+ end
314
+
315
+ describe "A single feature, single scenario, three steps" do
316
+
317
+ it "should find the feature, scenario, and three steps" do
318
+ @feature.scan("Feature: Feature Text\n Scenario: Reading a Scenario\n Given there is a step\n And another step\n And a third step\n")
319
+ @listener.to_sexp.should == [
320
+ [:feature, "Feature", "Feature Text", 1],
321
+ [:scenario, "Scenario", "Reading a Scenario", 2],
322
+ [:step, "Given", "there is a step", 3],
323
+ [:step, "And", "another step", 4],
324
+ [:step, "And", "a third step", 5]
325
+ ]
326
+ end
327
+ end
328
+
329
+ describe "A single feature with no scenario" do
330
+ it "should find the feature" do
331
+ @feature.scan("Feature: Feature Text\n")
332
+ @listener.to_sexp.should == [[:feature, "Feature", "Feature Text", 1]]
333
+ end
334
+
335
+ it "should parse a one line feature with no newline" do
336
+ @feature.scan("Feature: hi")
337
+ @listener.to_sexp.should == [[:feature, "Feature", "hi", 1]]
338
+ end
339
+ end
340
+
341
+ describe "A multi-line feature with no scenario" do
342
+ it "should find the feature" do
343
+ @feature.scan("Feature: Feature Text\n And some more text")
344
+ @listener.to_sexp.should == [[:feature, "Feature", "Feature Text\n And some more text", 1]]
345
+ end
346
+ end
347
+
348
+ describe "A feature with a scenario but no steps" do
349
+ it "should find the feature and scenario" do
350
+ @feature.scan("Feature: Feature Text\nScenario: Reading a Scenario\n")
351
+ @listener.to_sexp.should == [
352
+ [:feature, "Feature", "Feature Text", 1],
353
+ [:scenario, "Scenario", "Reading a Scenario", 2]
354
+ ]
355
+ end
356
+ end
357
+
358
+ describe "A feature with two scenarios" do
359
+ it "should find the feature and two scenarios" do
360
+ @feature.scan("Feature: Feature Text\nScenario: Reading a Scenario\n Given a step\n\nScenario: A second scenario\n Given another step\n")
361
+ @listener.to_sexp.should == [
362
+ [:feature, "Feature", "Feature Text", 1],
363
+ [:scenario, "Scenario", "Reading a Scenario", 2],
364
+ [:step, "Given", "a step", 3],
365
+ [:scenario, "Scenario", "A second scenario", 5],
366
+ [:step, "Given", "another step", 6]
367
+ ]
368
+ end
369
+
370
+ it "should find the feature and two scenarios without indentation" do
371
+ @feature.scan("Feature: Feature Text\nScenario: Reading a Scenario\nGiven a step\nScenario: A second scenario\nGiven another step\n")
372
+ @listener.to_sexp.should == [
373
+ [:feature, "Feature", "Feature Text", 1],
374
+ [:scenario, "Scenario", "Reading a Scenario", 2],
375
+ [:step, "Given", "a step", 3],
376
+ [:scenario, "Scenario", "A second scenario", 4],
377
+ [:step, "Given", "another step", 5]
378
+ ]
379
+ end
380
+ end
381
+
382
+ describe "A simple feature with comments" do
383
+ it "should find the feature, scenarios, steps, and comments in the proper order" do
384
+ scan_file("simple_with_comments.feature")
385
+ @listener.to_sexp.should == [
386
+ [:comment, "# Here is a comment", 1],
387
+ [:feature, "Feature", "Feature Text", 2],
388
+ [:comment, "# Here is another # comment", 3],
389
+ [:scenario, "Scenario", "Reading a Scenario", 4],
390
+ [:comment, "# Here is a third comment", 5],
391
+ [:step, "Given", "there is a step", 6],
392
+ [:comment, "# Here is a fourth comment", 7]
393
+ ]
394
+ end
395
+ end
396
+
397
+ describe "A simple feature with tags" do
398
+ it "should find the feature, scenario, step, and tags in the proper order" do
399
+ scan_file("simple_with_tags.feature")
400
+ @listener.to_sexp.should == [
401
+ [:tag, "tag1", 1],
402
+ [:tag, "tag2", 1],
403
+ [:feature, "Feature", "Feature Text", 2],
404
+ [:tag, "tag3", 3],
405
+ [:tag, "tag4", 3],
406
+ [:scenario, "Scenario", "Reading a Scenario", 4],
407
+ [:step, "Given", "there is a step", 5]
408
+ ]
409
+ end
410
+ end
411
+
412
+ describe "A complex feature with tags, comments, multiple scenarios, and multiple steps" do
413
+ it "should find things in the right order" do
414
+ scan_file("complex.feature")
415
+ @listener.to_sexp.should == [
416
+ [:comment, "#Comment on line 1", 1],
417
+ [:tag, "tag1", 2],
418
+ [:tag, "tag2", 2],
419
+ [:comment, "#Comment on line 3", 3],
420
+ [:feature, "Feature", "Feature Text\n In order to test multiline forms\n As a ragel writer\n I need to check for complex combinations", 4],
421
+ [:comment, "#Comment on line 9", 9],
422
+ [:comment, "#Comment on line 11", 11],
423
+ [:tag, "tag3", 13],
424
+ [:tag, "tag4", 13],
425
+ [:scenario, "Scenario", "Reading a Scenario", 14],
426
+ [:step, "Given", "there is a step", 15],
427
+ [:step, "But", "not another step", 16],
428
+ [:tag, "tag3", 18],
429
+ [:scenario, "Scenario", "Reading a second scenario", 19],
430
+ [:comment, "#Comment on line 20", 20],
431
+ [:step, "Given", "a third step", 21],
432
+ [:comment, "#Comment on line 22", 22],
433
+ [:step, "Then", "I am happy", 23]
434
+ ]
435
+ end
436
+ end
437
+ end
438
+ end
439
+ end