gherkin 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitattributes +1 -0
  2. data/History.txt +18 -0
  3. data/README.rdoc +4 -1
  4. data/Rakefile +4 -2
  5. data/VERSION.yml +1 -1
  6. data/bin/gherkin +1 -1
  7. data/dotnet/.gitignore +13 -0
  8. data/features/feature_parser.feature +22 -2
  9. data/features/native_lexer.feature +1 -1
  10. data/features/parser_with_native_lexer.feature +1 -1
  11. data/features/step_definitions/gherkin_steps.rb +2 -6
  12. data/features/step_definitions/pretty_printer_steps.rb +2 -3
  13. data/features/steps_parser.feature +1 -1
  14. data/gherkin.gemspec +53 -24
  15. data/java/Gherkin.iml +2 -4
  16. data/java/build.xml +3 -0
  17. data/java/src/gherkin/FixJava.java +6 -3
  18. data/java/src/gherkin/I18nLexer.java +48 -0
  19. data/java/src/gherkin/Listener.java +3 -1
  20. data/java/src/gherkin/Main.java +17 -0
  21. data/java/src/gherkin/Parser.java +9 -3
  22. data/java/src/gherkin/formatter/Argument.java +39 -0
  23. data/java/src/gherkin/formatter/ArgumentFormat.java +17 -0
  24. data/java/src/gherkin/formatter/Colors.java +7 -0
  25. data/java/src/gherkin/formatter/Formatter.java +15 -0
  26. data/java/src/gherkin/formatter/PrettyFormatter.java +219 -0
  27. data/java/src/gherkin/parser/StateMachineReader.java +8 -3
  28. data/java/test/gherkin/formatter/ArgumentTest.java +17 -0
  29. data/lib/gherkin/csharp_lexer.rb +15 -0
  30. data/lib/gherkin/format/argument.rb +35 -0
  31. data/lib/gherkin/format/monochrome_format.rb +9 -0
  32. data/lib/gherkin/i18n.rb +22 -0
  33. data/lib/gherkin/i18n.yml +34 -20
  34. data/lib/gherkin/i18n_lexer.rb +57 -13
  35. data/lib/gherkin/lexer.rb +9 -18
  36. data/lib/gherkin/parser.rb +3 -3
  37. data/lib/gherkin/parser/meta.txt +5 -4
  38. data/lib/gherkin/parser/root.txt +11 -9
  39. data/lib/gherkin/parser/steps.txt +4 -3
  40. data/lib/gherkin/rb_parser.rb +13 -5
  41. data/lib/gherkin/tools/colors.rb +119 -0
  42. data/lib/gherkin/tools/files.rb +6 -1
  43. data/lib/gherkin/tools/pretty_listener.rb +115 -23
  44. data/ragel/lexer.c.rl.erb +67 -51
  45. data/ragel/lexer.csharp.rl.erb +240 -0
  46. data/ragel/lexer.java.rl.erb +27 -18
  47. data/ragel/lexer.rb.rl.erb +17 -17
  48. data/ragel/lexer_common.rl.erb +8 -8
  49. data/spec/gherkin/c_lexer_spec.rb +4 -4
  50. data/spec/gherkin/csharp_lexer_spec.rb +20 -0
  51. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  52. data/spec/gherkin/fixtures/complex.feature +2 -0
  53. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  54. data/spec/gherkin/fixtures/i18n_fr.feature +1 -0
  55. data/spec/gherkin/fixtures/i18n_no.feature +1 -0
  56. data/spec/gherkin/fixtures/i18n_zh-CN.feature +1 -0
  57. data/spec/gherkin/format/argument_spec.rb +28 -0
  58. data/spec/gherkin/i18n_lexer_spec.rb +4 -4
  59. data/spec/gherkin/i18n_spec.rb +31 -23
  60. data/spec/gherkin/java_lexer_spec.rb +4 -3
  61. data/spec/gherkin/parser_spec.rb +5 -0
  62. data/spec/gherkin/rb_lexer_spec.rb +4 -2
  63. data/spec/gherkin/sexp_recorder.rb +1 -1
  64. data/spec/gherkin/shared/lexer_spec.rb +169 -60
  65. data/spec/gherkin/shared/py_string_spec.rb +6 -0
  66. data/spec/gherkin/shared/row_spec.rb +107 -0
  67. data/spec/gherkin/shared/tags_spec.rb +1 -1
  68. data/spec/gherkin/tools/colors_spec.rb +19 -0
  69. data/spec/gherkin/tools/pretty_listener_spec.rb +147 -0
  70. data/spec/spec_helper.rb +31 -7
  71. data/tasks/compile.rake +81 -7
  72. data/tasks/ragel_task.rb +6 -4
  73. data/tasks/rspec.rake +2 -2
  74. metadata +104 -41
  75. data/lib/gherkin/java_lexer.rb +0 -10
  76. data/spec/gherkin/shared/table_spec.rb +0 -97
@@ -0,0 +1,20 @@
1
+ #encoding: utf-8
2
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ironruby"
3
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
4
+
5
+ module Gherkin
6
+ module Lexer
7
+ describe "C# Lexer" do
8
+ before do
9
+ @listener = Gherkin::SexpRecorder.new
10
+ @lexer = Gherkin::Lexer.csharp['en'].new(@listener)
11
+ end
12
+
13
+ it_should_behave_like "a Gherkin lexer"
14
+ it_should_behave_like "a Gherkin lexer lexing tags"
15
+ it_should_behave_like "a Gherkin lexer lexing py_strings"
16
+ it_should_behave_like "a Gherkin lexer lexing rows"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ Feature: x
2
+
3
+ Scenario Outline: x
4
+ Then x is <state>
5
+
6
+ Examples:
7
+ | state |
8
+ # comment
9
+ | 1 |
@@ -21,6 +21,7 @@ Feature: Feature Text
21
21
 
22
22
  @tag3
23
23
  Scenario: Reading a second scenario
24
+ With two lines of text
24
25
  #Comment on line 24
25
26
  Given a third step with a table
26
27
  |a|b|
@@ -39,5 +40,6 @@ Feature: Feature Text
39
40
  Given All work and no play
40
41
  """
41
42
  Makes Homer something something
43
+ And something else
42
44
  """
43
45
  Then crazy
@@ -0,0 +1,45 @@
1
+ #Comment on line 1
2
+ #Comment on line 2
3
+ @tag1 @tag2
4
+ Feature: Feature Text
5
+ In order to test multiline forms
6
+ As a ragel writer
7
+ I need to check for complex combinations
8
+
9
+ #Comment on line 9
10
+
11
+ #Comment on line 11
12
+
13
+ Background:
14
+ Given this is a background step
15
+ And this is another one
16
+
17
+ @tag3 @tag4
18
+ Scenario: Reading a Scenario
19
+ Given there is a step
20
+ But not another step
21
+
22
+ @tag3
23
+ Scenario: Reading a second scenario
24
+ With two lines of text
25
+ #Comment on line 24
26
+ Given a third step with a table
27
+ |a|b|
28
+ |c|d|
29
+ |e|f|
30
+ And I am still testing things
31
+ |g|h|
32
+ |e|r|
33
+ |k|i|
34
+ |n||
35
+ And I am done testing these tables
36
+ #Comment on line 29
37
+ Then I am happy
38
+
39
+ Scenario: Hammerzeit
40
+ Given All work and no play
41
+ """
42
+ Makes Homer something something
43
+ And something else
44
+ """
45
+ Then crazy
@@ -1,3 +1,4 @@
1
+ #language:fr
1
2
  Fonctionnalité: Addition
2
3
  Plan du scénario: Addition de produits dérivés
3
4
  Soit une calculatrice
@@ -1,3 +1,4 @@
1
+ #language:no
1
2
  Egenskap: i18n support
2
3
 
3
4
  Scenario: Parsing many languages
@@ -1,3 +1,4 @@
1
+ #language:zh-CN
1
2
  功能:加法
2
3
 
3
4
  场景: 两个数相加
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+ require 'gherkin/format/argument'
4
+
5
+ module Gherkin
6
+ module Format
7
+ class BracketFormat
8
+ class << self
9
+ def new
10
+ defined?(JRUBY_VERSION) ? ::Java::GherkinFormatter::ArgumentFormat.new("[", "]") : super
11
+ end
12
+ end
13
+
14
+ def format_argument(s)
15
+ "[#{s}]"
16
+ end
17
+ end
18
+
19
+ describe Argument do
20
+ it "should replace one arg" do
21
+ argument_class = defined?(JRUBY_VERSION) ? ::Java::GherkinFormatter::Argument : Argument
22
+ argument_class.format("I have 10 cukes", BracketFormat.new, [Argument.new(7, '10')]).should == "I have [10] cukes"
23
+ end
24
+
25
+ # TODO: Add this spec: http://github.com/alg/cucumber/commit/33188e9db51f59ced74c4861524d7b2e69454630
26
+ end
27
+ end
28
+ end
@@ -4,19 +4,19 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
4
4
  module Gherkin
5
5
  describe I18nLexer do
6
6
  before do
7
- @lexer = I18nLexer.new(SexpRecorder.new)
7
+ @lexer = I18nLexer.new(SexpRecorder.new, false)
8
8
  end
9
9
 
10
10
  it "should store the i18n language of the last scanned feature" do
11
11
  @lexer.scan("# language: fr\n")
12
- @lexer.language.key.should == "fr"
12
+ @lexer.i18n_language.should == "fr"
13
13
  @lexer.scan("# language: no\n")
14
- @lexer.language.key.should == "no"
14
+ @lexer.i18n_language.should == "no"
15
15
  end
16
16
 
17
17
  it "should use English i18n by default" do
18
18
  @lexer.scan("Feature: foo\n")
19
- @lexer.language.key.should == "en"
19
+ @lexer.i18n_language.should == "en"
20
20
  end
21
21
  end
22
22
  end
@@ -13,43 +13,51 @@ module Gherkin
13
13
  end
14
14
 
15
15
  it "should recognize keywords in the language of the lexer" do
16
- lexer = Gherkin::Lexer['no'].new(@listener)
16
+ lexer = Gherkin::I18nLexer.new(@listener, false)
17
17
  scan_file(lexer, "i18n_no.feature")
18
18
  @listener.to_sexp.should == [
19
- [:feature, "Egenskap", "i18n support", 1],
20
- [:scenario, "Scenario", "Parsing many languages", 3],
21
- [:step, "Gitt", "Gherkin supports many languages", 4],
22
- [:step, "Når", "Norwegian keywords are parsed", 5],
23
- [:step, "", "they should be recognized", 6]
19
+ [:comment, "#language:no", 1],
20
+ [:feature, "Egenskap", "i18n support", 2],
21
+ [:scenario, "Scenario", "Parsing many languages", 4],
22
+ [:step, "Gitt ", "Gherkin supports many languages", 5],
23
+ [:step, "Når ", "Norwegian keywords are parsed", 6],
24
+ [:step, "Så ", "they should be recognized", 7],
25
+ [:eof]
24
26
  ]
25
27
  end
26
28
 
27
29
  it "should parse languages without a space after keywords" do
28
- lexer = Gherkin::Lexer['zh-CN'].new(@listener)
30
+ lexer = Gherkin::I18nLexer.new(@listener, false)
29
31
  scan_file(lexer, "i18n_zh-CN.feature")
30
32
  @listener.to_sexp.should == [
31
- [:feature, "功能", "加法", 1],
32
- [:scenario, "场景", "两个数相加", 3],
33
- [:step, "假如", "我已经在计算器里输入6", 4],
34
- [:step, "而且", "我已经在计算器里输入7", 5],
35
- [:step, "", "我按相加按钮", 6],
36
- [:step, "那么", "我应该在屏幕上看到的结果是13", 7]
33
+ [:comment, "#language:zh-CN", 1],
34
+ [:feature, "功能", "加法", 2],
35
+ [:scenario, "场景", "两个数相加", 4],
36
+ [:step, "假如", "我已经在计算器里输入6", 5],
37
+ [:step, "而且", "我已经在计算器里输入7", 6],
38
+ [:step, "", "我按相加按钮", 7],
39
+ [:step, "那么", "我应该在屏幕上看到的结果是13", 8],
40
+ [:eof]
37
41
  ]
38
42
  end
39
43
 
40
44
  it "should parse languages with spaces after some keywords but not others" do
41
- lexer = Gherkin::Lexer['fr'].new(@listener)
45
+ lexer = Gherkin::I18nLexer.new(@listener, false)
42
46
  scan_file(lexer, "i18n_fr.feature")
43
47
  @listener.to_sexp.should == [
44
- [:feature, "Fonctionnalité", "Addition", 1],
45
- [:scenario_outline, "Plan du scénario", "Addition de produits dérivés", 2],
46
- [:step, "Soit", "une calculatrice", 3],
47
- [:step, "Etant donné", "qu'on tape <a>", 4],
48
- [:step, "Et", "qu'on tape <b>", 5],
49
- [:step, "Lorsqu'", "on tape additionner", 6],
50
- [:step, "Alors", "le résultat doit être <somme>", 7],
51
- [:examples, "Exemples", "", 9],
52
- [:table, [["a","b","somme"],["2","2","4"],["2","3","5"]], 10]
48
+ [:comment, "#language:fr", 1],
49
+ [:feature, "Fonctionnalité", "Addition", 2],
50
+ [:scenario_outline, "Plan du scénario", "Addition de produits dérivés", 3],
51
+ [:step, "Soit ", "une calculatrice", 4],
52
+ [:step, "Etant donné ", "qu'on tape <a>", 5],
53
+ [:step, "Et ", "qu'on tape <b>", 6],
54
+ [:step, "Lorsqu'", "on tape additionner", 7],
55
+ [:step, "Alors ", "le résultat doit être <somme>", 8],
56
+ [:examples, "Exemples", "", 10],
57
+ [:row, %w{a b somme}, 11],
58
+ [:row, %w{2 2 4}, 12],
59
+ [:row, %w{2 3 5}, 13],
60
+ [:eof]
53
61
  ]
54
62
  end
55
63
  end
@@ -1,20 +1,21 @@
1
1
  #encoding: utf-8
2
2
  if defined?(JRUBY_VERSION)
3
3
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
4
+ require 'gherkin.jar'
4
5
 
5
6
  module Gherkin
6
7
  module JavaLexer
7
8
  describe "Java Lexer" do
8
9
  before do
9
10
  @listener = Gherkin::SexpRecorder.new
10
- @lexer = Gherkin::Lexer.java['en'].new(@listener)
11
+ @lexer = Java::Gherkin::I18nLexer.new(@listener)
11
12
  end
12
13
 
13
14
  it_should_behave_like "a Gherkin lexer"
14
15
  it_should_behave_like "a Gherkin lexer lexing tags"
15
16
  it_should_behave_like "a Gherkin lexer lexing py_strings"
16
- it_should_behave_like "a Gherkin lexer lexing tables"
17
+ it_should_behave_like "a Gherkin lexer lexing rows"
17
18
  end
18
19
  end
19
20
  end
20
- end
21
+ end
@@ -19,6 +19,11 @@ module Gherkin
19
19
  }.should raise_error(/Parse error on line 12\. Found scenario when expecting one of: comment, feature, tag\. \(Current state: root\)\.$/)
20
20
  end
21
21
 
22
+ it "should allow empty files" do
23
+ @listener.should_receive(:eof)
24
+ @parser.eof
25
+ end
26
+
22
27
  it "should delegate an error message when raise on error is false" do
23
28
  @listener.should_receive(:syntax_error).with(sym(:root), sym(:background), a([:comment, :feature, :tag]), 1)
24
29
  @parser = Parser.new(@listener, false)
@@ -1,18 +1,20 @@
1
1
  #encoding: utf-8
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require 'gherkin/rb_lexer'
4
+ require 'gherkin/rb_lexer/en'
3
5
 
4
6
  module Gherkin
5
7
  module Lexer
6
8
  describe "Ruby Lexer" do
7
9
  before do
8
10
  @listener = Gherkin::SexpRecorder.new
9
- @lexer = Gherkin::Lexer.rb['en'].new(@listener)
11
+ @lexer = Gherkin::RbLexer::En.new(@listener)
10
12
  end
11
13
 
12
14
  it_should_behave_like "a Gherkin lexer"
13
15
  it_should_behave_like "a Gherkin lexer lexing tags"
14
16
  it_should_behave_like "a Gherkin lexer lexing py_strings"
15
- it_should_behave_like "a Gherkin lexer lexing tables"
17
+ it_should_behave_like "a Gherkin lexer lexing rows"
16
18
  end
17
19
  end
18
20
  end
@@ -5,7 +5,7 @@ module Gherkin
5
5
  end
6
6
 
7
7
  def method_missing(m, *args)
8
- args[0] = args[0].map{|row| row.map{|cell| cell}} if m == :table
8
+ args[0] = args[0].map{|cell| cell} if m == :row
9
9
  @sexps << [m] + args
10
10
  end
11
11
 
@@ -8,14 +8,18 @@ module Gherkin
8
8
  describe "Comments" do
9
9
  it "should parse a one line comment" do
10
10
  @lexer.scan("# My comment\n")
11
- @listener.to_sexp.should == [[:comment, "# My comment", 1]]
11
+ @listener.to_sexp.should == [
12
+ [:comment, "# My comment", 1],
13
+ [:eof]
14
+ ]
12
15
  end
13
16
 
14
17
  it "should parse a multiline comment" do
15
18
  @lexer.scan("# Hello\n\n# World\n")
16
19
  @listener.to_sexp.should == [
17
20
  [:comment, "# Hello", 1],
18
- [:comment, "# World", 3]
21
+ [:comment, "# World", 3],
22
+ [:eof]
19
23
  ]
20
24
  end
21
25
 
@@ -24,7 +28,8 @@ module Gherkin
24
28
  @listener.to_sexp.should == [
25
29
  [:scenario, "Scenario", "test", 1],
26
30
  [:comment, "#hello", 2],
27
- [:scenario, "Scenario", "another", 3]
31
+ [:scenario, "Scenario", "another", 3],
32
+ [:eof]
28
33
  ]
29
34
  end
30
35
 
@@ -33,7 +38,8 @@ module Gherkin
33
38
  @listener.to_sexp.should == [
34
39
  [:comment, "#", 1],
35
40
  [:comment, "# A comment", 2],
36
- [:comment, "#", 3]
41
+ [:comment, "#", 3],
42
+ [:eof]
37
43
  ]
38
44
  end
39
45
 
@@ -51,7 +57,8 @@ module Gherkin
51
57
  [:feature, "Feature", "hi", 1],
52
58
  [:scenario, "Scenario", "test", 2],
53
59
  [:tag, "hello", 4],
54
- [:scenario, "Scenario", "another", 5]
60
+ [:scenario, "Scenario", "another", 5],
61
+ [:eof]
55
62
  ]
56
63
  end
57
64
  end
@@ -61,14 +68,16 @@ module Gherkin
61
68
  @lexer.scan("Background:\nGiven I am a step\n")
62
69
  @listener.to_sexp.should == [
63
70
  [:background, "Background", "", 1],
64
- [:step, "Given", "I am a step", 2]
71
+ [:step, "Given ", "I am a step", 2],
72
+ [:eof]
65
73
  ]
66
74
  end
67
75
 
68
76
  it "should allow multiline names ending at eof" do
69
77
  @lexer.scan("Background: I have several\n Lines to look at\n None starting with Given")
70
78
  @listener.to_sexp.should == [
71
- [:background, "Background", "I have several\nLines to look at\nNone starting with Given", 1]
79
+ [:background, "Background", "I have several\nLines to look at\nNone starting with Given", 1],
80
+ [:eof]
72
81
  ]
73
82
  end
74
83
 
@@ -82,7 +91,8 @@ Given I am a step})
82
91
  @listener.to_sexp.should == [
83
92
  [:feature, "Feature", "Hi", 1],
84
93
  [:background, "Background", "It is my ambition to say\nin ten sentences\nwhat others say\nin a whole book.",2],
85
- [:step, "Given", "I am a step", 6]
94
+ [:step, "Given ", "I am a step", 6],
95
+ [:eof]
86
96
  ]
87
97
  end
88
98
  end
@@ -91,7 +101,8 @@ Given I am a step})
91
101
  it "should be parsed" do
92
102
  @lexer.scan("Scenario: Hello\n")
93
103
  @listener.to_sexp.should == [
94
- [:scenario, "Scenario", "Hello", 1]
104
+ [:scenario, "Scenario", "Hello", 1],
105
+ [:eof]
95
106
  ]
96
107
  end
97
108
 
@@ -102,7 +113,8 @@ Given I am a step})
102
113
  })
103
114
  @listener.to_sexp.should == [
104
115
  [:scenario, "Scenario", "bar", 1],
105
- [:step, "Given", "baz", 3]
116
+ [:step, "Given ", "baz", 3],
117
+ [:eof]
106
118
  ]
107
119
  end
108
120
 
@@ -115,14 +127,16 @@ Given I am a step})
115
127
  })
116
128
  @listener.to_sexp.should == [
117
129
  [:scenario, "Scenario", "It is my ambition to say\nin ten sentences\nwhat others say\nin a whole book.", 1],
118
- [:step, "Given", "I am a step", 5]
130
+ [:step, "Given ", "I am a step", 5],
131
+ [:eof]
119
132
  ]
120
133
  end
121
134
 
122
135
  it "should allow multiline names ending at eof" do
123
136
  @lexer.scan("Scenario: I have several\n Lines to look at\n None starting with Given")
124
137
  @listener.to_sexp.should == [
125
- [:scenario, "Scenario", "I have several\nLines to look at\nNone starting with Given", 1]
138
+ [:scenario, "Scenario", "I have several\nLines to look at\nNone starting with Given", 1],
139
+ [:eof]
126
140
  ]
127
141
  end
128
142
 
@@ -134,8 +148,9 @@ Given I am a step})
134
148
  })
135
149
  @listener.to_sexp.should == [
136
150
  [:scenario, "Scenario", "I have a Button\nButtons are great", 1],
137
- [:step, "Given", "I have some", 3],
138
- [:step, "But", "I might not because I am a Charles Dickens character", 4]
151
+ [:step, "Given ", "I have some", 3],
152
+ [:step, "But ", "I might not because I am a Charles Dickens character", 4],
153
+ [:eof]
139
154
  ]
140
155
  end
141
156
 
@@ -146,7 +161,8 @@ Given I am a step
146
161
  })
147
162
  @listener.to_sexp.should == [
148
163
  [:scenario, "Scenario", "When I have when in scenario\nI should be fine", 1],
149
- [:step, "Given", "I am a step", 3]
164
+ [:step, "Given ", "I am a step", 3],
165
+ [:eof]
150
166
  ]
151
167
  end
152
168
  end
@@ -161,9 +177,11 @@ Given I am a step
161
177
  })
162
178
  @listener.to_sexp.should == [
163
179
  [:scenario_outline, "Scenario Outline", "Hello", 1],
164
- [:step, "Given", "a <what> cucumber", 2],
180
+ [:step, "Given ", "a <what> cucumber", 2],
165
181
  [:examples, "Examples", "", 3],
166
- [:table, [["what"],["green"]], 4]
182
+ [:row, ["what"], 4],
183
+ [:row, ["green"], 5],
184
+ [:eof]
167
185
  ]
168
186
  end
169
187
 
@@ -174,7 +192,8 @@ Given I am a step
174
192
  })
175
193
  @listener.to_sexp.should == [
176
194
  [:scenario_outline, "Scenario Outline", "Hello", 1],
177
- [:scenario, "Scenario", "My Scenario", 3]
195
+ [:scenario, "Scenario", "My Scenario", 3],
196
+ [:eof]
178
197
  ]
179
198
  end
180
199
 
@@ -188,7 +207,8 @@ Given I am a step
188
207
  })
189
208
  @listener.to_sexp.should == [
190
209
  [:scenario_outline, "Scenario Outline", "It is my ambition to say\nin ten sentences\nwhat others say\nin a whole book.", 1],
191
- [:step, "Given", "I am a step", 5]
210
+ [:step, "Given ", "I am a step", 5],
211
+ [:eof]
192
212
  ]
193
213
  end
194
214
  end
@@ -201,7 +221,9 @@ Given I am a step
201
221
  })
202
222
  @listener.to_sexp.should == [
203
223
  [:examples, "Examples", "", 1],
204
- [:table, [["x","y"],["5","6"]], 2]
224
+ [:row, ["x","y"], 2],
225
+ [:row, ["5","6"], 3],
226
+ [:eof]
205
227
  ]
206
228
  end
207
229
 
@@ -214,7 +236,9 @@ Given I am a step
214
236
  })
215
237
  @listener.to_sexp.should == [
216
238
  [:examples, "Examples", "I'm a multiline name\nand I'm ok\nf'real", 1],
217
- [:table, [["x"],["5"]], 4]
239
+ [:row, ["x"], 4],
240
+ [:row, ["5"], 5],
241
+ [:eof]
218
242
  ]
219
243
  end
220
244
  end
@@ -225,16 +249,18 @@ Given I am a step
225
249
  |a|b|
226
250
  })
227
251
  @listener.to_sexp.should == [
228
- [:step, "Given", "I have a table", 1],
229
- [:table, [['a','b']], 2]
252
+ [:step, "Given ", "I have a table", 1],
253
+ [:row, ['a','b'], 2],
254
+ [:eof]
230
255
  ]
231
256
  end
232
257
 
233
258
  it "should parse steps with inline py_string" do
234
259
  @lexer.scan("Given I have a string\n\"\"\"\nhello\nworld\n\"\"\"")
235
260
  @listener.to_sexp.should == [
236
- [:step, "Given", "I have a string", 1],
237
- [:py_string, "hello\nworld", 2]
261
+ [:step, "Given ", "I have a string", 1],
262
+ [:py_string, "hello\nworld", 2],
263
+ [:eof]
238
264
  ]
239
265
  end
240
266
  end
@@ -245,7 +271,8 @@ Given I am a step
245
271
  @listener.to_sexp.should == [
246
272
  [:feature, "Feature", "Feature Text", 1],
247
273
  [:scenario, "Scenario", "Reading a Scenario", 2],
248
- [:step, "Given", "there is a step", 3]
274
+ [:step, "Given ", "there is a step", 3],
275
+ [:eof]
249
276
  ]
250
277
  end
251
278
  end
@@ -256,7 +283,8 @@ Given I am a step
256
283
  @listener.to_sexp.should == [
257
284
  [:feature, "Feature", "Feature Text", 1],
258
285
  [:scenario, "Scenario", "Reading a Scenario", 2],
259
- [:step, "Given", "there is a step", 3]
286
+ [:step, "Given ", "there is a step", 3],
287
+ [:eof]
260
288
  ]
261
289
  end
262
290
  end
@@ -268,9 +296,10 @@ Given I am a step
268
296
  @listener.to_sexp.should == [
269
297
  [:feature, "Feature", "Feature Text", 1],
270
298
  [:scenario, "Scenario", "Reading a Scenario", 2],
271
- [:step, "Given", "there is a step", 3],
272
- [:step, "And", "another step", 4],
273
- [:step, "And", "a third step", 5]
299
+ [:step, "Given ", "there is a step", 3],
300
+ [:step, "And ", "another step", 4],
301
+ [:step, "And ", "a third step", 5],
302
+ [:eof]
274
303
  ]
275
304
  end
276
305
  end
@@ -278,19 +307,28 @@ Given I am a step
278
307
  describe "A single feature with no scenario" do
279
308
  it "should find the feature" do
280
309
  @lexer.scan("Feature: Feature Text\n")
281
- @listener.to_sexp.should == [[:feature, "Feature", "Feature Text", 1]]
310
+ @listener.to_sexp.should == [
311
+ [:feature, "Feature", "Feature Text", 1],
312
+ [:eof]
313
+ ]
282
314
  end
283
315
 
284
316
  it "should parse a one line feature with no newline" do
285
317
  @lexer.scan("Feature: hi")
286
- @listener.to_sexp.should == [[:feature, "Feature", "hi", 1]]
318
+ @listener.to_sexp.should == [
319
+ [:feature, "Feature", "hi", 1],
320
+ [:eof]
321
+ ]
287
322
  end
288
323
  end
289
324
 
290
325
  describe "A multi-line feature with no scenario" do
291
326
  it "should find the feature" do
292
327
  @lexer.scan("Feature: Feature Text\n And some more text")
293
- @listener.to_sexp.should == [[:feature, "Feature", "Feature Text\nAnd some more text", 1]]
328
+ @listener.to_sexp.should == [
329
+ [:feature, "Feature", "Feature Text\nAnd some more text", 1],
330
+ [:eof]
331
+ ]
294
332
  end
295
333
  end
296
334
 
@@ -299,7 +337,8 @@ Given I am a step
299
337
  @lexer.scan("Feature: Feature Text\nScenario: Reading a Scenario\n")
300
338
  @listener.to_sexp.should == [
301
339
  [:feature, "Feature", "Feature Text", 1],
302
- [:scenario, "Scenario", "Reading a Scenario", 2]
340
+ [:scenario, "Scenario", "Reading a Scenario", 2],
341
+ [:eof]
303
342
  ]
304
343
  end
305
344
  end
@@ -310,9 +349,10 @@ Given I am a step
310
349
  @listener.to_sexp.should == [
311
350
  [:feature, "Feature", "Feature Text", 1],
312
351
  [:scenario, "Scenario", "Reading a Scenario", 2],
313
- [:step, "Given", "a step", 3],
352
+ [:step, "Given ", "a step", 3],
314
353
  [:scenario, "Scenario", "A second scenario", 5],
315
- [:step, "Given", "another step", 6]
354
+ [:step, "Given ", "another step", 6],
355
+ [:eof]
316
356
  ]
317
357
  end
318
358
 
@@ -321,9 +361,10 @@ Given I am a step
321
361
  @listener.to_sexp.should == [
322
362
  [:feature, "Feature", "Feature Text", 1],
323
363
  [:scenario, "Scenario", "Reading a Scenario", 2],
324
- [:step, "Given", "a step", 3],
364
+ [:step, "Given ", "a step", 3],
325
365
  [:scenario, "Scenario", "A second scenario", 4],
326
- [:step, "Given", "another step", 5]
366
+ [:step, "Given ", "another step", 5],
367
+ [:eof]
327
368
  ]
328
369
  end
329
370
  end
@@ -337,8 +378,23 @@ Given I am a step
337
378
  [:comment, "# Here is another # comment", 3],
338
379
  [:scenario, "Scenario", "Reading a Scenario", 4],
339
380
  [:comment, "# Here is a third comment", 5],
340
- [:step, "Given", "there is a step", 6],
341
- [:comment, "# Here is a fourth comment", 7]
381
+ [:step, "Given ", "there is a step", 6],
382
+ [:comment, "# Here is a fourth comment", 7],
383
+ [:eof]
384
+ ]
385
+ end
386
+
387
+ it "should support comments in tables" do
388
+ scan_file("comments_in_table.feature")
389
+ @listener.to_sexp.should == [
390
+ [:feature, "Feature", "x", 1],
391
+ [:scenario_outline, "Scenario Outline", "x", 3],
392
+ [:step, "Then ", "x is <state>", 4],
393
+ [:examples, "Examples", "", 6],
394
+ [:row, ["state"], 7],
395
+ [:comment, "# comment", 8],
396
+ [:row, ["1"], 9],
397
+ [:eof]
342
398
  ]
343
399
  end
344
400
  end
@@ -353,12 +409,13 @@ Given I am a step
353
409
  [:tag, "st1", 5],
354
410
  [:tag, "st2", 5],
355
411
  [:scenario, "Scenario", "First", 6],
356
- [:step, "Given", "Pepper", 7],
412
+ [:step, "Given ", "Pepper", 7],
357
413
  [:tag, "st3", 9],
358
414
  [:tag, "st4", 10],
359
415
  [:tag, "ST5", 10],
360
416
  [:tag, "#^%&ST6**!", 10],
361
- [:scenario, "Scenario", "Second", 11]
417
+ [:scenario, "Scenario", "Second", 11],
418
+ [:eof]
362
419
  ]
363
420
  end
364
421
  end
@@ -371,7 +428,8 @@ Given I am a step
371
428
  [:comment, "# Comment", 3],
372
429
  [:scenario, "Scenario", "Anonymous user can get a login form.\nScenery here", 4],
373
430
  [:tag, "tag", 7],
374
- [:scenario, "Scenario", "Another one", 8]
431
+ [:scenario, "Scenario", "Another one", 8],
432
+ [:eof]
375
433
  ]
376
434
  end
377
435
  end
@@ -388,30 +446,81 @@ Given I am a step
388
446
  [:comment, "#Comment on line 9", 9],
389
447
  [:comment, "#Comment on line 11", 11],
390
448
  [:background, "Background", "", 13],
391
- [:step, "Given", "this is a background step", 14],
392
- [:step, "And", "this is another one", 15],
449
+ [:step, "Given ", "this is a background step", 14],
450
+ [:step, "And ", "this is another one", 15],
393
451
  [:tag, "tag3", 17],
394
452
  [:tag, "tag4", 17],
395
453
  [:scenario, "Scenario", "Reading a Scenario", 18],
396
- [:step, "Given", "there is a step", 19],
397
- [:step, "But", "not another step", 20],
454
+ [:step, "Given ", "there is a step", 19],
455
+ [:step, "But ", "not another step", 20],
398
456
  [:tag, "tag3", 22],
399
- [:scenario, "Scenario", "Reading a second scenario", 23],
400
- [:comment, "#Comment on line 24", 24],
401
- [:step, "Given", "a third step with a table", 25],
402
- [:table, [['a','b'],['c','d'],['e','f']], 26],
403
- [:step, "And", "I am still testing things", 29],
404
- [:table, [['g','h'],['e','r'],['k','i'],['n','']], 30],
405
- [:step, "And", "I am done testing these tables", 34],
406
- [:comment, "#Comment on line 29", 35],
407
- [:step, "Then", "I am happy", 36],
408
- [:scenario, "Scenario", "Hammerzeit", 38],
409
- [:step, "Given", "All work and no play", 39],
410
- [:py_string, "Makes Homer something something", 40],
411
- [:step, "Then", "crazy", 43]
457
+ [:scenario, "Scenario", "Reading a second scenario\nWith two lines of text", 23],
458
+ [:comment, "#Comment on line 24", 25],
459
+ [:step, "Given ", "a third step with a table", 26],
460
+ [:row, %w{a b}, 27],
461
+ [:row, %w{c d}, 28],
462
+ [:row, %w{e f}, 29],
463
+ [:step, "And ", "I am still testing things", 30],
464
+ [:row, %w{g h}, 31],
465
+ [:row, %w{e r}, 32],
466
+ [:row, %w{k i}, 33],
467
+ [:row, ['n', ''], 34],
468
+ [:step, "And ", "I am done testing these tables", 35],
469
+ [:comment, "#Comment on line 29", 36],
470
+ [:step, "Then ", "I am happy", 37],
471
+ [:scenario, "Scenario", "Hammerzeit", 39],
472
+ [:step, "Given ", "All work and no play", 40],
473
+ [:py_string, "Makes Homer something something\nAnd something else", 41 ],
474
+ [:step, "Then ", "crazy", 45],
475
+ [:eof]
412
476
  ]
413
477
  end
414
478
  end
479
+
480
+ context "DOS line endings" do
481
+ describe "A complex feature with tags, comments, multiple scenarios, and multiple steps and tables" do
482
+ it "should find things in the right order" do
483
+ scan_file("dos_line_endings.feature")
484
+ @listener.to_sexp.should == [
485
+ [:comment, "#Comment on line 1", 1],
486
+ [:comment, "#Comment on line 2", 2],
487
+ [:tag, "tag1", 3],
488
+ [:tag, "tag2", 3],
489
+ [:feature, "Feature", "Feature Text\r\nIn order to test multiline forms\r\nAs a ragel writer\r\nI need to check for complex combinations", 4],
490
+ [:comment, "#Comment on line 9", 9],
491
+ [:comment, "#Comment on line 11", 11],
492
+ [:background, "Background", "", 13],
493
+ [:step, "Given ", "this is a background step", 14],
494
+ [:step, "And ", "this is another one", 15],
495
+ [:tag, "tag3", 17],
496
+ [:tag, "tag4", 17],
497
+ [:scenario, "Scenario", "Reading a Scenario", 18],
498
+ [:step, "Given ", "there is a step", 19],
499
+ [:step, "But ", "not another step", 20],
500
+ [:tag, "tag3", 22],
501
+ [:scenario, "Scenario", "Reading a second scenario\r\nWith two lines of text", 23],
502
+ [:comment, "#Comment on line 24", 25],
503
+ [:step, "Given ", "a third step with a table", 26],
504
+ [:row, %w{a b}, 27],
505
+ [:row, %w{c d}, 28],
506
+ [:row, %w{e f}, 29],
507
+ [:step, "And ", "I am still testing things", 30],
508
+ [:row, %w{g h}, 31],
509
+ [:row, %w{e r}, 32],
510
+ [:row, %w{k i}, 33],
511
+ [:row, ['n', ''], 34],
512
+ [:step, "And ", "I am done testing these tables", 35],
513
+ [:comment, "#Comment on line 29", 36],
514
+ [:step, "Then ", "I am happy", 37],
515
+ [:scenario, "Scenario", "Hammerzeit", 39],
516
+ [:step, "Given ", "All work and no play", 40],
517
+ [:py_string, "Makes Homer something something\r\nAnd something else", 41],
518
+ [:step, "Then ", "crazy", 45],
519
+ [:eof]
520
+ ]
521
+ end
522
+ end
523
+ end
415
524
 
416
525
  describe "errors" do
417
526
  it "should raise a Lexing error if an unparseable token is found" do