cucumber-cucumber-expressions 17.1.0 → 18.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.
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cucumber/cucumber_expressions/argument'
4
- require 'cucumber/cucumber_expressions/tree_regexp'
5
- require 'cucumber/cucumber_expressions/parameter_type_registry'
6
-
7
- module Cucumber
8
- module CucumberExpressions
9
- describe Argument do
10
- it 'exposes parameter_type' do
11
- tree_regexp = TreeRegexp.new(/three (.*) mice/)
12
- parameter_type_registry = ParameterTypeRegistry.new
13
- arguments = described_class.build(tree_regexp, 'three blind mice', [parameter_type_registry.lookup_by_type_name('string')])
14
- argument = arguments[0]
15
- expect(argument.parameter_type.name).to eq('string')
16
- end
17
- end
18
- end
19
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cucumber/cucumber_expressions/parameter_type'
4
- require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory'
5
-
6
- describe Cucumber::CucumberExpressions::CombinatorialGeneratedExpressionFactory do
7
- let(:klazz) { Class.new }
8
- let(:color_parameter_type) do
9
- Cucumber::CucumberExpressions::ParameterType.new('color', /red|blue|yellow/, klazz, ->(_) { klazz.new }, true, false)
10
- end
11
- let(:css_color_parameter_type) do
12
- Cucumber::CucumberExpressions::ParameterType.new('csscolor', /red|blue|yellow/, klazz, ->(_) { klazz.new }, true, false)
13
- end
14
- let(:date_parameter_type) do
15
- Cucumber::CucumberExpressions::ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, klazz, ->(_) { klazz.new }, true, false)
16
- end
17
- let(:date_time_parameter_type) do
18
- Cucumber::CucumberExpressions::ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, klazz, ->(_) { klazz.new }, true, false)
19
- end
20
- let(:timestamp_parameter_type) do
21
- Cucumber::CucumberExpressions::ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, klazz, ->(_) { klazz.new }, true, false)
22
- end
23
-
24
- it 'generates multiple expressions' do
25
- parameter_type_combinations = [
26
- [color_parameter_type, css_color_parameter_type],
27
- [date_parameter_type, date_time_parameter_type, timestamp_parameter_type]
28
- ]
29
-
30
- factory = described_class.new('I bought a {%s} ball on {%s}', parameter_type_combinations)
31
- expressions = factory.generate_expressions.map { |generated_expression| generated_expression.source }
32
- expect(expressions).to eq([
33
- 'I bought a {color} ball on {date}',
34
- 'I bought a {color} ball on {datetime}',
35
- 'I bought a {color} ball on {timestamp}',
36
- 'I bought a {csscolor} ball on {date}',
37
- 'I bought a {csscolor} ball on {datetime}',
38
- 'I bought a {csscolor} ball on {timestamp}',
39
- ])
40
- end
41
- end
@@ -1,234 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cucumber/cucumber_expressions/cucumber_expression_generator'
4
- require 'cucumber/cucumber_expressions/cucumber_expression'
5
- require 'cucumber/cucumber_expressions/parameter_type'
6
- require 'cucumber/cucumber_expressions/parameter_type_registry'
7
-
8
- module Cucumber
9
- module CucumberExpressions
10
- describe CucumberExpressionGenerator do
11
- class Currency
12
- end
13
-
14
- before do
15
- @parameter_type_registry = ParameterTypeRegistry.new
16
- @generator = described_class.new(@parameter_type_registry)
17
- end
18
-
19
- it 'documents expression generation' do
20
- parameter_registry = ParameterTypeRegistry.new
21
- ### [generate-expression]
22
- generator = described_class.new(parameter_registry)
23
- undefined_step_text = 'I have 2 cucumbers and 1.5 tomato'
24
- generated_expression = generator.generate_expressions(undefined_step_text)[0]
25
- expect(generated_expression.source).to eq('I have {int} cucumbers and {float} tomato')
26
- expect(generated_expression.parameter_types[1].type).to eq(Float)
27
- ### [generate-expression]
28
- end
29
-
30
- it 'generates expression for no args' do
31
- assert_expression('hello', [], 'hello')
32
- end
33
-
34
- it 'generates expression with escaped left parenthesis' do
35
- assert_expression('\\(iii)', [], '(iii)')
36
- end
37
-
38
- it 'generates expression with escaped left curly brace' do
39
- assert_expression('\\{iii}', [], '{iii}')
40
- end
41
-
42
- it 'generates expression with escaped slashes' do
43
- assert_expression('The {int}\\/{int}\\/{int} hey', ['int', 'int2', 'int3'], 'The 1814/05/17 hey')
44
- end
45
-
46
- it 'generates expression for int float arg' do
47
- assert_expression('I have {int} cukes and {float} euro', ['int', 'float'], 'I have 2 cukes and 1.5 euro')
48
- end
49
-
50
- it 'generates expression for strings' do
51
- assert_expression('I like {string} and {string}', ['string', 'string2'], 'I like "bangers" and \'mash\'')
52
- end
53
-
54
- it 'generates expression with % sign' do
55
- assert_expression('I am {int}% foobar', ['int'], 'I am 20% foobar')
56
- end
57
-
58
- it 'generates expression for just int' do
59
- assert_expression('{int}', ['int'], '99999')
60
- end
61
-
62
- it 'numbers only second argument when builtin type is not reserved keyword' do
63
- assert_expression('I have {int} cukes and {int} euro', ['int', 'int2'], 'I have 2 cukes and 5 euro')
64
- end
65
-
66
- it 'numbers only second argument when type is not reserved keyword' do
67
- @parameter_type_registry.define_parameter_type(
68
- ParameterType.new(
69
- 'currency',
70
- '[A-Z]{3}',
71
- Currency,
72
- ->(s) { Currency.new(s) },
73
- true,
74
- true
75
- )
76
- )
77
-
78
- assert_expression('I have a {currency} account and a {currency} account', ['currency', 'currency2'], 'I have a EUR account and a GBP account')
79
- end
80
-
81
- it 'exposes parameters in a generated expression' do
82
- expression = @generator.generate_expressions('I have 2 cukes and 1.5 euro')[0]
83
- types = expression.parameter_types.map(&:type)
84
-
85
- expect(types).to eq([Integer, Float])
86
- end
87
-
88
- it 'matches parameter types with optional capture groups' do
89
- @parameter_type_registry.define_parameter_type(
90
- ParameterType.new(
91
- 'optional-flight',
92
- /(1st flight)?/,
93
- String,
94
- ->(s) { s },
95
- true,
96
- false
97
- )
98
- )
99
- @parameter_type_registry.define_parameter_type(
100
- ParameterType.new(
101
- 'optional-hotel',
102
- /(1 hotel)?/,
103
- String,
104
- ->(s) { s },
105
- true,
106
- false
107
- )
108
- )
109
-
110
- expression = @generator.generate_expressions('I reach Stage 4: 1st flight -1 hotel')[0]
111
- # While you would expect this to be `I reach Stage {int}: {optional-flight} -{optional-hotel}`
112
- # the `-1` causes {int} to match just before {optional-hotel}.
113
-
114
- expect(expression.source).to eq('I reach Stage {int}: {optional-flight} {int} hotel')
115
- end
116
-
117
- it 'generates at most 256 expressions' do
118
- for i in 0..3
119
- @parameter_type_registry.define_parameter_type(
120
- ParameterType.new(
121
- "my-type-#{i}",
122
- /([a-z] )*?[a-z]/,
123
- String,
124
- ->(s) { s },
125
- true,
126
- false
127
- )
128
- )
129
- end
130
- # This would otherwise generate 4^11=4194300 expressions and consume just shy of 1.5GB.
131
- expressions = @generator.generate_expressions('a s i m p l e s t e p')
132
-
133
- expect(expressions.length).to eq(256)
134
- end
135
-
136
- it 'prefers expression with longest non empty match' do
137
- @parameter_type_registry.define_parameter_type(
138
- ParameterType.new(
139
- 'zero-or-more',
140
- /[a-z]*/,
141
- String,
142
- ->(s) { s },
143
- true,
144
- false
145
- )
146
- )
147
- @parameter_type_registry.define_parameter_type(
148
- ParameterType.new(
149
- 'exactly-one',
150
- /[a-z]/,
151
- String,
152
- ->(s) { s },
153
- true,
154
- false
155
- )
156
- )
157
- expressions = @generator.generate_expressions('a simple step')
158
-
159
- expect(expressions.length).to eq(2)
160
- expect(expressions[0].source).to eq('{exactly-one} {zero-or-more} {zero-or-more}')
161
- expect(expressions[1].source).to eq('{zero-or-more} {zero-or-more} {zero-or-more}')
162
- end
163
-
164
- context 'does not suggest parameter when match is' do
165
- before do
166
- @parameter_type_registry.define_parameter_type(
167
- ParameterType.new(
168
- 'direction',
169
- /(up|down)/,
170
- String,
171
- ->(s) { s },
172
- true,
173
- false
174
- )
175
- )
176
- end
177
-
178
- it 'at the beginning of a word' do
179
- expect(@generator.generate_expressions('When I download a picture')[0].source).not_to eq('When I {direction}load a picture')
180
- expect(@generator.generate_expressions('When I download a picture')[0].source).to eq('When I download a picture')
181
- end
182
-
183
- it 'inside a word' do
184
- expect(@generator.generate_expressions('When I watch the muppet show')[0].source).not_to eq('When I watch the m{direction}pet show')
185
- expect(@generator.generate_expressions('When I watch the muppet show')[0].source).to eq('When I watch the muppet show')
186
- end
187
-
188
- it 'at the end of a word' do
189
- expect(@generator.generate_expressions('When I create a group')[0].source).not_to eq('When I create a gro{direction}')
190
- expect(@generator.generate_expressions('When I create a group')[0].source).to eq('When I create a group')
191
- end
192
- end
193
-
194
- context 'does suggest parameter when match is' do
195
- before do
196
- @parameter_type_registry.define_parameter_type(
197
- ParameterType.new(
198
- 'direction',
199
- /(up|down)/,
200
- String,
201
- ->(s) { s },
202
- true,
203
- false
204
- )
205
- )
206
- end
207
-
208
- it 'a full word' do
209
- expect(@generator.generate_expressions('When I go down the road')[0].source).to eq('When I go {direction} the road')
210
- expect(@generator.generate_expressions('When I walk up the hill')[0].source).to eq('When I walk {direction} the hill')
211
- expect(@generator.generate_expressions('up the hill, the road goes down')[0].source).to eq('{direction} the hill, the road goes {direction}')
212
- end
213
-
214
- it 'wrapped around punctuation characters' do
215
- expect(@generator.generate_expressions('When direction is:down')[0].source).to eq('When direction is:{direction}')
216
- expect(@generator.generate_expressions('Then direction is down.')[0].source).to eq('Then direction is {direction}.')
217
- end
218
- end
219
-
220
- def assert_expression(expected_expression, expected_argument_names, text)
221
- generated_expression = @generator.generate_expressions(text)[0]
222
- expect(generated_expression.parameter_names).to eq(expected_argument_names)
223
- expect(generated_expression.source).to eq(expected_expression)
224
-
225
- cucumber_expression = CucumberExpression.new(generated_expression.source, @parameter_type_registry)
226
- match = cucumber_expression.match(text)
227
-
228
- raise "Expected text '#{text}' to match generated expression '#{generated_expression.source}'" if match.nil?
229
-
230
- expect(match.length).to eq(expected_argument_names.length)
231
- end
232
- end
233
- end
234
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
- require 'cucumber/cucumber_expressions/cucumber_expression_parser'
5
- require 'cucumber/cucumber_expressions/errors'
6
-
7
- module Cucumber
8
- module CucumberExpressions
9
- describe CucumberExpressionParser do
10
- Dir['../testdata/cucumber-expression/parser/*.yaml'].each do |path|
11
- expectation = YAML.load_file(path)
12
- it "parses #{path}" do
13
- parser = described_class.new
14
- if expectation['exception']
15
- expect { parser.parse(expectation['expression']) }.to raise_error(expectation['exception'])
16
- else
17
- node = parser.parse(expectation['expression'])
18
- node_hash = node.to_hash
19
- expect(node_hash).to eq(expectation['expected_ast'])
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,178 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
- require 'cucumber/cucumber_expressions/cucumber_expression'
5
- require 'cucumber/cucumber_expressions/parameter_type_registry'
6
-
7
- module Cucumber
8
- module CucumberExpressions
9
- describe CucumberExpression do
10
- Dir['../testdata/cucumber-expression/matching/*.yaml'].each do |path|
11
- expectation = YAML.load_file(path)
12
-
13
- it "matches #{path}" do
14
- parameter_registry = ParameterTypeRegistry.new
15
- if expectation['exception']
16
- expect {
17
- cucumber_expression = described_class.new(expectation['expression'], parameter_registry)
18
- cucumber_expression.match(expectation['text'])
19
- }.to raise_error(expectation['exception'])
20
- else
21
- cucumber_expression = described_class.new(expectation['expression'], parameter_registry)
22
- matches = cucumber_expression.match(expectation['text'])
23
- values = matches.nil? ? nil : matches.map do |arg|
24
- value = arg.value(nil)
25
- case value
26
- when BigDecimal
27
- # Format {bigdecimal} as string (because it must be a string in matches-bigdecimal.yaml)
28
- value.to_s('f')
29
- when Integer
30
- # Format {bigint} as string (because it must be a string in matches-bigint.yaml)
31
- value.bit_length > 64 ? value.to_s : value
32
- else
33
- value
34
- end
35
- end
36
- expect(values).to eq(expectation['expected_args'])
37
- end
38
- end
39
- end
40
-
41
- it 'documents match arguments' do
42
- parameter_registry = ParameterTypeRegistry.new
43
-
44
- ### [capture-match-arguments]
45
- expr = 'I have {int} cuke(s)'
46
- expression = described_class.new(expr, parameter_registry)
47
- args = expression.match('I have 7 cukes')
48
-
49
- expect(args[0].value(nil)).to eq(7)
50
- ### [capture-match-arguments]
51
- end
52
-
53
- it 'matches float' do
54
- expect(match('{float}', '')).to eq(nil)
55
- expect(match('{float}', '.')).to eq(nil)
56
- expect(match('{float}', ',')).to eq(nil)
57
- expect(match('{float}', '-')).to eq(nil)
58
- expect(match('{float}', 'E')).to eq(nil)
59
- expect(match('{float}', '1,')).to eq(nil)
60
- expect(match('{float}', ',1')).to eq(nil)
61
- expect(match('{float}', '1.')).to eq(nil)
62
-
63
- expect(match('{float}', '1')).to eq([1])
64
- expect(match('{float}', '-1')).to eq([-1])
65
- expect(match('{float}', '1.1')).to eq([1.1])
66
- expect(match('{float}', '1,000')).to eq(nil)
67
- expect(match('{float}', '1,000,0')).to eq(nil)
68
- expect(match('{float}', '1,000.1')).to eq(nil)
69
- expect(match('{float}', '1,000,10')).to eq(nil)
70
- expect(match('{float}', '1,0.1')).to eq(nil)
71
- expect(match('{float}', '1,000,000.1')).to eq(nil)
72
- expect(match('{float}', '-1.1')).to eq([-1.1])
73
-
74
- expect(match('{float}', '.1')).to eq([0.1])
75
- expect(match('{float}', '-.1')).to eq([-0.1])
76
- expect(match('{float}', '-.1000001')).to eq([-0.1000001])
77
- expect(match('{float}', '1E1')).to eq([10.0])
78
- expect(match('{float}', '.1E1')).to eq([1])
79
- expect(match('{float}', 'E1')).to eq(nil)
80
- expect(match('{float}', '-.1E-1')).to eq([-0.01])
81
- expect(match('{float}', '-.1E-2')).to eq([-0.001])
82
- expect(match('{float}', '-.1E+1')).to eq([-1])
83
- expect(match('{float}', '-.1E+2')).to eq([-10])
84
- expect(match('{float}', '-.1E1')).to eq([-1])
85
- expect(match('{float}', '-.1E2')).to eq([-10])
86
- end
87
-
88
- it 'float with zero' do
89
- expect(match('{float}', '0')).to eq([0.0])
90
- end
91
-
92
- it 'matches anonymous' do
93
- expect(match('{}', '0.22')).to eq(['0.22'])
94
- end
95
-
96
- it 'exposes source' do
97
- expr = 'I have {int} cuke(s)'
98
-
99
- expect(described_class.new(expr, ParameterTypeRegistry.new).source).to eq(expr)
100
- end
101
-
102
- it 'exposes source via #to_s' do
103
- expr = 'I have {int} cuke(s)'
104
-
105
- expect(described_class.new(expr, ParameterTypeRegistry.new).to_s).to eq(expr.inspect)
106
- end
107
-
108
- it 'unmatched optional groups have undefined values' do
109
- parameter_type_registry = ParameterTypeRegistry.new
110
- parameter_type_registry.define_parameter_type(
111
- ParameterType.new(
112
- 'textAndOrNumber',
113
- /([A-Z]+)?(?: )?([0-9]+)?/,
114
- Object,
115
- ->(s1, s2) { [s1, s2] },
116
- false,
117
- true
118
- )
119
- )
120
- expression = described_class.new('{textAndOrNumber}', parameter_type_registry)
121
-
122
- class World; end
123
-
124
- expect(expression.match('TLA')[0].value(World.new)).to eq(['TLA', nil])
125
- expect(expression.match('123')[0].value(World.new)).to eq([nil, '123'])
126
- end
127
-
128
- # Ruby specific
129
-
130
- it 'delegates transform to custom object' do
131
- parameter_type_registry = ParameterTypeRegistry.new
132
- parameter_type_registry.define_parameter_type(
133
- ParameterType.new(
134
- 'widget',
135
- /\w+/,
136
- Object,
137
- ->(s) { self.create_widget(s) },
138
- false,
139
- true
140
- )
141
- )
142
- expression = described_class.new(
143
- 'I have a {widget}',
144
- parameter_type_registry
145
- )
146
-
147
- class World
148
- def create_widget(s)
149
- "widget:#{s}"
150
- end
151
- end
152
-
153
- args = expression.match('I have a bolt')
154
-
155
- expect(args[0].value(World.new)).to eq('widget:bolt')
156
- end
157
-
158
- it 'reports undefined parameter type name' do
159
- parameter_type_registry = ParameterTypeRegistry.new
160
-
161
- described_class.new(
162
- 'I have {int} {widget}(s) in {word}',
163
- parameter_type_registry
164
- )
165
- rescue UndefinedParameterTypeError => e
166
- expect(e.undefined_parameter_type_name).to eq('widget')
167
- end
168
-
169
- def match(expression, text)
170
- cucumber_expression = CucumberExpression.new(expression, ParameterTypeRegistry.new)
171
- args = cucumber_expression.match(text)
172
- return nil if args.nil?
173
-
174
- args.map { |arg| arg.value(nil) }
175
- end
176
- end
177
- end
178
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
- require 'cucumber/cucumber_expressions/cucumber_expression_tokenizer'
5
- require 'cucumber/cucumber_expressions/errors'
6
-
7
- module Cucumber
8
- module CucumberExpressions
9
- describe CucumberExpressionTokenizer do
10
- Dir['../testdata/cucumber-expression/tokenizer/*.yaml'].each do |path|
11
- expectation = YAML.load_file(path)
12
- it "tokenizes #{path}" do
13
- tokenizer = described_class.new
14
- if expectation['exception']
15
- expect { tokenizer.tokenize(expectation['expression']) }.to raise_error(expectation['exception'])
16
- else
17
- tokens = tokenizer.tokenize(expectation['expression'])
18
- token_hashes = tokens.map { |token| token.to_hash }
19
- expect(token_hashes).to eq(expectation['expected_tokens'])
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
- require 'cucumber/cucumber_expressions/cucumber_expression'
5
- require 'cucumber/cucumber_expressions/parameter_type_registry'
6
-
7
- module Cucumber
8
- module CucumberExpressions
9
- describe CucumberExpression do
10
- Dir['../testdata/cucumber-expression/transformation/*.yaml'].each do |path|
11
- expectation = YAML.load_file(path)
12
- it "transforms #{path}" do
13
- parameter_registry = ParameterTypeRegistry.new
14
- if expectation['exception']
15
- expect {
16
- cucumber_expression = described_class.new(expectation['expression'], parameter_registry)
17
- cucumber_expression.match(expectation['text'])
18
- }.to raise_error(expectation['exception'])
19
- else
20
- cucumber_expression = described_class.new(expectation['expression'], parameter_registry)
21
- matches = cucumber_expression.match(expectation['text'])
22
- values = matches.nil? ? nil : matches.map { |arg| arg.value(nil) }
23
- expect(values).to eq(expectation['expected_args'])
24
- end
25
- end
26
- end
27
- end
28
- end
29
- end