bryanl-gherkin 2.11.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/.gitattributes +2 -0
  2. data/.mailmap +2 -0
  3. data/.rbenv-gemsets +1 -0
  4. data/.rspec +1 -0
  5. data/.rvmrc +1 -0
  6. data/.travis.yml +16 -0
  7. data/.yardopts +5 -0
  8. data/Gemfile +5 -0
  9. data/History.md +788 -0
  10. data/LICENSE +20 -0
  11. data/README.md +272 -0
  12. data/Rakefile +26 -0
  13. data/build_native_gems.sh +7 -0
  14. data/cucumber.yml +4 -0
  15. data/examples/parse_and_output_json.rb +19 -0
  16. data/features/.cucumber/stepdefs.json +244 -0
  17. data/features/escaped_pipes.feature +8 -0
  18. data/features/feature_parser.feature +237 -0
  19. data/features/json_formatter.feature +498 -0
  20. data/features/json_parser.feature +331 -0
  21. data/features/native_lexer.feature +19 -0
  22. data/features/parser_with_native_lexer.feature +205 -0
  23. data/features/pretty_formatter.feature +16 -0
  24. data/features/step_definitions/eyeball_steps.rb +3 -0
  25. data/features/step_definitions/gherkin_steps.rb +29 -0
  26. data/features/step_definitions/json_formatter_steps.rb +30 -0
  27. data/features/step_definitions/json_parser_steps.rb +20 -0
  28. data/features/step_definitions/pretty_formatter_steps.rb +85 -0
  29. data/features/steps_parser.feature +46 -0
  30. data/features/support/env.rb +42 -0
  31. data/gherkin.gemspec +77 -0
  32. data/install_mingw_os_x.sh +7 -0
  33. data/js/.npmignore +1 -0
  34. data/js/lib/gherkin/lexer/.npmignore +0 -0
  35. data/lib/gherkin/c_lexer.rb +17 -0
  36. data/lib/gherkin/formatter/ansi_escapes.rb +97 -0
  37. data/lib/gherkin/formatter/argument.rb +16 -0
  38. data/lib/gherkin/formatter/escaping.rb +15 -0
  39. data/lib/gherkin/formatter/filter_formatter.rb +146 -0
  40. data/lib/gherkin/formatter/hashable.rb +19 -0
  41. data/lib/gherkin/formatter/json_formatter.rb +122 -0
  42. data/lib/gherkin/formatter/line_filter.rb +26 -0
  43. data/lib/gherkin/formatter/model.rb +281 -0
  44. data/lib/gherkin/formatter/pretty_formatter.rb +244 -0
  45. data/lib/gherkin/formatter/regexp_filter.rb +21 -0
  46. data/lib/gherkin/formatter/step_printer.rb +21 -0
  47. data/lib/gherkin/formatter/tag_count_formatter.rb +47 -0
  48. data/lib/gherkin/formatter/tag_filter.rb +19 -0
  49. data/lib/gherkin/i18n.rb +180 -0
  50. data/lib/gherkin/i18n.yml +613 -0
  51. data/lib/gherkin/js_lexer.rb +20 -0
  52. data/lib/gherkin/json_parser.rb +177 -0
  53. data/lib/gherkin/lexer/i18n_lexer.rb +46 -0
  54. data/lib/gherkin/listener/event.rb +45 -0
  55. data/lib/gherkin/listener/formatter_listener.rb +143 -0
  56. data/lib/gherkin/native/java.rb +72 -0
  57. data/lib/gherkin/native/null.rb +5 -0
  58. data/lib/gherkin/native/therubyracer.rb +39 -0
  59. data/lib/gherkin/native.rb +7 -0
  60. data/lib/gherkin/parser/meta.txt +5 -0
  61. data/lib/gherkin/parser/parser.rb +164 -0
  62. data/lib/gherkin/parser/root.txt +11 -0
  63. data/lib/gherkin/parser/steps.txt +4 -0
  64. data/lib/gherkin/rb_lexer/README.rdoc +8 -0
  65. data/lib/gherkin/rb_lexer.rb +8 -0
  66. data/lib/gherkin/rubify.rb +24 -0
  67. data/lib/gherkin/tag_expression.rb +62 -0
  68. data/lib/gherkin.jar +0 -0
  69. data/lib/gherkin.rb +2 -0
  70. data/ragel/lexer.c.rl.erb +454 -0
  71. data/ragel/lexer.java.rl.erb +219 -0
  72. data/ragel/lexer.js.rl.erb +227 -0
  73. data/ragel/lexer.rb.rl.erb +174 -0
  74. data/ragel/lexer_common.rl.erb +50 -0
  75. data/spec/gherkin/c_lexer_spec.rb +22 -0
  76. data/spec/gherkin/fixtures/1.feature +8 -0
  77. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  78. data/spec/gherkin/fixtures/complex.feature +45 -0
  79. data/spec/gherkin/fixtures/complex.json +139 -0
  80. data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
  81. data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
  82. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  83. data/spec/gherkin/fixtures/examples_with_only_header.feature +14 -0
  84. data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
  85. data/spec/gherkin/fixtures/i18n_fr.feature +14 -0
  86. data/spec/gherkin/fixtures/i18n_fr2.feature +8 -0
  87. data/spec/gherkin/fixtures/i18n_no.feature +7 -0
  88. data/spec/gherkin/fixtures/i18n_pt1.feature +44 -0
  89. data/spec/gherkin/fixtures/i18n_pt2.feature +4 -0
  90. data/spec/gherkin/fixtures/i18n_pt3.feature +4 -0
  91. data/spec/gherkin/fixtures/i18n_pt4.feature +4 -0
  92. data/spec/gherkin/fixtures/i18n_zh-CN.feature +9 -0
  93. data/spec/gherkin/fixtures/issue_145.feature +22 -0
  94. data/spec/gherkin/fixtures/scenario_outline_with_tags.feature +13 -0
  95. data/spec/gherkin/fixtures/scenario_without_steps.feature +5 -0
  96. data/spec/gherkin/fixtures/simple_with_comments.feature +7 -0
  97. data/spec/gherkin/fixtures/simple_with_tags.feature +11 -0
  98. data/spec/gherkin/fixtures/with_bom.feature +3 -0
  99. data/spec/gherkin/formatter/ansi_escapes_spec.rb +32 -0
  100. data/spec/gherkin/formatter/filter_formatter_spec.rb +204 -0
  101. data/spec/gherkin/formatter/json_formatter_spec.rb +92 -0
  102. data/spec/gherkin/formatter/model_spec.rb +28 -0
  103. data/spec/gherkin/formatter/pretty_formatter_spec.rb +177 -0
  104. data/spec/gherkin/formatter/spaces.feature +9 -0
  105. data/spec/gherkin/formatter/step_printer_spec.rb +55 -0
  106. data/spec/gherkin/formatter/tabs.feature +9 -0
  107. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +30 -0
  108. data/spec/gherkin/i18n_spec.rb +241 -0
  109. data/spec/gherkin/java_lexer_spec.rb +20 -0
  110. data/spec/gherkin/js_lexer_spec.rb +23 -0
  111. data/spec/gherkin/json_parser_spec.rb +176 -0
  112. data/spec/gherkin/lexer/i18n_lexer_spec.rb +43 -0
  113. data/spec/gherkin/output_stream_string_io.rb +20 -0
  114. data/spec/gherkin/parser/parser_spec.rb +16 -0
  115. data/spec/gherkin/rb_lexer_spec.rb +20 -0
  116. data/spec/gherkin/sexp_recorder.rb +59 -0
  117. data/spec/gherkin/shared/bom_group.rb +20 -0
  118. data/spec/gherkin/shared/doc_string_group.rb +163 -0
  119. data/spec/gherkin/shared/lexer_group.rb +591 -0
  120. data/spec/gherkin/shared/row_group.rb +125 -0
  121. data/spec/gherkin/shared/tags_group.rb +54 -0
  122. data/spec/gherkin/tag_expression_spec.rb +142 -0
  123. data/spec/spec_helper.rb +75 -0
  124. data/tasks/bench/feature_builder.rb +49 -0
  125. data/tasks/bench/null_listener.rb +4 -0
  126. data/tasks/bench.rake +184 -0
  127. data/tasks/compile.rake +120 -0
  128. data/tasks/cucumber.rake +22 -0
  129. data/tasks/gems.rake +31 -0
  130. data/tasks/ikvm.rake +124 -0
  131. data/tasks/ragel_task.rb +100 -0
  132. data/tasks/release.rake +49 -0
  133. data/tasks/rspec.rake +8 -0
  134. data/tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  135. data/tasks/yard/default/layout/html/bubble_48x48.png +0 -0
  136. data/tasks/yard/default/layout/html/footer.erb +5 -0
  137. data/tasks/yard/default/layout/html/index.erb +1 -0
  138. data/tasks/yard/default/layout/html/layout.erb +25 -0
  139. data/tasks/yard/default/layout/html/logo.erb +1 -0
  140. data/tasks/yard/default/layout/html/setup.rb +4 -0
  141. data/tasks/yard.rake +7 -0
  142. metadata +412 -0
@@ -0,0 +1,591 @@
1
+ #encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ module Gherkin
5
+ module Lexer
6
+ shared_examples_for "a Gherkin lexer" do
7
+ def scan(gherkin)
8
+ @lexer.scan(gherkin)
9
+ end
10
+
11
+ describe "Comments" do
12
+ it "should parse a one line comment" do
13
+ scan("# My comment\n")
14
+ @listener.to_sexp.should == [
15
+ [:comment, "# My comment", 1],
16
+ [:eof]
17
+ ]
18
+ end
19
+
20
+ it "should parse a multiline comment" do
21
+ scan("# Hello\n\n# World\n")
22
+ @listener.to_sexp.should == [
23
+ [:comment, "# Hello", 1],
24
+ [:comment, "# World", 3],
25
+ [:eof]
26
+ ]
27
+ end
28
+
29
+ it "should not consume comments as part of a multiline name" do
30
+ scan("Scenario: test\n#hello\n Scenario: another")
31
+ @listener.to_sexp.should == [
32
+ [:scenario, "Scenario", "test", "", 1],
33
+ [:comment, "#hello", 2],
34
+ [:scenario, "Scenario", "another", "", 3],
35
+ [:eof]
36
+ ]
37
+ end
38
+
39
+ it "should not consume comments as part of a multiline example name" do
40
+ scan("Examples: thing\n# ho hum\n| 1 | 2 |\n| 3 | 4 |\n")
41
+ @listener.to_sexp.should == [
42
+ [:examples, "Examples", "thing", "", 1],
43
+ [:comment, "# ho hum", 2],
44
+ [:row, ["1","2"], 3],
45
+ [:row, ["3","4"], 4],
46
+ [:eof]
47
+ ]
48
+ end
49
+
50
+ it "should allow empty comment lines" do
51
+ scan("#\n # A comment\n #\n")
52
+ @listener.to_sexp.should == [
53
+ [:comment, "#", 1],
54
+ [:comment, "# A comment", 2],
55
+ [:comment, "#", 3],
56
+ [:eof]
57
+ ]
58
+ end
59
+
60
+ it "should not allow comments within the Feature description" do
61
+ lambda {
62
+ scan("Feature: something\nAs a something\n# Comment\nI want something")
63
+ }.should raise_error(/Lexing error on line 4/)
64
+ end
65
+ end
66
+
67
+ describe "Tags" do
68
+ it "should not take the tags as part of a multiline name feature element" do
69
+ scan("Feature: hi\n Scenario: test\n\n@hello\n Scenario: another")
70
+ @listener.to_sexp.should == [
71
+ [:feature, "Feature", "hi", "", 1],
72
+ [:scenario, "Scenario", "test", "", 2],
73
+ [:tag, "@hello", 4],
74
+ [:scenario, "Scenario", "another", "", 5],
75
+ [:eof]
76
+ ]
77
+ end
78
+ end
79
+
80
+ describe "Background" do
81
+ it "should allow an empty background name and description" do
82
+ scan("Background:\nGiven I am a step\n")
83
+ @listener.to_sexp.should == [
84
+ [:background, "Background", "", "", 1],
85
+ [:step, "Given ", "I am a step", 2],
86
+ [:eof]
87
+ ]
88
+ end
89
+
90
+ it "should allow an empty background description" do
91
+ scan("Background: Yeah\nGiven I am a step\n")
92
+ @listener.to_sexp.should == [
93
+ [:background, "Background", "Yeah", "", 1],
94
+ [:step, "Given ", "I am a step", 2],
95
+ [:eof]
96
+ ]
97
+ end
98
+
99
+ it "should allow multiline descriptions ending at eof" do
100
+ scan("Background: I have several\n Lines to look at\n None starting with Given")
101
+ @listener.to_sexp.should == [
102
+ [:background, "Background", "I have several", " Lines to look at\n None starting with Given", 1],
103
+ [:eof]
104
+ ]
105
+ end
106
+
107
+ it "should allow multiline descriptions, including whitespace" do
108
+ scan(%{Feature: Hi
109
+ Background: It is my ambition to say
110
+ in ten sentences
111
+ what others say
112
+ in a whole book.
113
+ Given I am a step})
114
+ @listener.to_sexp.should == [
115
+ [:feature, "Feature", "Hi", "", 1],
116
+ [:background, "Background", "It is my ambition to say", "in ten sentences\n what others say \nin a whole book.",2],
117
+ [:step, "Given ", "I am a step", 6],
118
+ [:eof]
119
+ ]
120
+ end
121
+ end
122
+
123
+ describe "Scenarios" do
124
+ it "should be parsed" do
125
+ scan("Scenario: Hello\n")
126
+ @listener.to_sexp.should == [
127
+ [:scenario, "Scenario", "Hello", "", 1],
128
+ [:eof]
129
+ ]
130
+ end
131
+
132
+ it "should allow whitespace lines after the Scenario line" do
133
+ scan(%{Scenario: bar
134
+
135
+ Given baz
136
+ })
137
+ @listener.to_sexp.should == [
138
+ [:scenario, "Scenario", "bar", "", 1],
139
+ [:step, "Given ", "baz", 3],
140
+ [:eof]
141
+ ]
142
+ end
143
+
144
+ it "should allow multiline descriptions, including whitespace" do
145
+ scan(%{Scenario: It is my ambition to say
146
+ in ten sentences
147
+ what others say
148
+ in a whole book.
149
+ Given I am a step
150
+ })
151
+ @listener.to_sexp.should == [
152
+ [:scenario, "Scenario", "It is my ambition to say", "in ten sentences\nwhat others say \n in a whole book.", 1],
153
+ [:step, "Given ", "I am a step", 5],
154
+ [:eof]
155
+ ]
156
+ end
157
+
158
+ it "should allow multiline names ending at eof" do
159
+ scan("Scenario: I have several\nLines to look at\n None starting with Given")
160
+ @listener.to_sexp.should == [
161
+ [:scenario, "Scenario", "I have several", "Lines to look at\nNone starting with Given", 1],
162
+ [:eof]
163
+ ]
164
+ end
165
+
166
+ it "should ignore gherkin keywords embedded in other words" do
167
+ scan(%{Scenario: I have a Button
168
+ Buttons are great
169
+ Given I have some
170
+ But I might not because I am a Charles Dickens character
171
+ })
172
+ @listener.to_sexp.should == [
173
+ [:scenario, "Scenario", "I have a Button", "Buttons are great", 1],
174
+ [:step, "Given ", "I have some", 3],
175
+ [:step, "But ", "I might not because I am a Charles Dickens character", 4],
176
+ [:eof]
177
+ ]
178
+ end
179
+
180
+ it "should allow step keywords in Scenario names" do
181
+ scan(%{Scenario: When I have when in scenario
182
+ I should be fine
183
+ Given I am a step
184
+ })
185
+ @listener.to_sexp.should == [
186
+ [:scenario, "Scenario", "When I have when in scenario", "I should be fine", 1],
187
+ [:step, "Given ", "I am a step", 3],
188
+ [:eof]
189
+ ]
190
+ end
191
+ end
192
+
193
+ describe "Scenario Outlines" do
194
+ it "should be parsed" do
195
+ scan(<<-HERE)
196
+ Scenario Outline: Hello
197
+ With a description
198
+ Given a <what> cucumber
199
+ Examples: With a name
200
+ and a description
201
+ |what|
202
+ |green|
203
+ HERE
204
+ @listener.to_sexp.should == [
205
+ [:scenario_outline, "Scenario Outline", "Hello", "With a description", 1],
206
+ [:step, "Given ", "a <what> cucumber", 3],
207
+ [:examples, "Examples", "With a name", "and a description", 4],
208
+ [:row, ["what"], 6],
209
+ [:row, ["green"], 7],
210
+ [:eof]
211
+ ]
212
+ end
213
+
214
+
215
+ it "should parse with no steps or examples" do
216
+ scan(%{Scenario Outline: Hello
217
+
218
+ Scenario: My Scenario
219
+ })
220
+ @listener.to_sexp.should == [
221
+ [:scenario_outline, "Scenario Outline", "Hello", "", 1],
222
+ [:scenario, "Scenario", "My Scenario", "", 3],
223
+ [:eof]
224
+ ]
225
+ end
226
+
227
+ it "should allow multiline description" do
228
+ scan(<<-HERE)
229
+ Scenario Outline: It is my ambition to say
230
+ in ten sentences
231
+ what others say
232
+ in a whole book.
233
+ Given I am a step
234
+ HERE
235
+ @listener.to_sexp.should == [
236
+ [:scenario_outline, "Scenario Outline", "It is my ambition to say", "in ten sentences\n what others say \nin a whole book.", 1],
237
+ [:step, "Given ", "I am a step", 5],
238
+ [:eof]
239
+ ]
240
+ end
241
+ end
242
+
243
+ describe "Examples" do
244
+ it "should be parsed" do
245
+ scan(%{Examples:
246
+ |x|y|
247
+ |5|6|
248
+ })
249
+ @listener.to_sexp.should == [
250
+ [:examples, "Examples", "", "", 1],
251
+ [:row, ["x","y"], 2],
252
+ [:row, ["5","6"], 3],
253
+ [:eof]
254
+ ]
255
+ end
256
+
257
+ it "should parse multiline example names" do
258
+ scan(%{Examples: I'm a multiline name
259
+ and I'm ok
260
+ f'real
261
+ |x|
262
+ |5|
263
+ })
264
+ @listener.to_sexp.should == [
265
+ [:examples, "Examples", "I'm a multiline name", "and I'm ok\nf'real", 1],
266
+ [:row, ["x"], 4],
267
+ [:row, ["5"], 5],
268
+ [:eof]
269
+ ]
270
+ end
271
+ end
272
+
273
+ describe "Steps" do
274
+ it "should parse steps with inline table" do
275
+ scan(%{Given I have a table
276
+ |a|b|
277
+ })
278
+ @listener.to_sexp.should == [
279
+ [:step, "Given ", "I have a table", 1],
280
+ [:row, ['a','b'], 2],
281
+ [:eof]
282
+ ]
283
+ end
284
+
285
+ it "should parse steps with inline doc_string" do
286
+ scan("Given I have a string\n\"\"\"\nhello\nworld\n\"\"\"")
287
+ @listener.to_sexp.should == [
288
+ [:step, "Given ", "I have a string", 1],
289
+ [:doc_string, '', "hello\nworld", 2],
290
+ [:eof]
291
+ ]
292
+ end
293
+
294
+ it "should parse steps with an empty name" do
295
+ scan("Given ")
296
+ @listener.to_sexp.should == [
297
+ [:step, "Given ", "", 1],
298
+ [:eof]
299
+ ]
300
+ end
301
+ end
302
+
303
+ describe "A single feature, single scenario, single step" do
304
+ it "should find the feature, scenario, and step" do
305
+ scan("Feature: Feature Text\n Scenario: Reading a Scenario\n Given there is a step\n")
306
+ @listener.to_sexp.should == [
307
+ [:feature, "Feature", "Feature Text", "", 1],
308
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
309
+ [:step, "Given ", "there is a step", 3],
310
+ [:eof]
311
+ ]
312
+ end
313
+ end
314
+
315
+ describe "A feature ending in whitespace" do
316
+ it "should not raise an error when whitespace follows the Feature, Scenario, and Steps" do
317
+ scan("Feature: Feature Text\n Scenario: Reading a Scenario\n Given there is a step\n ")
318
+ @listener.to_sexp.should == [
319
+ [:feature, "Feature", "Feature Text", "", 1],
320
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
321
+ [:step, "Given ", "there is a step", 3],
322
+ [:eof]
323
+ ]
324
+ end
325
+ end
326
+
327
+ describe "A single feature, single scenario, three steps" do
328
+
329
+ it "should find the feature, scenario, and three steps" do
330
+ 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")
331
+ @listener.to_sexp.should == [
332
+ [:feature, "Feature", "Feature Text", "", 1],
333
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
334
+ [:step, "Given ", "there is a step", 3],
335
+ [:step, "And ", "another step", 4],
336
+ [:step, "And ", "a third step", 5],
337
+ [:eof]
338
+ ]
339
+ end
340
+ end
341
+
342
+ describe "A single feature with no scenario" do
343
+ it "should find the feature" do
344
+ scan("Feature: Feature Text\n")
345
+ @listener.to_sexp.should == [
346
+ [:feature, "Feature", "Feature Text", "", 1],
347
+ [:eof]
348
+ ]
349
+ end
350
+
351
+ it "should parse a one line feature with no newline" do
352
+ scan("Feature: hi")
353
+ @listener.to_sexp.should == [
354
+ [:feature, "Feature", "hi", "", 1],
355
+ [:eof]
356
+ ]
357
+ end
358
+ end
359
+
360
+ describe "A multi-line feature with no scenario" do
361
+ it "should find the feature" do
362
+ scan("Feature: Feature Text\n And some more text")
363
+ @listener.to_sexp.should == [
364
+ [:feature, "Feature", "Feature Text", "And some more text", 1],
365
+ [:eof]
366
+ ]
367
+ end
368
+ end
369
+
370
+ describe "A feature with a scenario but no steps" do
371
+ it "should find the feature and scenario" do
372
+ scan("Feature: Feature Text\nScenario: Reading a Scenario\n")
373
+ @listener.to_sexp.should == [
374
+ [:feature, "Feature", "Feature Text", "", 1],
375
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
376
+ [:eof]
377
+ ]
378
+ end
379
+ end
380
+
381
+ describe "A feature with two scenarios" do
382
+ it "should find the feature and two scenarios" do
383
+ scan("Feature: Feature Text\nScenario: Reading a Scenario\n Given a step\n\nScenario: A second scenario\n Given another step\n")
384
+ @listener.to_sexp.should == [
385
+ [:feature, "Feature", "Feature Text", "", 1],
386
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
387
+ [:step, "Given ", "a step", 3],
388
+ [:scenario, "Scenario", "A second scenario", "", 5],
389
+ [:step, "Given ", "another step", 6],
390
+ [:eof]
391
+ ]
392
+ end
393
+
394
+ it "should find the feature and two scenarios without indentation" do
395
+ scan("Feature: Feature Text\nScenario: Reading a Scenario\nGiven a step\nScenario: A second scenario\nGiven another step\n")
396
+ @listener.to_sexp.should == [
397
+ [:feature, "Feature", "Feature Text", "", 1],
398
+ [:scenario, "Scenario", "Reading a Scenario", "", 2],
399
+ [:step, "Given ", "a step", 3],
400
+ [:scenario, "Scenario", "A second scenario", "", 4],
401
+ [:step, "Given ", "another step", 5],
402
+ [:eof]
403
+ ]
404
+ end
405
+ end
406
+
407
+ describe "A simple feature with comments" do
408
+ it "should find the feature, scenarios, steps, and comments in the proper order" do
409
+ scan_file("simple_with_comments.feature")
410
+ @listener.to_sexp.should == [
411
+ [:comment, "# Here is a comment", 1],
412
+ [:feature, "Feature", "Feature Text", "", 2],
413
+ [:comment, "# Here is another # comment", 3],
414
+ [:scenario, "Scenario", "Reading a Scenario", "", 4],
415
+ [:comment, "# Here is a third comment", 5],
416
+ [:step, "Given ", "there is a step", 6],
417
+ [:comment, "# Here is a fourth comment", 7],
418
+ [:eof]
419
+ ]
420
+ end
421
+
422
+ it "should support comments in tables" do
423
+ scan_file("comments_in_table.feature")
424
+ @listener.to_sexp.should == [
425
+ [:feature, "Feature", "x", "", 1],
426
+ [:scenario_outline, "Scenario Outline", "x", "", 3],
427
+ [:step, "Then ", "x is <state>", 4],
428
+ [:examples, "Examples", "", "", 6],
429
+ [:row, ["state"], 7],
430
+ [:comment, "# comment", 8],
431
+ [:row, ["1"], 9],
432
+ [:eof]
433
+ ]
434
+ end
435
+ end
436
+
437
+ describe "A feature with tags everywhere" do
438
+ it "should find the feature, scenario, step, and tags in the proper order" do
439
+ scan_file("simple_with_tags.feature")
440
+ @listener.to_sexp.should == [
441
+ [:comment, "# FC", 1],
442
+ [:tag, "@ft",2],
443
+ [:feature, "Feature", "hi", "", 3],
444
+ [:tag, "@st1", 5],
445
+ [:tag, "@st2", 5],
446
+ [:scenario, "Scenario", "First", "", 6],
447
+ [:step, "Given ", "Pepper", 7],
448
+ [:tag, "@st3", 9],
449
+ [:tag, "@st4", 10],
450
+ [:tag, "@ST5", 10],
451
+ [:tag, "@#^%&ST6**!", 10],
452
+ [:scenario, "Scenario", "Second", "", 11],
453
+ [:eof]
454
+ ]
455
+ end
456
+ end
457
+
458
+ describe "Comment or tag between Feature elements where previous narrative starts with same letter as a keyword" do
459
+ it "should lex this feature properly" do
460
+ scan_file("1.feature")
461
+ @listener.to_sexp.should == [
462
+ [:feature, "Feature", "Logging in", "So that I can be myself", 1],
463
+ [:comment, "# Comment", 3],
464
+ [:scenario, "Scenario", "Anonymous user can get a login form.", "Scenery here", 4],
465
+ [:tag, "@tag", 7],
466
+ [:scenario, "Scenario", "Another one", "", 8],
467
+ [:eof]
468
+ ]
469
+ end
470
+ end
471
+
472
+ describe "A complex feature with tags, comments, multiple scenarios, and multiple steps and tables" do
473
+ it "should find things in the right order" do
474
+ scan_file("complex.feature")
475
+ @listener.to_sexp.should == [
476
+ [:comment, "#Comment on line 1", 1],
477
+ [:comment, "#Comment on line 2", 2],
478
+ [:tag, "@tag1", 3],
479
+ [:tag, "@tag2", 3],
480
+ [:feature, "Feature", "Feature Text", "In order to test multiline forms\nAs a ragel writer\nI need to check for complex combinations", 4],
481
+ [:comment, "#Comment on line 9", 9],
482
+ [:comment, "#Comment on line 11", 11],
483
+ [:background, "Background", "", "", 13],
484
+ [:step, "Given ", "this is a background step", 14],
485
+ [:step, "And ", "this is another one", 15],
486
+ [:tag, "@tag3", 17],
487
+ [:tag, "@tag4", 17],
488
+ [:scenario, "Scenario", "Reading a Scenario", "", 18],
489
+ [:step, "Given ", "there is a step", 19],
490
+ [:step, "But ", "not another step", 20],
491
+ [:tag, "@tag3", 22],
492
+ [:scenario, "Scenario", "Reading a second scenario", "With two lines of text", 23],
493
+ [:comment, "#Comment on line 24", 25],
494
+ [:step, "Given ", "a third step with a table", 26],
495
+ [:row, %w{a b}, 27],
496
+ [:row, %w{c d}, 28],
497
+ [:row, %w{e f}, 29],
498
+ [:step, "And ", "I am still testing things", 30],
499
+ [:row, %w{g h}, 31],
500
+ [:row, %w{e r}, 32],
501
+ [:row, %w{k i}, 33],
502
+ [:row, ['n', ''], 34],
503
+ [:step, "And ", "I am done testing these tables", 35],
504
+ [:comment, "#Comment on line 29", 36],
505
+ [:step, "Then ", "I am happy", 37],
506
+ [:scenario, "Scenario", "Hammerzeit", "", 39],
507
+ [:step, "Given ", "All work and no play", 40],
508
+ [:doc_string, '', "Makes Homer something something\nAnd something else", 41 ],
509
+ [:step, "Then ", "crazy", 45],
510
+ [:eof]
511
+ ]
512
+ end
513
+ end
514
+
515
+ describe "Windows stuff" do
516
+ it "should find things in the right order for CRLF features" do
517
+ scan_file("dos_line_endings.feature")
518
+ @listener.to_sexp.should == [
519
+ [:comment, "#Comment on line 1", 1],
520
+ [:comment, "#Comment on line 2", 2],
521
+ [:tag, "@tag1", 3],
522
+ [:tag, "@tag2", 3],
523
+ [:feature, "Feature", "Feature Text", "In order to test multiline forms\r\nAs a ragel writer\r\nI need to check for complex combinations", 4],
524
+ [:comment, "#Comment on line 9", 9],
525
+ [:comment, "#Comment on line 11", 11],
526
+ [:background, "Background", "", "", 13],
527
+ [:step, "Given ", "this is a background step", 14],
528
+ [:step, "And ", "this is another one", 15],
529
+ [:tag, "@tag3", 17],
530
+ [:tag, "@tag4", 17],
531
+ [:scenario, "Scenario", "Reading a Scenario", "", 18],
532
+ [:step, "Given ", "there is a step", 19],
533
+ [:step, "But ", "not another step", 20],
534
+ [:tag, "@tag3", 22],
535
+ [:scenario, "Scenario", "Reading a second scenario", "With two lines of text", 23],
536
+ [:comment, "#Comment on line 24", 25],
537
+ [:step, "Given ", "a third step with a table", 26],
538
+ [:row, %w{a b}, 27],
539
+ [:row, %w{c d}, 28],
540
+ [:row, %w{e f}, 29],
541
+ [:step, "And ", "I am still testing things", 30],
542
+ [:row, %w{g h}, 31],
543
+ [:row, %w{e r}, 32],
544
+ [:row, %w{k i}, 33],
545
+ [:row, ['n', ''], 34],
546
+ [:step, "And ", "I am done testing these tables", 35],
547
+ [:comment, "#Comment on line 29", 36],
548
+ [:step, "Then ", "I am happy", 37],
549
+ [:scenario, "Scenario", "Hammerzeit", "", 39],
550
+ [:step, "Given ", "All work and no play", 40],
551
+ [:doc_string, '', "Makes Homer something something\r\nAnd something else", 41],
552
+ [:step, "Then ", "crazy", 45],
553
+ [:eof]
554
+ ]
555
+ end
556
+ end
557
+
558
+ describe "errors" do
559
+ it "should raise a Lexing error if an unparseable token is found" do
560
+ ["Some text\nFeature: Hi",
561
+ "Feature: Hi\nBackground:\nGiven something\nScenario A scenario",
562
+ "Scenario: My scenario\nGiven foo\nAand bar\nScenario: another one\nGiven blah"].each do |text|
563
+ lambda { scan(text) }.should raise_error(/Lexing error on line/)
564
+ end
565
+ end
566
+
567
+ it "should include the line number and context of the error" do
568
+ lambda {
569
+ scan("Feature: hello\nScenario: My scenario\nGiven foo\nAand blah\nHmmm wrong\nThen something something")
570
+ }.should raise_error(/Lexing error on line 4/)
571
+ end
572
+
573
+ it "Feature keyword should terminate narratives for multiline capable tokens" do
574
+ scan("Feature:\nBackground:\nFeature:\nScenario Outline:\nFeature:\nScenario:\nFeature:\nExamples:\nFeature:\n")
575
+ @listener.to_sexp.should == [
576
+ [:feature, "Feature", "", "", 1],
577
+ [:background, "Background", "", "", 2],
578
+ [:feature, "Feature", "", "", 3],
579
+ [:scenario_outline, "Scenario Outline", "", "", 4],
580
+ [:feature, "Feature", "", "", 5],
581
+ [:scenario, "Scenario", "", "", 6],
582
+ [:feature, "Feature", "", "", 7],
583
+ [:examples, "Examples", "","", 8],
584
+ [:feature, "Feature", "", "", 9],
585
+ [:eof]
586
+ ]
587
+ end
588
+ end
589
+ end
590
+ end
591
+ end