cucumber-cucumber-expressions 10.3.0 → 11.0.0

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/.rsync +1 -0
  3. data/VERSION +1 -1
  4. data/cucumber-cucumber-expressions.gemspec +1 -1
  5. data/examples.txt +5 -1
  6. data/lib/cucumber/cucumber_expressions/ast.rb +201 -0
  7. data/lib/cucumber/cucumber_expressions/cucumber_expression.rb +80 -76
  8. data/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb +4 -8
  9. data/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb +219 -0
  10. data/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb +95 -0
  11. data/lib/cucumber/cucumber_expressions/errors.rb +175 -4
  12. data/lib/cucumber/cucumber_expressions/parameter_type.rb +12 -7
  13. data/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb +24 -0
  14. data/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +62 -140
  15. data/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb +24 -0
  16. data/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +1 -1
  17. data/spec/cucumber/cucumber_expressions/expression_examples_spec.rb +1 -1
  18. data/spec/cucumber/cucumber_expressions/expression_factory_spec.rb +0 -4
  19. data/testdata/ast/alternation-followed-by-optional.yaml +17 -0
  20. data/testdata/ast/alternation-phrase.yaml +16 -0
  21. data/testdata/ast/alternation-with-parameter.yaml +27 -0
  22. data/testdata/ast/alternation-with-unused-end-optional.yaml +15 -0
  23. data/testdata/ast/alternation-with-unused-start-optional.yaml +8 -0
  24. data/testdata/ast/alternation-with-white-space.yaml +12 -0
  25. data/testdata/ast/alternation.yaml +12 -0
  26. data/testdata/ast/anonymous-parameter.yaml +5 -0
  27. data/testdata/ast/closing-brace.yaml +5 -0
  28. data/testdata/ast/closing-parenthesis.yaml +5 -0
  29. data/testdata/ast/empty-alternation.yaml +8 -0
  30. data/testdata/ast/empty-alternations.yaml +9 -0
  31. data/testdata/ast/empty-string.yaml +3 -0
  32. data/testdata/ast/escaped-alternation.yaml +5 -0
  33. data/testdata/ast/escaped-backslash.yaml +5 -0
  34. data/testdata/ast/escaped-opening-parenthesis.yaml +5 -0
  35. data/testdata/ast/escaped-optional-followed-by-optional.yaml +15 -0
  36. data/testdata/ast/escaped-optional-phrase.yaml +10 -0
  37. data/testdata/ast/escaped-optional.yaml +7 -0
  38. data/testdata/ast/opening-brace.yaml +8 -0
  39. data/testdata/ast/opening-parenthesis.yaml +8 -0
  40. data/testdata/ast/optional-containing-nested-optional.yaml +15 -0
  41. data/testdata/ast/optional-phrase.yaml +12 -0
  42. data/testdata/ast/optional.yaml +7 -0
  43. data/testdata/ast/parameter.yaml +7 -0
  44. data/testdata/ast/phrase.yaml +9 -0
  45. data/testdata/ast/unfinished-parameter.yaml +8 -0
  46. data/testdata/expression/allows-escaped-optional-parameter-types.yaml +4 -0
  47. data/testdata/expression/allows-parameter-type-in-alternation-1.yaml +4 -0
  48. data/testdata/expression/allows-parameter-type-in-alternation-2.yaml +4 -0
  49. data/testdata/expression/does-allow-parameter-adjacent-to-alternation.yaml +5 -0
  50. data/testdata/expression/does-not-allow-alternation-in-optional.yaml +9 -0
  51. data/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-left-parameter.yaml +10 -0
  52. data/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-optional.yaml +9 -0
  53. data/testdata/expression/does-not-allow-alternation-with-empty-alternative-by-adjacent-right-parameter.yaml +9 -0
  54. data/testdata/expression/does-not-allow-alternation-with-empty-alternative.yaml +9 -0
  55. data/testdata/expression/does-not-allow-empty-optional.yaml +9 -0
  56. data/testdata/expression/does-not-allow-nested-optional.yaml +8 -0
  57. data/testdata/expression/does-not-allow-optional-parameter-types.yaml +9 -0
  58. data/testdata/expression/does-not-allow-parameter-name-with-reserved-characters.yaml +10 -0
  59. data/testdata/expression/does-not-allow-unfinished-parenthesis-1.yaml +8 -0
  60. data/testdata/expression/does-not-allow-unfinished-parenthesis-2.yaml +8 -0
  61. data/testdata/expression/does-not-allow-unfinished-parenthesis-3.yaml +8 -0
  62. data/testdata/expression/does-not-match-misquoted-string.yaml +4 -0
  63. data/testdata/expression/doesnt-match-float-as-int.yaml +5 -0
  64. data/testdata/expression/matches-alternation.yaml +4 -0
  65. data/testdata/expression/matches-anonymous-parameter-type.yaml +5 -0
  66. data/testdata/expression/matches-double-quoted-empty-string-as-empty-string-along-with-other-strings.yaml +4 -0
  67. data/testdata/expression/matches-double-quoted-empty-string-as-empty-string.yaml +4 -0
  68. data/testdata/expression/matches-double-quoted-string-with-escaped-double-quote.yaml +4 -0
  69. data/testdata/expression/matches-double-quoted-string-with-single-quotes.yaml +4 -0
  70. data/testdata/expression/matches-double-quoted-string.yaml +4 -0
  71. data/testdata/expression/matches-doubly-escaped-parenthesis.yaml +4 -0
  72. data/testdata/expression/matches-doubly-escaped-slash-1.yaml +4 -0
  73. data/testdata/expression/matches-doubly-escaped-slash-2.yaml +4 -0
  74. data/testdata/expression/matches-escaped-parenthesis-1.yaml +4 -0
  75. data/testdata/expression/matches-escaped-parenthesis-2.yaml +4 -0
  76. data/testdata/expression/matches-escaped-parenthesis-3.yaml +4 -0
  77. data/testdata/expression/matches-escaped-slash.yaml +4 -0
  78. data/testdata/expression/matches-float-1.yaml +5 -0
  79. data/testdata/expression/matches-float-2.yaml +5 -0
  80. data/testdata/expression/matches-int.yaml +5 -0
  81. data/testdata/expression/matches-multiple-double-quoted-strings.yaml +4 -0
  82. data/testdata/expression/matches-multiple-single-quoted-strings.yaml +4 -0
  83. data/testdata/expression/matches-optional-before-alternation-1.yaml +4 -0
  84. data/testdata/expression/matches-optional-before-alternation-2.yaml +4 -0
  85. data/testdata/expression/matches-optional-before-alternation-with-regex-characters-1.yaml +4 -0
  86. data/testdata/expression/matches-optional-before-alternation-with-regex-characters-2.yaml +4 -0
  87. data/testdata/expression/matches-optional-in-alternation-1.yaml +5 -0
  88. data/testdata/expression/matches-optional-in-alternation-2.yaml +5 -0
  89. data/testdata/expression/matches-optional-in-alternation-3.yaml +5 -0
  90. data/testdata/expression/matches-single-quoted-empty-string-as-empty-string-along-with-other-strings.yaml +4 -0
  91. data/testdata/expression/matches-single-quoted-empty-string-as-empty-string.yaml +4 -0
  92. data/testdata/expression/matches-single-quoted-string-with-double-quotes.yaml +4 -0
  93. data/testdata/expression/matches-single-quoted-string-with-escaped-single-quote.yaml +4 -0
  94. data/testdata/expression/matches-single-quoted-string.yaml +4 -0
  95. data/testdata/expression/matches-word.yaml +4 -0
  96. data/testdata/expression/throws-unknown-parameter-type.yaml +10 -0
  97. data/testdata/regex/alternation-with-optional.yaml +2 -0
  98. data/testdata/regex/alternation.yaml +2 -0
  99. data/testdata/regex/empty.yaml +2 -0
  100. data/testdata/regex/escape-regex-characters.yaml +2 -0
  101. data/testdata/regex/optional.yaml +2 -0
  102. data/testdata/regex/parameter.yaml +2 -0
  103. data/testdata/regex/text.yaml +2 -0
  104. data/testdata/regex/unicode.yaml +2 -0
  105. data/testdata/tokens/alternation-phrase.yaml +13 -0
  106. data/testdata/tokens/alternation.yaml +9 -0
  107. data/testdata/tokens/empty-string.yaml +6 -0
  108. data/testdata/tokens/escape-non-reserved-character.yaml +8 -0
  109. data/testdata/tokens/escaped-alternation.yaml +9 -0
  110. data/testdata/tokens/escaped-char-has-start-index-of-text-token.yaml +9 -0
  111. data/testdata/tokens/escaped-end-of-line.yaml +8 -0
  112. data/testdata/tokens/escaped-optional.yaml +7 -0
  113. data/testdata/tokens/escaped-parameter.yaml +7 -0
  114. data/testdata/tokens/escaped-space.yaml +7 -0
  115. data/testdata/tokens/optional-phrase.yaml +13 -0
  116. data/testdata/tokens/optional.yaml +9 -0
  117. data/testdata/tokens/parameter-phrase.yaml +13 -0
  118. data/testdata/tokens/parameter.yaml +9 -0
  119. data/testdata/tokens/phrase.yaml +11 -0
  120. metadata +115 -9
  121. data/spec/cucumber/cucumber_expressions/cucumber_expression_regexp_spec.rb +0 -57
@@ -9,12 +9,16 @@ module Cucumber
9
9
  attr_reader :name, :type, :regexps
10
10
 
11
11
  def self.check_parameter_type_name(type_name)
12
+ unless is_valid_parameter_type_name(type_name)
13
+ raise CucumberExpressionError.new("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '[]()$.|?*+'")
14
+ end
15
+ end
16
+
17
+ def self.is_valid_parameter_type_name(type_name)
12
18
  unescaped_type_name = type_name.gsub(UNESCAPE_PATTERN) do
13
19
  $2
14
20
  end
15
- if ILLEGAL_PARAMETER_NAME_PATTERN =~ unescaped_type_name
16
- raise CucumberExpressionError.new("Illegal character '#{$1}' in parameter name {#{unescaped_type_name}}")
17
- end
21
+ !(ILLEGAL_PARAMETER_NAME_PATTERN =~ unescaped_type_name)
18
22
  end
19
23
 
20
24
  def prefer_for_regexp_match?
@@ -58,16 +62,17 @@ module Cucumber
58
62
 
59
63
  private
60
64
 
65
+
61
66
  def string_array(regexps)
62
67
  array = regexps.is_a?(Array) ? regexps : [regexps]
63
- array.map {|regexp| regexp.is_a?(String) ? regexp : regexp_source(regexp)}
68
+ array.map { |regexp| regexp.is_a?(String) ? regexp : regexp_source(regexp) }
64
69
  end
65
70
 
66
71
  def regexp_source(regexp)
67
72
  [
68
- 'EXTENDED',
69
- 'IGNORECASE',
70
- 'MULTILINE'
73
+ 'EXTENDED',
74
+ 'IGNORECASE',
75
+ 'MULTILINE'
71
76
  ].each do |option_name|
72
77
  option = Regexp.const_get(option_name)
73
78
  if regexp.options & option != 0
@@ -0,0 +1,24 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'cucumber/cucumber_expressions/cucumber_expression_parser'
4
+ require 'cucumber/cucumber_expressions/errors'
5
+
6
+ module Cucumber
7
+ module CucumberExpressions
8
+ describe 'Cucumber expression parser' do
9
+ Dir['testdata/ast/*.yaml'].each do |testcase|
10
+ expectation = YAML.load_file(testcase) # encoding?
11
+ it "#{testcase}" do
12
+ parser = CucumberExpressionParser.new
13
+ if expectation['exception'].nil?
14
+ node = parser.parse(expectation['expression'])
15
+ node_hash = node.to_hash
16
+ expect(node_hash).to eq(JSON.parse(expectation['expected']))
17
+ else
18
+ expect { parser.parse(expectation['expression']) }.to raise_error(expectation['exception'])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,9 +1,39 @@
1
+ require 'yaml'
2
+ require 'json'
1
3
  require 'cucumber/cucumber_expressions/cucumber_expression'
2
4
  require 'cucumber/cucumber_expressions/parameter_type_registry'
3
5
 
4
6
  module Cucumber
5
7
  module CucumberExpressions
6
8
  describe CucumberExpression do
9
+
10
+ Dir['testdata/expression/*.yaml'].each do |testcase|
11
+ expectation = YAML.load_file(testcase) # encoding?
12
+ it "#{testcase}" do
13
+ parameter_registry = ParameterTypeRegistry.new
14
+ if expectation['exception'].nil?
15
+ cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry)
16
+ matches = cucumber_expression.match(expectation['text'])
17
+ values = matches.nil? ? nil : matches.map { |arg| arg.value(nil) }
18
+ expect(values).to eq(JSON.parse(expectation['expected']))
19
+ else
20
+ expect {
21
+ cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry)
22
+ cucumber_expression.match(expectation['text'])
23
+ }.to raise_error(expectation['exception'])
24
+ end
25
+ end
26
+ end
27
+
28
+ Dir['testdata/regex/*.yaml'].each do |testcase|
29
+ expectation = YAML.load_file(testcase) # encoding?
30
+ it "#{testcase}" do
31
+ parameter_registry = ParameterTypeRegistry.new
32
+ cucumber_expression = CucumberExpression.new(expectation['expression'], parameter_registry)
33
+ expect(cucumber_expression.regexp.source).to eq(expectation['expected'])
34
+ end
35
+ end
36
+
7
37
  it "documents match arguments" do
8
38
  parameter_registry = ParameterTypeRegistry.new
9
39
 
@@ -15,82 +45,6 @@ module Cucumber
15
45
  ### [capture-match-arguments]
16
46
  end
17
47
 
18
- it "matches word" do
19
- expect(match("three {word} mice", "three blind mice")).to eq(['blind'])
20
- end
21
-
22
- it('matches double quoted string') do
23
- expect(match('three {string} mice', 'three "blind" mice')).to eq(['blind'])
24
- end
25
-
26
- it('matches multiple double quoted strings') do
27
- expect(match('three {string} and {string} mice', 'three "blind" and "crippled" mice')).to eq(['blind', 'crippled'])
28
- end
29
-
30
- it('matches single quoted string') do
31
- expect(match('three {string} mice', "three 'blind' mice")).to eq(['blind'])
32
- end
33
-
34
- it('matches multiple single quoted strings') do
35
- expect(match('three {string} and {string} mice', "three 'blind' and 'crippled' mice")).to eq(['blind', 'crippled'])
36
- end
37
-
38
- it('does not match misquoted string') do
39
- expect(match('three {string} mice', 'three "blind\' mice')).to eq(nil)
40
- end
41
-
42
- it('matches single quoted string with double quotes') do
43
- expect(match('three {string} mice', 'three \'"blind"\' mice')).to eq(['"blind"'])
44
- end
45
-
46
- it('matches double quoted string with single quotes') do
47
- expect(match('three {string} mice', 'three "\'blind\'" mice')).to eq(["'blind'"])
48
- end
49
-
50
- it('matches double quoted string with escaped double quote') do
51
- expect(match('three {string} mice', 'three "bl\\"nd" mice')).to eq(['bl"nd'])
52
- end
53
-
54
- it('matches single quoted string with escaped single quote') do
55
- expect(match('three {string} mice', "three 'bl\\'nd' mice")).to eq(["bl'nd"])
56
- end
57
-
58
- it('matches single quoted empty string as empty string') do
59
- expect(match('three {string} mice', "three '' mice")).to eq([''])
60
- end
61
-
62
- it('matches double quoted empty string as empty string') do
63
- expect(match('three {string} mice', 'three "" mice')).to eq([''])
64
- end
65
-
66
- it('matches single quoted empty string as empty string, along with other strings') do
67
- expect(match('three {string} and {string} mice', "three '' and 'handsome' mice")).to eq(['', 'handsome'])
68
- end
69
-
70
- it('matches double quoted empty string as empty string, along with other strings') do
71
- expect(match('three {string} and {string} mice', 'three "" and "handsome" mice')).to eq(['', 'handsome'])
72
- end
73
-
74
- it 'matches escaped parentheses' do
75
- expect(match('three \\(exceptionally) {string} mice', 'three (exceptionally) "blind" mice')).to eq(['blind'])
76
- end
77
-
78
- it "matches escaped slash" do
79
- expect(match("12\\/2020", "12/2020")).to eq([])
80
- end
81
-
82
- it "matches int" do
83
- expect(match("{int}", "22")).to eq([22])
84
- end
85
-
86
- it "doesn't match float as int" do
87
- expect(match("{int}", "1.22")).to be_nil
88
- end
89
-
90
- it "matches int as float" do
91
- expect(match("{float}", "0")).to eq([0.0])
92
- end
93
-
94
48
  it "matches float" do
95
49
  expect(match("{float}", "")).to eq(nil)
96
50
  expect(match("{float}", ".")).to eq(nil)
@@ -126,34 +80,12 @@ module Cucumber
126
80
  expect(match("{float}", "-.1E2")).to eq([-10])
127
81
  end
128
82
 
129
- it "matches anonymous" do
130
- expect(match("{}", "0.22")).to eq(["0.22"])
131
- end
132
-
133
- '[]()$.|?*+'.split('').each do |char|
134
- it "does not allow parameter type with #{char}" do
135
- expect {match("{#{char}string}", "something")}.to raise_error("Illegal character '#{char}' in parameter name {#{char}string}")
136
- end
137
- end
138
-
139
- it "throws unknown parameter type" do
140
- expect {match("{unknown}", "something")}.to raise_error('Undefined parameter type {unknown}')
141
- end
142
-
143
- it "does not allow optional parameter types" do
144
- expect {match("({int})", "3")}.to raise_error('Parameter types cannot be optional: ({int})')
145
- end
146
-
147
- it "does allow escaped optional parameter types" do
148
- expect(match("\\({int})", "(3)")).to eq([3])
149
- end
150
-
151
- it "does not allow text/parameter type alternation" do
152
- expect {match("x/{int}", "3")}.to raise_error('Parameter types cannot be alternative: x/{int}')
83
+ it "float with zero" do
84
+ expect(match("{float}", "0")).to eq([0.0])
153
85
  end
154
86
 
155
- it "does not allow parameter type/text alternation" do
156
- expect {match("{int}/x", "3")}.to raise_error('Parameter types cannot be alternative: {int}/x')
87
+ it "matches anonymous" do
88
+ expect(match("{}", "0.22")).to eq(["0.22"])
157
89
  end
158
90
 
159
91
  it "exposes source" do
@@ -161,78 +93,68 @@ module Cucumber
161
93
  expect(CucumberExpression.new(expr, ParameterTypeRegistry.new).source).to eq(expr)
162
94
  end
163
95
 
164
- it "delegates transform to custom object" do
96
+ it "unmatched optional groups have undefined values" do
165
97
  parameter_type_registry = ParameterTypeRegistry.new
166
98
  parameter_type_registry.define_parameter_type(
167
- ParameterType.new(
168
- 'widget',
169
- /\w+/,
170
- Object,
171
- -> (s) {
172
- self.create_widget(s)
173
- },
174
- false,
175
- true
176
- )
99
+ ParameterType.new(
100
+ 'textAndOrNumber',
101
+ /([A-Z]+)?(?: )?([0-9]+)?/,
102
+ Object,
103
+ -> (s1, s2) {
104
+ [s1, s2]
105
+ },
106
+ false,
107
+ true
108
+ )
177
109
  )
178
110
  expression = CucumberExpression.new(
179
- 'I have a {widget}',
180
- parameter_type_registry
111
+ '{textAndOrNumber}',
112
+ parameter_type_registry
181
113
  )
182
114
 
183
115
  class World
184
- def create_widget(s)
185
- "widget:#{s}"
186
- end
187
116
  end
188
117
 
189
- args = expression.match("I have a bolt")
190
- expect(args[0].value(World.new)).to eq('widget:bolt')
191
- end
192
-
193
- describe "escapes special characters" do
194
- %w(\\ [ ] ^ $ . | ? * +).each do |character|
195
- it "escapes #{character}" do
196
- expr = "I have {int} cuke(s) and #{character}"
197
- expression = CucumberExpression.new(expr, ParameterTypeRegistry.new)
198
- arg1 = expression.match("I have 800 cukes and #{character}")[0]
199
- expect(arg1.value(nil)).to eq(800)
200
- end
201
- end
118
+ expect(expression.match("TLA")[0].value(World.new)).to eq(["TLA", nil])
119
+ expect(expression.match("123")[0].value(World.new)).to eq([nil, "123"])
202
120
  end
203
121
 
122
+ # Ruby specific
204
123
 
205
- it "unmatched optional groups have undefined values" do
124
+ it "delegates transform to custom object" do
206
125
  parameter_type_registry = ParameterTypeRegistry.new
207
126
  parameter_type_registry.define_parameter_type(
208
127
  ParameterType.new(
209
- 'textAndOrNumber',
210
- /([A-Z]+)?(?: )?([0-9]+)?/,
128
+ 'widget',
129
+ /\w+/,
211
130
  Object,
212
- -> (s1, s2) {
213
- [s1, s2]
131
+ -> (s) {
132
+ self.create_widget(s)
214
133
  },
215
134
  false,
216
135
  true
217
136
  )
218
137
  )
219
138
  expression = CucumberExpression.new(
220
- '{textAndOrNumber}',
139
+ 'I have a {widget}',
221
140
  parameter_type_registry
222
141
  )
223
142
 
224
143
  class World
144
+ def create_widget(s)
145
+ "widget:#{s}"
146
+ end
225
147
  end
226
148
 
227
- expect(expression.match("TLA")[0].value(World.new)).to eq(["TLA", nil])
228
- expect(expression.match("123")[0].value(World.new)).to eq([nil, "123"])
149
+ args = expression.match("I have a bolt")
150
+ expect(args[0].value(World.new)).to eq('widget:bolt')
229
151
  end
230
152
 
231
153
  def match(expression, text)
232
154
  cucumber_expression = CucumberExpression.new(expression, ParameterTypeRegistry.new)
233
155
  args = cucumber_expression.match(text)
234
156
  return nil if args.nil?
235
- args.map {|arg| arg.value(nil)}
157
+ args.map { |arg| arg.value(nil) }
236
158
  end
237
159
  end
238
160
  end
@@ -0,0 +1,24 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'cucumber/cucumber_expressions/cucumber_expression_tokenizer'
4
+ require 'cucumber/cucumber_expressions/errors'
5
+
6
+ module Cucumber
7
+ module CucumberExpressions
8
+ describe 'Cucumber expression tokenizer' do
9
+ Dir['testdata/tokens/*.yaml'].each do |testcase|
10
+ expectation = YAML.load_file(testcase) # encoding?
11
+ it "#{testcase}" do
12
+ tokenizer = CucumberExpressionTokenizer.new
13
+ if expectation['exception'].nil?
14
+ tokens = tokenizer.tokenize(expectation['expression'])
15
+ token_hashes = tokens.map{|token| token.to_hash}
16
+ expect(token_hashes).to eq(JSON.parse(expectation['expected']))
17
+ else
18
+ expect { tokenizer.tokenize(expectation['expression']) }.to raise_error(expectation['exception'])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -69,7 +69,7 @@ module Cucumber
69
69
  true,
70
70
  false
71
71
  )
72
- end.to raise_error("Illegal character '[' in parameter name {[string]}")
72
+ end.to raise_error("Illegal character in parameter name {[string]}. Parameter names may not contain '[]()$.|?*+'")
73
73
  end
74
74
 
75
75
  describe CucumberExpression do
@@ -7,7 +7,7 @@ module Cucumber
7
7
  module CucumberExpressions
8
8
  describe 'examples.txt' do
9
9
  def match(expression_text, text)
10
- expression = expression_text =~ /\/(.*)\// ?
10
+ expression = expression_text =~ /^\/(.*)\/$/ ?
11
11
  RegularExpression.new(Regexp.new($1), ParameterTypeRegistry.new) :
12
12
  CucumberExpression.new(expression_text, ParameterTypeRegistry.new)
13
13
 
@@ -14,10 +14,6 @@ module Cucumber
14
14
  it 'creates a CucumberExpression' do
15
15
  expect(@expression_factory.create_expression('{int}').class).to eq(CucumberExpression)
16
16
  end
17
-
18
- it 'creates a XXXRegularExpression' do
19
- expect {@expression_factory.create_expression('hello {x}')}.to raise_error("Undefined parameter type {x}")
20
- end
21
17
  end
22
18
  end
23
19
  end
@@ -0,0 +1,17 @@
1
+ expression: three blind\ rat/cat(s)
2
+ expected: |-
3
+ {"type": "EXPRESSION_NODE", "start": 0, "end": 23, "nodes": [
4
+ {"type": "TEXT_NODE", "start": 0, "end": 5, "token": "three"},
5
+ {"type": "TEXT_NODE", "start": 5, "end": 6, "token": " "},
6
+ {"type": "ALTERNATION_NODE", "start": 6, "end": 23, "nodes": [
7
+ {"type": "ALTERNATIVE_NODE", "start": 6, "end": 16, "nodes": [
8
+ {"type": "TEXT_NODE", "start": 6, "end": 16, "token": "blind rat"}
9
+ ]},
10
+ {"type": "ALTERNATIVE_NODE", "start": 17, "end": 23, "nodes": [
11
+ {"type": "TEXT_NODE", "start": 17, "end": 20, "token": "cat"},
12
+ {"type": "OPTIONAL_NODE", "start": 20, "end": 23, "nodes": [
13
+ {"type": "TEXT_NODE", "start": 21, "end": 22, "token": "s"}
14
+ ]}
15
+ ]}
16
+ ]}
17
+ ]}
@@ -0,0 +1,16 @@
1
+ expression: three hungry/blind mice
2
+ expected: |-
3
+ {"type": "EXPRESSION_NODE", "start": 0, "end": 23, "nodes": [
4
+ {"type": "TEXT_NODE", "start": 0, "end": 5, "token": "three"},
5
+ {"type": "TEXT_NODE", "start": 5, "end": 6, "token": " "},
6
+ {"type": "ALTERNATION_NODE", "start": 6, "end": 18, "nodes": [
7
+ {"type": "ALTERNATIVE_NODE", "start": 6, "end": 12, "nodes": [
8
+ {"type": "TEXT_NODE", "start": 6, "end": 12, "token": "hungry"}
9
+ ]},
10
+ {"type": "ALTERNATIVE_NODE", "start": 13, "end": 18, "nodes": [
11
+ {"type": "TEXT_NODE", "start": 13, "end": 18, "token": "blind"}
12
+ ]}
13
+ ]},
14
+ {"type": "TEXT_NODE", "start": 18, "end": 19, "token": " "},
15
+ {"type": "TEXT_NODE", "start": 19, "end": 23, "token": "mice"}
16
+ ]}
@@ -0,0 +1,27 @@
1
+ expression: I select the {int}st/nd/rd/th
2
+ expected: |-
3
+ {"type": "EXPRESSION_NODE", "start": 0, "end": 29, "nodes": [
4
+ {"type": "TEXT_NODE", "start": 0, "end": 1, "token": "I"},
5
+ {"type": "TEXT_NODE", "start": 1, "end": 2, "token": " "},
6
+ {"type": "TEXT_NODE", "start": 2, "end": 8, "token": "select"},
7
+ {"type": "TEXT_NODE", "start": 8, "end": 9, "token": " "},
8
+ {"type": "TEXT_NODE", "start": 9, "end": 12, "token": "the"},
9
+ {"type": "TEXT_NODE", "start": 12, "end": 13, "token": " "},
10
+ {"type": "PARAMETER_NODE", "start": 13, "end": 18, "nodes": [
11
+ {"type": "TEXT_NODE", "start": 14, "end": 17, "token": "int"}
12
+ ]},
13
+ {"type": "ALTERNATION_NODE", "start": 18, "end": 29, "nodes": [
14
+ {"type": "ALTERNATIVE_NODE", "start": 18, "end": 20, "nodes": [
15
+ {"type": "TEXT_NODE", "start": 18, "end": 20, "token": "st"}
16
+ ]},
17
+ {"type": "ALTERNATIVE_NODE", "start": 21, "end": 23, "nodes": [
18
+ {"type": "TEXT_NODE", "start": 21, "end": 23, "token": "nd"}
19
+ ]},
20
+ {"type": "ALTERNATIVE_NODE", "start": 24, "end": 26, "nodes": [
21
+ {"type": "TEXT_NODE", "start": 24, "end": 26, "token": "rd"}
22
+ ]},
23
+ {"type": "ALTERNATIVE_NODE", "start": 27, "end": 29, "nodes": [
24
+ {"type": "TEXT_NODE", "start": 27, "end": 29, "token": "th"}
25
+ ]}
26
+ ]}
27
+ ]}