gherkin 2.2.5-x86-mswin32

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