cucumber-cucumber-expressions 8.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE.md +5 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +5 -0
- data/.rspec +1 -0
- data/.rsync +4 -0
- data/.subrepo +1 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/Makefile +1 -0
- data/README.md +5 -0
- data/Rakefile +27 -0
- data/cucumber-cucumber-expressions.gemspec +33 -0
- data/default.mk +70 -0
- data/examples.txt +31 -0
- data/lib/cucumber/cucumber_expressions/argument.rb +37 -0
- data/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb +49 -0
- data/lib/cucumber/cucumber_expressions/cucumber_expression.rb +119 -0
- data/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb +105 -0
- data/lib/cucumber/cucumber_expressions/errors.rb +40 -0
- data/lib/cucumber/cucumber_expressions/generated_expression.rb +31 -0
- data/lib/cucumber/cucumber_expressions/group.rb +18 -0
- data/lib/cucumber/cucumber_expressions/group_builder.rb +42 -0
- data/lib/cucumber/cucumber_expressions/parameter_type.rb +81 -0
- data/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb +59 -0
- data/lib/cucumber/cucumber_expressions/parameter_type_registry.rb +70 -0
- data/lib/cucumber/cucumber_expressions/regular_expression.rb +48 -0
- data/lib/cucumber/cucumber_expressions/tree_regexp.rb +76 -0
- data/scripts/update-gemspec +32 -0
- data/spec/capture_warnings.rb +74 -0
- data/spec/coverage.rb +7 -0
- data/spec/cucumber/cucumber_expressions/argument_spec.rb +17 -0
- data/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb +43 -0
- data/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb +231 -0
- data/spec/cucumber/cucumber_expressions/cucumber_expression_regexp_spec.rb +57 -0
- data/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +212 -0
- data/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +202 -0
- data/spec/cucumber/cucumber_expressions/expression_examples_spec.rb +30 -0
- data/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb +86 -0
- data/spec/cucumber/cucumber_expressions/parameter_type_spec.rb +15 -0
- data/spec/cucumber/cucumber_expressions/regular_expression_spec.rb +80 -0
- data/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb +133 -0
- metadata +162 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'cucumber/cucumber_expressions/argument'
|
2
|
+
require 'cucumber/cucumber_expressions/parameter_type'
|
3
|
+
require 'cucumber/cucumber_expressions/tree_regexp'
|
4
|
+
|
5
|
+
module Cucumber
|
6
|
+
module CucumberExpressions
|
7
|
+
class RegularExpression
|
8
|
+
|
9
|
+
def initialize(expression_regexp, parameter_type_registry)
|
10
|
+
@expression_regexp = expression_regexp
|
11
|
+
@parameter_type_registry = parameter_type_registry
|
12
|
+
@tree_regexp = TreeRegexp.new(@expression_regexp)
|
13
|
+
end
|
14
|
+
|
15
|
+
def match(text)
|
16
|
+
parameter_types = @tree_regexp.group_builder.children.map do |group_builder|
|
17
|
+
parameter_type_regexp = group_builder.source
|
18
|
+
@parameter_type_registry.lookup_by_regexp(
|
19
|
+
parameter_type_regexp,
|
20
|
+
@expression_regexp,
|
21
|
+
text
|
22
|
+
) || ParameterType.new(
|
23
|
+
nil,
|
24
|
+
parameter_type_regexp,
|
25
|
+
String,
|
26
|
+
lambda {|*s| s[0]},
|
27
|
+
false,
|
28
|
+
false
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
Argument.build(@tree_regexp, text, parameter_types)
|
33
|
+
end
|
34
|
+
|
35
|
+
def regexp
|
36
|
+
@expression_regexp
|
37
|
+
end
|
38
|
+
|
39
|
+
def source
|
40
|
+
@expression_regexp.source
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
regexp.inspect
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'cucumber/cucumber_expressions/group_builder'
|
2
|
+
require 'cucumber/cucumber_expressions/errors'
|
3
|
+
|
4
|
+
module Cucumber
|
5
|
+
module CucumberExpressions
|
6
|
+
class TreeRegexp
|
7
|
+
attr_reader :regexp, :group_builder
|
8
|
+
|
9
|
+
def initialize(regexp)
|
10
|
+
@regexp = regexp.is_a?(Regexp) ? regexp : Regexp.new(regexp)
|
11
|
+
@stack = [GroupBuilder.new]
|
12
|
+
group_start_stack = []
|
13
|
+
last = nil
|
14
|
+
escaping = false
|
15
|
+
@non_capturing_maybe = false
|
16
|
+
@name_capturing_maybe = false
|
17
|
+
char_class = false
|
18
|
+
|
19
|
+
@regexp.source.each_char.with_index do |c, n|
|
20
|
+
if c == '[' && !escaping
|
21
|
+
char_class = true
|
22
|
+
elsif c == ']' && !escaping
|
23
|
+
char_class = false
|
24
|
+
elsif c == '(' && !escaping && !char_class
|
25
|
+
@stack.push(GroupBuilder.new)
|
26
|
+
group_start_stack.push(n + 1)
|
27
|
+
@non_capturing_maybe = false
|
28
|
+
elsif c == ')' && !escaping && !char_class
|
29
|
+
gb = @stack.pop
|
30
|
+
group_start = group_start_stack.pop
|
31
|
+
if gb.capturing?
|
32
|
+
gb.source = @regexp.source[group_start...n]
|
33
|
+
@stack.last.add(gb)
|
34
|
+
else
|
35
|
+
gb.move_children_to(@stack.last)
|
36
|
+
end
|
37
|
+
end_group
|
38
|
+
elsif c == '?' && last == '('
|
39
|
+
@non_capturing_maybe = true
|
40
|
+
elsif (c == '<') && @non_capturing_maybe
|
41
|
+
@name_capturing_maybe = true
|
42
|
+
elsif (c == ':' || c == '!' || c == '=') && last == '?' && @non_capturing_maybe
|
43
|
+
end_non_capturing_group
|
44
|
+
elsif (c == '=' || c == '!') && last == '<' && @name_capturing_maybe
|
45
|
+
end_non_capturing_group
|
46
|
+
elsif @name_capturing_maybe
|
47
|
+
raise CucumberExpressionError.new("Named capture groups are not supported. See https://github.com/cucumber/cucumber/issues/329")
|
48
|
+
end
|
49
|
+
|
50
|
+
escaping = c == '\\' && !escaping
|
51
|
+
last = c
|
52
|
+
end
|
53
|
+
@group_builder = @stack.pop
|
54
|
+
end
|
55
|
+
|
56
|
+
def match(s)
|
57
|
+
match = @regexp.match(s)
|
58
|
+
return nil if match.nil?
|
59
|
+
group_indices = (0..match.length).to_a.to_enum
|
60
|
+
@group_builder.build(match, group_indices)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def end_non_capturing_group
|
66
|
+
@stack.last.set_non_capturing!
|
67
|
+
end_group
|
68
|
+
end
|
69
|
+
|
70
|
+
def end_group
|
71
|
+
@non_capturing_maybe = false
|
72
|
+
@name_capturing_maybe = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
#
|
3
|
+
# Updates the *.gemspec in the current directory to use the latest releases of gems
|
4
|
+
#
|
5
|
+
set -uf -o pipefail
|
6
|
+
IFS=$'\n'
|
7
|
+
|
8
|
+
gemspec=$(find . -type f -maxdepth 1 -name "*.gemspec")
|
9
|
+
if [ "${gemspec}" = "" ]; then
|
10
|
+
exit 0
|
11
|
+
fi
|
12
|
+
add_dependency_lines=$(cat ${gemspec} | grep "s.add_[a-z_]*dependency '[^']*'")
|
13
|
+
if [ $? -ne 0 ]; then
|
14
|
+
# No add_dependency_lines found - nothing to do
|
15
|
+
exit 0
|
16
|
+
fi
|
17
|
+
|
18
|
+
set -e
|
19
|
+
|
20
|
+
gems=$(echo "${add_dependency_lines}" | tr -s ' ' | cut -d ' ' -f3 | cut -d"'" -f 2)
|
21
|
+
while read -r gem; do
|
22
|
+
echo "upgrading ${gem}"
|
23
|
+
if [ "${gem}" = "bundler" ]; then
|
24
|
+
cat "${gemspec}" | sed "s/\(s.add_[a-z_]*dependency\) '${gem}'.*/\1 '${gem}', '>= 1.16.2'/" > ${gemspec}.tmp
|
25
|
+
else
|
26
|
+
gem_line=$(gem list "${gem}" --remote --all --no-prerelease | grep "^${gem}\s")
|
27
|
+
latest_patch_version=$(echo "${gem_line}" | cut -d'(' -f2 | cut -d')' -f1 | cut -d',' -f1 | cut -d' ' -f1)
|
28
|
+
latest_minor_version=$(echo "${latest_patch_version}" | cut -d. -f1,2)
|
29
|
+
cat "${gemspec}" | sed "s/\(s.add_[a-z_]*dependency\) '${gem}'.*/\1 '${gem}', '~> ${latest_minor_version}', '>= ${latest_patch_version}'/" > ${gemspec}.tmp
|
30
|
+
fi
|
31
|
+
mv ${gemspec}.tmp ${gemspec}
|
32
|
+
done <<< "${gems}"
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# With thanks to @myronmarston
|
3
|
+
# https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
|
4
|
+
|
5
|
+
module CaptureWarnings
|
6
|
+
def report_warnings(&block)
|
7
|
+
current_dir = Dir.pwd
|
8
|
+
warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
|
9
|
+
project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
|
10
|
+
|
11
|
+
if errors.any?
|
12
|
+
puts errors.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
if other_warnings.any?
|
16
|
+
puts "#{ other_warnings.count } warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
|
17
|
+
print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
|
18
|
+
end
|
19
|
+
|
20
|
+
# Until they fix https://bugs.ruby-lang.org/issues/10661
|
21
|
+
if RUBY_VERSION == "2.2.0"
|
22
|
+
project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
|
23
|
+
end
|
24
|
+
|
25
|
+
if project_warnings.any?
|
26
|
+
puts "#{ project_warnings.count } warnings detected"
|
27
|
+
print_warnings('cucumber-expressions', project_warnings)
|
28
|
+
fail "Please remove all cucumber-expressions warnings."
|
29
|
+
end
|
30
|
+
|
31
|
+
ensure_system_exit_if_required
|
32
|
+
end
|
33
|
+
|
34
|
+
def capture_error(&block)
|
35
|
+
old_stderr = STDERR.clone
|
36
|
+
pipe_r, pipe_w = IO.pipe
|
37
|
+
pipe_r.sync = true
|
38
|
+
error = String.new
|
39
|
+
reader = Thread.new do
|
40
|
+
begin
|
41
|
+
loop do
|
42
|
+
error << pipe_r.readpartial(1024)
|
43
|
+
end
|
44
|
+
rescue EOFError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
STDERR.reopen(pipe_w)
|
48
|
+
block.call
|
49
|
+
ensure
|
50
|
+
capture_system_exit
|
51
|
+
STDERR.reopen(old_stderr)
|
52
|
+
pipe_w.close
|
53
|
+
reader.join
|
54
|
+
return error.split("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
def print_warnings(type, warnings)
|
58
|
+
puts
|
59
|
+
puts "-" * 30 + " #{type} warnings: " + "-" * 30
|
60
|
+
puts
|
61
|
+
puts warnings.join("\n")
|
62
|
+
puts
|
63
|
+
puts "-" * 75
|
64
|
+
puts
|
65
|
+
end
|
66
|
+
|
67
|
+
def ensure_system_exit_if_required
|
68
|
+
raise @system_exit if @system_exit
|
69
|
+
end
|
70
|
+
|
71
|
+
def capture_system_exit
|
72
|
+
@system_exit = $!
|
73
|
+
end
|
74
|
+
end
|
data/spec/coverage.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'cucumber/cucumber_expressions/argument'
|
2
|
+
require 'cucumber/cucumber_expressions/tree_regexp'
|
3
|
+
require 'cucumber/cucumber_expressions/parameter_type_registry'
|
4
|
+
|
5
|
+
module Cucumber
|
6
|
+
module CucumberExpressions
|
7
|
+
describe Argument do
|
8
|
+
it 'exposes parameter_type' do
|
9
|
+
tree_regexp = TreeRegexp.new(/three (.*) mice/)
|
10
|
+
parameter_type_registry = ParameterTypeRegistry.new
|
11
|
+
arguments = Argument.build(tree_regexp, "three blind mice", [parameter_type_registry.lookup_by_type_name("string")])
|
12
|
+
argument = arguments[0]
|
13
|
+
expect(argument.parameter_type.name).to eq("string")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'cucumber/cucumber_expressions/parameter_type'
|
2
|
+
require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory'
|
3
|
+
|
4
|
+
module Cucumber
|
5
|
+
module CucumberExpressions
|
6
|
+
|
7
|
+
class Color; end
|
8
|
+
class CssColor; end
|
9
|
+
class Date; end
|
10
|
+
class DateTime; end
|
11
|
+
class Timestamp; end
|
12
|
+
|
13
|
+
describe CombinatorialGeneratedExpressionFactory do
|
14
|
+
it 'generates multiple expressions' do
|
15
|
+
parameter_type_combinations = [
|
16
|
+
[
|
17
|
+
ParameterType.new('color', /red|blue|yellow/, Color, lambda {|s| Color.new}, true, false),
|
18
|
+
ParameterType.new('csscolor', /red|blue|yellow/, CssColor, lambda {|s| CssColor.new}, true, false)
|
19
|
+
],
|
20
|
+
[
|
21
|
+
ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date, lambda {|s| Date.new}, true, false),
|
22
|
+
ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime, lambda {|s| DateTime.new}, true, false),
|
23
|
+
ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp, lambda {|s| Timestamp.new}, true, false)
|
24
|
+
]
|
25
|
+
]
|
26
|
+
|
27
|
+
factory = CombinatorialGeneratedExpressionFactory.new(
|
28
|
+
'I bought a {%s} ball on {%s}',
|
29
|
+
parameter_type_combinations
|
30
|
+
)
|
31
|
+
expressions = factory.generate_expressions.map {|ge| ge.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
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'cucumber/cucumber_expressions/cucumber_expression_generator'
|
2
|
+
require 'cucumber/cucumber_expressions/cucumber_expression'
|
3
|
+
require 'cucumber/cucumber_expressions/parameter_type'
|
4
|
+
require 'cucumber/cucumber_expressions/parameter_type_registry'
|
5
|
+
|
6
|
+
module Cucumber
|
7
|
+
module CucumberExpressions
|
8
|
+
describe CucumberExpressionGenerator do
|
9
|
+
class Currency
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
@parameter_type_registry = ParameterTypeRegistry.new
|
14
|
+
@generator = CucumberExpressionGenerator.new(@parameter_type_registry)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "documents expression generation" do
|
18
|
+
parameter_registry = ParameterTypeRegistry.new
|
19
|
+
### [generate-expression]
|
20
|
+
generator = CucumberExpressionGenerator.new(parameter_registry)
|
21
|
+
undefined_step_text = "I have 2 cucumbers and 1.5 tomato"
|
22
|
+
generated_expression = generator.generate_expression(undefined_step_text)
|
23
|
+
expect(generated_expression.source).to eq("I have {int} cucumbers and {float} tomato")
|
24
|
+
expect(generated_expression.parameter_types[1].type).to eq(Float)
|
25
|
+
### [generate-expression]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "generates expression for no args" do
|
29
|
+
assert_expression("hello", [], "hello")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "generates expression with escaped left parenthesis" do
|
33
|
+
assert_expression(
|
34
|
+
"\\(iii)", [],
|
35
|
+
"(iii)")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "generates expression with escaped left curly brace" do
|
39
|
+
assert_expression(
|
40
|
+
"\\{iii}", [],
|
41
|
+
"{iii}")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "generates expression with escaped slashes" do
|
45
|
+
assert_expression(
|
46
|
+
"The {int}\\/{int}\\/{int} hey", ["int", "int2", "int3"],
|
47
|
+
"The 1814/05/17 hey")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "generates expression for int float arg" do
|
51
|
+
assert_expression(
|
52
|
+
"I have {int} cukes and {float} euro", ["int", "float"],
|
53
|
+
"I have 2 cukes and 1.5 euro")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "generates expression for strings" do
|
57
|
+
assert_expression(
|
58
|
+
"I like {string} and {string}", ["string", "string2"],
|
59
|
+
'I like "bangers" and \'mash\'')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "generates expression with % sign" do
|
63
|
+
assert_expression(
|
64
|
+
"I am {int}% foobar", ["int"],
|
65
|
+
'I am 20% foobar')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "generates expression for just int" do
|
69
|
+
assert_expression(
|
70
|
+
"{int}", ["int"],
|
71
|
+
"99999")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "numbers only second argument when builtin type is not reserved keyword" do
|
75
|
+
assert_expression(
|
76
|
+
"I have {int} cukes and {int} euro", ["int", "int2"],
|
77
|
+
"I have 2 cukes and 5 euro")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "numbers only second argument when type is not reserved keyword" do
|
81
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
82
|
+
'currency',
|
83
|
+
'[A-Z]{3}',
|
84
|
+
Currency,
|
85
|
+
lambda {|s| Currency.new(s)},
|
86
|
+
true,
|
87
|
+
true
|
88
|
+
))
|
89
|
+
|
90
|
+
assert_expression(
|
91
|
+
"I have a {currency} account and a {currency} account", ["currency", "currency2"],
|
92
|
+
"I have a EUR account and a GBP account")
|
93
|
+
end
|
94
|
+
|
95
|
+
it "exposes parameters in generated expression" do
|
96
|
+
expression = @generator.generate_expression("I have 2 cukes and 1.5 euro")
|
97
|
+
types = expression.parameter_types.map(&:type)
|
98
|
+
expect(types).to eq([Integer, Float])
|
99
|
+
end
|
100
|
+
|
101
|
+
it "matches parameter types with optional capture groups" do
|
102
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
103
|
+
'optional-flight',
|
104
|
+
/(1st flight)?/,
|
105
|
+
String,
|
106
|
+
lambda {|s| s},
|
107
|
+
true,
|
108
|
+
false
|
109
|
+
))
|
110
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
111
|
+
'optional-hotel',
|
112
|
+
/(1 hotel)?/,
|
113
|
+
String,
|
114
|
+
lambda {|s| s},
|
115
|
+
true,
|
116
|
+
false
|
117
|
+
))
|
118
|
+
|
119
|
+
expression = @generator.generate_expressions("I reach Stage 4: 1st flight -1 hotel")[0]
|
120
|
+
# While you would expect this to be `I reach Stage {int}: {optional-flight} -{optional-hotel}`
|
121
|
+
# the `-1` causes {int} to match just before {optional-hotel}.
|
122
|
+
expect(expression.source).to eq("I reach Stage {int}: {optional-flight} {int} hotel")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "generates at most 256 expressions" do
|
126
|
+
for i in 0..3
|
127
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
128
|
+
"my-type-#{i}",
|
129
|
+
/([a-z] )*?[a-z]/,
|
130
|
+
String,
|
131
|
+
lambda {|s| s},
|
132
|
+
true,
|
133
|
+
false
|
134
|
+
))
|
135
|
+
end
|
136
|
+
# This would otherwise generate 4^11=4194300 expressions and consume just shy of 1.5GB.
|
137
|
+
expressions = @generator.generate_expressions("a s i m p l e s t e p")
|
138
|
+
expect(expressions.length).to eq(256)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "prefers expression with longest non empty match" do
|
142
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
143
|
+
'zero-or-more',
|
144
|
+
/[a-z]*/,
|
145
|
+
String,
|
146
|
+
lambda {|s| s},
|
147
|
+
true,
|
148
|
+
false
|
149
|
+
))
|
150
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
151
|
+
'exactly-one',
|
152
|
+
/[a-z]/,
|
153
|
+
String,
|
154
|
+
lambda {|s| s},
|
155
|
+
true,
|
156
|
+
false
|
157
|
+
))
|
158
|
+
|
159
|
+
expressions = @generator.generate_expressions("a simple step")
|
160
|
+
expect(expressions.length).to eq(2)
|
161
|
+
expect(expressions[0].source).to eq("{exactly-one} {zero-or-more} {zero-or-more}")
|
162
|
+
expect(expressions[1].source).to eq("{zero-or-more} {zero-or-more} {zero-or-more}")
|
163
|
+
end
|
164
|
+
|
165
|
+
context "does not suggest parameter when match is" do
|
166
|
+
before do
|
167
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
168
|
+
'direction',
|
169
|
+
/(up|down)/,
|
170
|
+
String,
|
171
|
+
lambda {|s| s},
|
172
|
+
true,
|
173
|
+
false
|
174
|
+
))
|
175
|
+
end
|
176
|
+
|
177
|
+
it "at the beginning of a word" do
|
178
|
+
expect(@generator.generate_expression("When I download a picture").source).not_to eq("When I {direction}load a picture")
|
179
|
+
expect(@generator.generate_expression("When I download a picture").source).to eq("When I download a picture")
|
180
|
+
end
|
181
|
+
|
182
|
+
it "inside a word" do
|
183
|
+
expect(@generator.generate_expression("When I watch the muppet show").source).not_to eq("When I watch the m{direction}pet show")
|
184
|
+
expect(@generator.generate_expression("When I watch the muppet show").source).to eq("When I watch the muppet show")
|
185
|
+
end
|
186
|
+
|
187
|
+
it "at the end of a word" do
|
188
|
+
expect(@generator.generate_expression("When I create a group").source).not_to eq("When I create a gro{direction}")
|
189
|
+
expect(@generator.generate_expression("When I create a group").source).to eq("When I create a group")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "does suggest parameter when match is" do
|
194
|
+
before do
|
195
|
+
@parameter_type_registry.define_parameter_type(ParameterType.new(
|
196
|
+
'direction',
|
197
|
+
/(up|down)/,
|
198
|
+
String,
|
199
|
+
lambda {|s| s},
|
200
|
+
true,
|
201
|
+
false
|
202
|
+
))
|
203
|
+
end
|
204
|
+
|
205
|
+
it "a full word" do
|
206
|
+
expect(@generator.generate_expression("When I go down the road").source).to eq("When I go {direction} the road")
|
207
|
+
expect(@generator.generate_expression("When I walk up the hill").source).to eq("When I walk {direction} the hill")
|
208
|
+
expect(@generator.generate_expression("up the hill, the road goes down").source).to eq("{direction} the hill, the road goes {direction}")
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'wrapped around punctuation characters' do
|
212
|
+
expect(@generator.generate_expression("When direction is:down").source).to eq("When direction is:{direction}")
|
213
|
+
expect(@generator.generate_expression("Then direction is down.").source).to eq("Then direction is {direction}.")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def assert_expression(expected_expression, expected_argument_names, text)
|
218
|
+
generated_expression = @generator.generate_expression(text)
|
219
|
+
expect(generated_expression.parameter_names).to eq(expected_argument_names)
|
220
|
+
expect(generated_expression.source).to eq(expected_expression)
|
221
|
+
|
222
|
+
cucumber_expression = CucumberExpression.new(generated_expression.source, @parameter_type_registry)
|
223
|
+
match = cucumber_expression.match(text)
|
224
|
+
if match.nil?
|
225
|
+
raise "Expected text '#{text}' to match generated expression '#{generated_expression.source}'"
|
226
|
+
end
|
227
|
+
expect(match.length).to eq(expected_argument_names.length)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|