cucumber 3.0.2 → 4.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +216 -17
- data/CONTRIBUTING.md +4 -21
- data/README.md +8 -10
- data/bin/cucumber +1 -1
- data/lib/autotest/cucumber.rb +1 -0
- data/lib/autotest/cucumber_mixin.rb +35 -39
- data/lib/autotest/cucumber_rails.rb +1 -0
- data/lib/autotest/cucumber_rails_rspec.rb +1 -0
- data/lib/autotest/cucumber_rails_rspec2.rb +1 -0
- data/lib/autotest/cucumber_rspec.rb +1 -0
- data/lib/autotest/cucumber_rspec2.rb +1 -0
- data/lib/autotest/discover.rb +1 -0
- data/lib/cucumber.rb +2 -1
- data/lib/cucumber/cli/configuration.rb +6 -5
- data/lib/cucumber/cli/main.rb +14 -14
- data/lib/cucumber/cli/options.rb +113 -116
- data/lib/cucumber/cli/profile_loader.rb +50 -29
- data/lib/cucumber/cli/rerun_file.rb +1 -0
- data/lib/cucumber/configuration.rb +38 -29
- data/lib/cucumber/constantize.rb +8 -10
- data/lib/cucumber/core_ext/string.rb +1 -0
- data/lib/cucumber/deprecate.rb +32 -8
- data/lib/cucumber/encoding.rb +2 -1
- data/lib/cucumber/errors.rb +6 -7
- data/lib/cucumber/events.rb +14 -7
- data/lib/cucumber/events/envelope.rb +9 -0
- data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
- data/lib/cucumber/events/gherkin_source_read.rb +1 -4
- data/lib/cucumber/events/hook_test_step_created.rb +13 -0
- data/lib/cucumber/events/step_activated.rb +6 -6
- data/lib/cucumber/events/step_definition_registered.rb +4 -8
- data/lib/cucumber/events/test_case_created.rb +13 -0
- data/lib/cucumber/events/test_case_finished.rb +0 -4
- data/lib/cucumber/events/test_case_ready.rb +12 -0
- data/lib/cucumber/events/test_case_started.rb +0 -4
- data/lib/cucumber/events/test_run_finished.rb +2 -3
- data/lib/cucumber/events/test_run_started.rb +2 -4
- data/lib/cucumber/events/test_step_created.rb +13 -0
- data/lib/cucumber/events/test_step_finished.rb +0 -4
- data/lib/cucumber/events/test_step_started.rb +1 -5
- data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
- data/lib/cucumber/file_specs.rb +7 -6
- data/lib/cucumber/filters.rb +2 -0
- data/lib/cucumber/filters/activate_steps.rb +6 -4
- data/lib/cucumber/filters/apply_after_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_after_step_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_around_hooks.rb +1 -0
- data/lib/cucumber/filters/apply_before_hooks.rb +1 -0
- data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
- data/lib/cucumber/filters/broadcast_test_run_started_event.rb +2 -1
- data/lib/cucumber/filters/gated_receiver.rb +1 -2
- data/lib/cucumber/filters/prepare_world.rb +6 -13
- data/lib/cucumber/filters/quit.rb +3 -6
- data/lib/cucumber/filters/randomizer.rb +6 -7
- data/lib/cucumber/filters/retry.rb +2 -2
- data/lib/cucumber/filters/tag_limits.rb +2 -2
- data/lib/cucumber/filters/tag_limits/test_case_index.rb +1 -2
- data/lib/cucumber/filters/tag_limits/verifier.rb +3 -6
- data/lib/cucumber/formatter/ansicolor.rb +33 -37
- data/lib/cucumber/formatter/ast_lookup.rb +165 -0
- data/lib/cucumber/formatter/backtrace_filter.rb +10 -10
- data/lib/cucumber/formatter/console.rb +65 -74
- data/lib/cucumber/formatter/console_counts.rb +4 -9
- data/lib/cucumber/formatter/console_issues.rb +9 -6
- data/lib/cucumber/formatter/duration.rb +2 -1
- data/lib/cucumber/formatter/duration_extractor.rb +4 -2
- data/lib/cucumber/formatter/errors.rb +6 -0
- data/lib/cucumber/formatter/fail_fast.rb +9 -6
- data/lib/cucumber/formatter/fanout.rb +3 -3
- data/lib/cucumber/formatter/html.rb +11 -602
- data/lib/cucumber/formatter/http_io.rb +146 -0
- data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -3
- data/lib/cucumber/formatter/interceptor.rb +11 -18
- data/lib/cucumber/formatter/io.rb +18 -11
- data/lib/cucumber/formatter/json.rb +102 -109
- data/lib/cucumber/formatter/junit.rb +73 -68
- data/lib/cucumber/formatter/message.rb +22 -0
- data/lib/cucumber/formatter/message_builder.rb +255 -0
- data/lib/cucumber/formatter/pretty.rb +360 -153
- data/lib/cucumber/formatter/progress.rb +31 -32
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
- data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
- data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
- data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
- data/lib/cucumber/formatter/rerun.rb +23 -4
- data/lib/cucumber/formatter/stepdefs.rb +2 -2
- data/lib/cucumber/formatter/steps.rb +4 -5
- data/lib/cucumber/formatter/summary.rb +17 -9
- data/lib/cucumber/formatter/unicode.rb +16 -18
- data/lib/cucumber/formatter/usage.rb +30 -26
- data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +83 -86
- data/lib/cucumber/gherkin/formatter/escaping.rb +13 -12
- data/lib/cucumber/gherkin/i18n.rb +1 -0
- data/lib/cucumber/gherkin/steps_parser.rb +18 -8
- data/lib/cucumber/glue/dsl.rb +2 -1
- data/lib/cucumber/glue/hook.rb +35 -11
- data/lib/cucumber/glue/invoke_in_world.rb +15 -20
- data/lib/cucumber/glue/proto_world.rb +47 -39
- data/lib/cucumber/glue/registry_and_more.rb +54 -23
- data/lib/cucumber/glue/snippet.rb +24 -27
- data/lib/cucumber/glue/step_definition.rb +51 -28
- data/lib/cucumber/glue/world_factory.rb +1 -3
- data/lib/cucumber/hooks.rb +24 -14
- data/lib/cucumber/load_path.rb +1 -0
- data/lib/cucumber/multiline_argument.rb +6 -8
- data/lib/cucumber/multiline_argument/data_table.rb +106 -73
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +8 -11
- data/lib/cucumber/multiline_argument/doc_string.rb +2 -1
- data/lib/cucumber/platform.rb +4 -3
- data/lib/cucumber/project_initializer.rb +1 -1
- data/lib/cucumber/rake/task.rb +21 -18
- data/lib/cucumber/rspec/disable_option_parser.rb +10 -8
- data/lib/cucumber/rspec/doubles.rb +1 -0
- data/lib/cucumber/running_test_case.rb +4 -54
- data/lib/cucumber/runtime.rb +57 -61
- data/lib/cucumber/runtime/after_hooks.rb +9 -4
- data/lib/cucumber/runtime/before_hooks.rb +9 -4
- data/lib/cucumber/runtime/for_programming_languages.rb +12 -9
- data/lib/cucumber/runtime/step_hooks.rb +5 -2
- data/lib/cucumber/runtime/support_code.rb +16 -22
- data/lib/cucumber/runtime/user_interface.rb +8 -19
- data/lib/cucumber/step_definition_light.rb +6 -4
- data/lib/cucumber/step_definitions.rb +3 -2
- data/lib/cucumber/step_match.rb +20 -18
- data/lib/cucumber/step_match_search.rb +9 -9
- data/lib/cucumber/term/ansicolor.rb +39 -39
- data/lib/cucumber/unit.rb +1 -0
- data/lib/cucumber/version +1 -1
- data/lib/simplecov_setup.rb +1 -0
- metadata +214 -127
- data/lib/cucumber/formatter/cucumber.css +0 -286
- data/lib/cucumber/formatter/cucumber.sass +0 -247
- data/lib/cucumber/formatter/hook_query_visitor.rb +0 -41
- data/lib/cucumber/formatter/html_builder.rb +0 -120
- data/lib/cucumber/formatter/inline-js.js +0 -30
- data/lib/cucumber/formatter/jquery-min.js +0 -154
- data/lib/cucumber/formatter/json_pretty.rb +0 -10
- data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
- data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
- data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
- data/lib/cucumber/step_argument.rb +0 -24
@@ -3,8 +3,7 @@
|
|
3
3
|
module Cucumber
|
4
4
|
module Glue
|
5
5
|
module Snippet
|
6
|
-
|
7
|
-
ARGUMENT_PATTERNS = ['"([^"]*)"', '(\d+)']
|
6
|
+
ARGUMENT_PATTERNS = ['"([^"]*)"', '(\d+)'].freeze
|
8
7
|
|
9
8
|
class Generator
|
10
9
|
def self.register_on(configuration)
|
@@ -26,7 +25,6 @@ module Cucumber
|
|
26
25
|
end
|
27
26
|
|
28
27
|
class BaseSnippet
|
29
|
-
|
30
28
|
def initialize(cucumber_expression_generator, code_keyword, step_name, multiline_argument)
|
31
29
|
@number_of_arguments = 0
|
32
30
|
@code_keyword = code_keyword
|
@@ -44,7 +42,7 @@ module Cucumber
|
|
44
42
|
end
|
45
43
|
|
46
44
|
def self.cli_option_string(type, cucumber_expression_generator)
|
47
|
-
format('
|
45
|
+
format('%<type>-7s: %<description>-28s e.g. %<example>s', type: type, description: description, example: example(cucumber_expression_generator))
|
48
46
|
end
|
49
47
|
|
50
48
|
private
|
@@ -63,7 +61,7 @@ module Cucumber
|
|
63
61
|
end
|
64
62
|
|
65
63
|
def do_block
|
66
|
-
do_block = String.new
|
64
|
+
do_block = String.new # rubocop:disable Style/EmptyLiteral
|
67
65
|
do_block << "do#{parameters}\n"
|
68
66
|
multiline_argument.append_comment_to(do_block)
|
69
67
|
do_block << " pending # Write code here that turns the phrase above into concrete actions\n"
|
@@ -72,15 +70,18 @@ module Cucumber
|
|
72
70
|
end
|
73
71
|
|
74
72
|
def parameters
|
75
|
-
block_args = (0...number_of_arguments).map { |n| "arg#{n+1}" }
|
73
|
+
block_args = (0...number_of_arguments).map { |n| "arg#{n + 1}" }
|
76
74
|
multiline_argument.append_block_parameter_to(block_args)
|
77
|
-
block_args.empty? ? '' : " |#{block_args.join(
|
75
|
+
block_args.empty? ? '' : " |#{block_args.join(', ')}|"
|
78
76
|
end
|
79
77
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
78
|
+
class << self
|
79
|
+
private
|
83
80
|
|
81
|
+
def example(cucumber_expression_generator)
|
82
|
+
new(cucumber_expression_generator, 'Given', 'I have 2 cukes', MultilineArgument::None.new).step
|
83
|
+
end
|
84
|
+
end
|
84
85
|
end
|
85
86
|
|
86
87
|
class CucumberExpression < BaseSnippet
|
@@ -90,11 +91,11 @@ module Cucumber
|
|
90
91
|
|
91
92
|
def to_s
|
92
93
|
header = generated_expressions.each_with_index.map do |expr, i|
|
93
|
-
prefix = i
|
94
|
-
"#{prefix}#{code_keyword}(
|
94
|
+
prefix = i.zero? ? '' : '# '
|
95
|
+
"#{prefix}#{code_keyword}('#{expr.source}') do#{parameters(expr)}"
|
95
96
|
end.join("\n")
|
96
97
|
|
97
|
-
body = String.new
|
98
|
+
body = String.new # rubocop:disable Style/EmptyLiteral
|
98
99
|
multiline_argument.append_comment_to(body)
|
99
100
|
body << " pending # Write code here that turns the phrase above into concrete actions\n"
|
100
101
|
body << 'end'
|
@@ -105,7 +106,7 @@ module Cucumber
|
|
105
106
|
def parameters(expr)
|
106
107
|
parameter_names = expr.parameter_names
|
107
108
|
multiline_argument.append_block_parameter_to(parameter_names)
|
108
|
-
parameter_names.empty? ? '' : " |#{parameter_names.join(
|
109
|
+
parameter_names.empty? ? '' : " |#{parameter_names.join(', ')}|"
|
109
110
|
end
|
110
111
|
|
111
112
|
def self.description
|
@@ -144,14 +145,13 @@ module Cucumber
|
|
144
145
|
end
|
145
146
|
|
146
147
|
SNIPPET_TYPES = {
|
147
|
-
:
|
148
|
-
:
|
149
|
-
:
|
150
|
-
:
|
151
|
-
}
|
148
|
+
cucumber_expression: CucumberExpression,
|
149
|
+
regexp: Regexp,
|
150
|
+
classic: Classic,
|
151
|
+
percent: Percent
|
152
|
+
}.freeze
|
152
153
|
|
153
154
|
module MultilineArgumentSnippet
|
154
|
-
|
155
155
|
def self.new(multiline_argument)
|
156
156
|
builder = Builder.new
|
157
157
|
multiline_argument.describe_to(builder)
|
@@ -174,11 +174,10 @@ module Cucumber
|
|
174
174
|
|
175
175
|
class DocString
|
176
176
|
def append_block_parameter_to(array)
|
177
|
-
array << '
|
177
|
+
array << 'doc_string'
|
178
178
|
end
|
179
179
|
|
180
|
-
def append_comment_to(string)
|
181
|
-
end
|
180
|
+
def append_comment_to(string); end
|
182
181
|
end
|
183
182
|
|
184
183
|
class DataTable
|
@@ -196,11 +195,9 @@ module Cucumber
|
|
196
195
|
end
|
197
196
|
|
198
197
|
class None
|
199
|
-
def append_block_parameter_to(array)
|
200
|
-
end
|
198
|
+
def append_block_parameter_to(array); end
|
201
199
|
|
202
|
-
def append_comment_to(string)
|
203
|
-
end
|
200
|
+
def append_comment_to(string); end
|
204
201
|
end
|
205
202
|
end
|
206
203
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'cucumber/step_match'
|
3
|
-
require 'cucumber/step_argument'
|
4
4
|
require 'cucumber/core_ext/string'
|
5
5
|
require 'cucumber/glue/invoke_in_world'
|
6
6
|
|
@@ -17,7 +17,6 @@ module Cucumber
|
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
class StepDefinition
|
20
|
-
|
21
20
|
class MissingProc < StandardError
|
22
21
|
def message
|
23
22
|
'Step definitions must always have a proc or symbol'
|
@@ -25,9 +24,9 @@ module Cucumber
|
|
25
24
|
end
|
26
25
|
|
27
26
|
class << self
|
28
|
-
def new(registry, string_or_regexp, proc_or_sym, options)
|
27
|
+
def new(id, registry, string_or_regexp, proc_or_sym, options)
|
29
28
|
raise MissingProc if proc_or_sym.nil?
|
30
|
-
super registry, registry.create_expression(string_or_regexp), create_proc(proc_or_sym, options)
|
29
|
+
super id, registry, registry.create_expression(string_or_regexp), create_proc(proc_or_sym, options)
|
31
30
|
end
|
32
31
|
|
33
32
|
private
|
@@ -44,34 +43,60 @@ module Cucumber
|
|
44
43
|
end
|
45
44
|
|
46
45
|
def patch_location_onto(block)
|
47
|
-
location = Core::
|
46
|
+
location = Core::Test::Location.of_caller(5)
|
48
47
|
block.define_singleton_method(:source_location) { [location.file, location.line] }
|
49
48
|
block
|
50
49
|
end
|
51
50
|
|
52
51
|
def parse_target_proc_from(options)
|
53
|
-
return
|
52
|
+
return -> { self } unless options.key?(:on)
|
54
53
|
target = options[:on]
|
55
54
|
case target
|
56
55
|
when Proc
|
57
56
|
target
|
58
57
|
when Symbol
|
59
|
-
|
58
|
+
-> { send(target) }
|
60
59
|
else
|
61
|
-
|
60
|
+
-> { raise ArgumentError, 'Target must be a symbol or a proc' }
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
66
|
-
attr_reader :expression
|
65
|
+
attr_reader :id, :expression, :registry
|
67
66
|
|
68
|
-
def initialize(registry, expression, proc)
|
67
|
+
def initialize(id, registry, expression, proc)
|
69
68
|
raise 'No regexp' if expression.is_a?(Regexp)
|
70
|
-
@
|
69
|
+
@id = id
|
70
|
+
@registry = registry
|
71
|
+
@expression = expression
|
72
|
+
@proc = proc
|
71
73
|
# @registry.available_step_definition(regexp_source, location)
|
72
74
|
end
|
73
75
|
|
74
|
-
|
76
|
+
def to_envelope
|
77
|
+
Cucumber::Messages::Envelope.new(
|
78
|
+
step_definition: Cucumber::Messages::StepDefinition.new(
|
79
|
+
id: id,
|
80
|
+
pattern: Cucumber::Messages::StepDefinition::StepDefinitionPattern.new(
|
81
|
+
source: expression.source.to_s,
|
82
|
+
type: expression_type
|
83
|
+
),
|
84
|
+
source_reference: Cucumber::Messages::SourceReference.new(
|
85
|
+
uri: location.file,
|
86
|
+
location: Cucumber::Messages::Location.new(
|
87
|
+
line: location.lines.first
|
88
|
+
)
|
89
|
+
)
|
90
|
+
)
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def expression_type
|
95
|
+
return Cucumber::Messages::StepDefinition::StepDefinitionPattern::StepDefinitionPatternType::CUCUMBER_EXPRESSION if expression.is_a?(CucumberExpressions::CucumberExpression)
|
96
|
+
Cucumber::Messages::StepDefinition::StepDefinitionPattern::StepDefinitionPatternType::REGULAR_EXPRESSION
|
97
|
+
end
|
98
|
+
|
99
|
+
# @api private
|
75
100
|
def to_hash
|
76
101
|
type = expression.is_a?(CucumberExpressions::RegularExpression) ? 'regular expression' : 'cucumber expression'
|
77
102
|
regexp = expression.regexp
|
@@ -91,35 +116,33 @@ module Cucumber
|
|
91
116
|
}
|
92
117
|
end
|
93
118
|
|
94
|
-
#
|
95
|
-
def ==(
|
96
|
-
expression.source ==
|
119
|
+
# @api private
|
120
|
+
def ==(other)
|
121
|
+
expression.source == other.expression.source
|
97
122
|
end
|
98
123
|
|
99
|
-
#
|
124
|
+
# @api private
|
100
125
|
def arguments_from(step_name)
|
101
126
|
args = @expression.match(step_name)
|
102
127
|
# @registry.invoked_step_definition(regexp_source, location) if args
|
103
128
|
args
|
104
129
|
end
|
105
130
|
|
106
|
-
#
|
131
|
+
# @api private
|
107
132
|
# TODO: inline this and step definition just be a value object
|
108
133
|
def invoke(args)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
raise e
|
114
|
-
end
|
134
|
+
InvokeInWorld.cucumber_instance_exec_in(@registry.current_world, true, @expression.to_s, *args, &@proc)
|
135
|
+
rescue ArityMismatchError => e
|
136
|
+
e.backtrace.unshift(backtrace_line)
|
137
|
+
raise e
|
115
138
|
end
|
116
139
|
|
117
|
-
#
|
140
|
+
# @api private
|
118
141
|
def backtrace_line
|
119
142
|
"#{location}:in `#{@expression}'"
|
120
143
|
end
|
121
144
|
|
122
|
-
#
|
145
|
+
# @api private
|
123
146
|
def file_colon_line
|
124
147
|
case @proc
|
125
148
|
when Proc
|
@@ -129,12 +152,12 @@ module Cucumber
|
|
129
152
|
end
|
130
153
|
end
|
131
154
|
|
132
|
-
# The source location where the step
|
155
|
+
# The source location where the step definition can be found
|
133
156
|
def location
|
134
|
-
@location ||= Cucumber::Core::
|
157
|
+
@location ||= Cucumber::Core::Test::Location.from_source_location(*@proc.source_location)
|
135
158
|
end
|
136
159
|
|
137
|
-
#
|
160
|
+
# @api private
|
138
161
|
def file
|
139
162
|
@file ||= location.file
|
140
163
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Cucumber
|
2
2
|
module Glue
|
3
|
-
|
4
3
|
class WorldFactory
|
5
4
|
def initialize(proc)
|
6
5
|
@proc = proc || -> { Object.new }
|
@@ -11,13 +10,12 @@ module Cucumber
|
|
11
10
|
end
|
12
11
|
|
13
12
|
def raise_nil_world
|
14
|
-
raise NilWorld
|
13
|
+
raise NilWorld
|
15
14
|
rescue NilWorld => e
|
16
15
|
e.backtrace.clear
|
17
16
|
e.backtrace.push(Glue.backtrace_line(@proc, 'World'))
|
18
17
|
raise e
|
19
18
|
end
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
data/lib/cucumber/hooks.rb
CHANGED
@@ -1,38 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'pathname'
|
3
|
-
require 'cucumber/core/
|
4
|
+
require 'cucumber/core/test/location'
|
4
5
|
require 'cucumber/core/test/around_hook'
|
5
6
|
|
6
7
|
module Cucumber
|
7
|
-
|
8
8
|
# Hooks quack enough like `Cucumber::Core::Ast` source nodes that we can use them as
|
9
9
|
# source for test steps
|
10
10
|
module Hooks
|
11
|
-
|
12
11
|
class << self
|
13
|
-
def before_hook(
|
14
|
-
build_hook_step(
|
12
|
+
def before_hook(id, location, &block)
|
13
|
+
build_hook_step(id, location, block, BeforeHook, Core::Test::UnskippableAction)
|
15
14
|
end
|
16
15
|
|
17
|
-
def after_hook(
|
18
|
-
build_hook_step(
|
16
|
+
def after_hook(id, location, &block)
|
17
|
+
build_hook_step(id, location, block, AfterHook, Core::Test::UnskippableAction)
|
19
18
|
end
|
20
19
|
|
21
|
-
def after_step_hook(
|
22
|
-
raise ArgumentError
|
23
|
-
build_hook_step(
|
20
|
+
def after_step_hook(id, test_step, location, &block)
|
21
|
+
raise ArgumentError if test_step.hook?
|
22
|
+
build_hook_step(id, location, block, AfterStepHook, Core::Test::Action)
|
24
23
|
end
|
25
24
|
|
26
|
-
def around_hook(
|
25
|
+
def around_hook(&block)
|
27
26
|
Core::Test::AroundHook.new(&block)
|
28
27
|
end
|
29
28
|
|
30
29
|
private
|
31
30
|
|
32
|
-
def build_hook_step(
|
31
|
+
def build_hook_step(id, location, block, hook_type, action_type)
|
33
32
|
action = action_type.new(location, &block)
|
34
33
|
hook = hook_type.new(action.location)
|
35
|
-
Core::Test::
|
34
|
+
Core::Test::HookStep.new(id, hook.text, location, action)
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
@@ -47,6 +46,10 @@ module Cucumber
|
|
47
46
|
'After hook'
|
48
47
|
end
|
49
48
|
|
49
|
+
def to_s
|
50
|
+
"#{text} at #{location}"
|
51
|
+
end
|
52
|
+
|
50
53
|
def match_locations?(queried_locations)
|
51
54
|
queried_locations.any? { |other_location| other_location.match?(location) }
|
52
55
|
end
|
@@ -67,6 +70,10 @@ module Cucumber
|
|
67
70
|
'Before hook'
|
68
71
|
end
|
69
72
|
|
73
|
+
def to_s
|
74
|
+
"#{text} at #{location}"
|
75
|
+
end
|
76
|
+
|
70
77
|
def match_locations?(queried_locations)
|
71
78
|
queried_locations.any? { |other_location| other_location.match?(location) }
|
72
79
|
end
|
@@ -87,6 +94,10 @@ module Cucumber
|
|
87
94
|
'AfterStep hook'
|
88
95
|
end
|
89
96
|
|
97
|
+
def to_s
|
98
|
+
"#{text} at #{location}"
|
99
|
+
end
|
100
|
+
|
90
101
|
def match_locations?(queried_locations)
|
91
102
|
queried_locations.any? { |other_location| other_location.match?(location) }
|
92
103
|
end
|
@@ -95,6 +106,5 @@ module Cucumber
|
|
95
106
|
visitor.after_step_hook(self, *args)
|
96
107
|
end
|
97
108
|
end
|
98
|
-
|
99
109
|
end
|
100
110
|
end
|
data/lib/cucumber/load_path.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'delegate'
|
3
4
|
require 'cucumber/multiline_argument/data_table'
|
4
5
|
require 'cucumber/multiline_argument/doc_string'
|
5
6
|
|
6
7
|
module Cucumber
|
7
8
|
module MultilineArgument
|
8
|
-
|
9
9
|
class << self
|
10
10
|
def from_core(node)
|
11
11
|
builder.wrap(node)
|
12
12
|
end
|
13
13
|
|
14
|
-
def from(argument, location=nil, content_type=nil)
|
15
|
-
location ||= Core::
|
14
|
+
def from(argument, location = nil, content_type = nil)
|
15
|
+
location ||= Core::Test::Location.of_caller
|
16
16
|
case argument
|
17
17
|
when String
|
18
|
-
builder.doc_string(Core::
|
18
|
+
builder.doc_string(Core::Test::DocString.new(argument, content_type))
|
19
19
|
when Array
|
20
20
|
location = location.on_line(argument.first.line..argument.last.line)
|
21
21
|
builder.data_table(argument.map(&:cells), location)
|
@@ -52,11 +52,9 @@ module Cucumber
|
|
52
52
|
end
|
53
53
|
|
54
54
|
class None
|
55
|
-
def append_to(array)
|
56
|
-
end
|
55
|
+
def append_to(array); end
|
57
56
|
|
58
|
-
def describe_to(visitor)
|
59
|
-
end
|
57
|
+
def describe_to(visitor); end
|
60
58
|
end
|
61
59
|
end
|
62
60
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'forwardable'
|
3
4
|
require 'cucumber/gherkin/data_table_parser'
|
4
5
|
require 'cucumber/gherkin/formatter/escaping'
|
5
|
-
require 'cucumber/core/ast/describes_itself'
|
6
6
|
require 'cucumber/multiline_argument/data_table/diff_matrices'
|
7
7
|
|
8
8
|
module Cucumber
|
@@ -27,19 +27,21 @@ module Cucumber
|
|
27
27
|
# This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
|
28
28
|
#
|
29
29
|
class DataTable
|
30
|
-
include Core::Ast::DescribesItself
|
31
|
-
|
32
30
|
def self.default_arg_name #:nodoc:
|
33
31
|
'table'
|
34
32
|
end
|
35
33
|
|
34
|
+
def describe_to(visitor, *args)
|
35
|
+
visitor.legacy_table(self, *args)
|
36
|
+
end
|
37
|
+
|
36
38
|
class << self
|
37
|
-
def from(data
|
39
|
+
def from(data)
|
38
40
|
case data
|
39
41
|
when Array
|
40
|
-
from_array(data
|
42
|
+
from_array(data)
|
41
43
|
when String
|
42
|
-
parse(data
|
44
|
+
parse(data)
|
43
45
|
else
|
44
46
|
raise ArgumentError, 'expected data to be a String or an Array.'
|
45
47
|
end
|
@@ -47,15 +49,15 @@ module Cucumber
|
|
47
49
|
|
48
50
|
private
|
49
51
|
|
50
|
-
def parse(text
|
52
|
+
def parse(text)
|
51
53
|
builder = Builder.new
|
52
54
|
parser = Cucumber::Gherkin::DataTableParser.new(builder)
|
53
55
|
parser.parse(text)
|
54
|
-
from_array(builder.rows
|
56
|
+
from_array(builder.rows)
|
55
57
|
end
|
56
58
|
|
57
|
-
def from_array(data
|
58
|
-
new Core::
|
59
|
+
def from_array(data)
|
60
|
+
new Core::Test::DataTable.new(data)
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
@@ -70,19 +72,17 @@ module Cucumber
|
|
70
72
|
@rows << row
|
71
73
|
end
|
72
74
|
|
73
|
-
def eof
|
74
|
-
end
|
75
|
+
def eof; end
|
75
76
|
end
|
76
77
|
|
78
|
+
NULL_CONVERSIONS = Hash.new(strict: false, proc: ->(cell_value) { cell_value }).freeze
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
# @param data [Core::Ast::DataTable] the data for the table
|
80
|
+
# @param data [Core::Test::DataTable] the data for the table
|
81
81
|
# @param conversion_procs [Hash] see map_columns!
|
82
82
|
# @param header_mappings [Hash] see map_headers!
|
83
83
|
# @param header_conversion_proc [Proc] see map_headers!
|
84
84
|
def initialize(data, conversion_procs = NULL_CONVERSIONS.dup, header_mappings = {}, header_conversion_proc = nil)
|
85
|
-
raise ArgumentError, 'data must be a Core::
|
85
|
+
raise ArgumentError, 'data must be a Core::Test::DataTable' unless data.is_a? Core::Test::DataTable
|
86
86
|
ast_table = data
|
87
87
|
# Verify that it's square
|
88
88
|
ast_table.transpose
|
@@ -111,7 +111,7 @@ module Cucumber
|
|
111
111
|
# registered with #map_column! and #map_headers!.
|
112
112
|
#
|
113
113
|
def dup
|
114
|
-
self.class.new(Core::
|
114
|
+
self.class.new(Core::Test::DataTable.new(raw), @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
|
115
115
|
end
|
116
116
|
|
117
117
|
# Returns a new, transposed table. Example:
|
@@ -126,7 +126,7 @@ module Cucumber
|
|
126
126
|
# | 4 | 2 |
|
127
127
|
#
|
128
128
|
def transpose
|
129
|
-
self.class.new(Core::
|
129
|
+
self.class.new(Core::Test::DataTable.new(raw.transpose), @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
|
130
130
|
end
|
131
131
|
|
132
132
|
# Converts this table into an Array of Hash where the keys of each
|
@@ -160,8 +160,8 @@ module Cucumber
|
|
160
160
|
#
|
161
161
|
def symbolic_hashes
|
162
162
|
@symbolic_hashes ||=
|
163
|
-
|
164
|
-
Hash[string_hash.map{ |a,b| [symbolize_key(a), b] }]
|
163
|
+
hashes.map do |string_hash|
|
164
|
+
Hash[string_hash.map { |a, b| [symbolize_key(a), b] }]
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -180,7 +180,7 @@ module Cucumber
|
|
180
180
|
def rows_hash
|
181
181
|
return @rows_hash if @rows_hash
|
182
182
|
verify_table_width(2)
|
183
|
-
@rows_hash =
|
183
|
+
@rows_hash = transpose.hashes[0]
|
184
184
|
end
|
185
185
|
|
186
186
|
# Gets the raw data of this table. For example, a Table built from
|
@@ -200,7 +200,7 @@ module Cucumber
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def column_names #:nodoc:
|
203
|
-
@
|
203
|
+
@column_names ||= cell_matrix[0].map(&:value)
|
204
204
|
end
|
205
205
|
|
206
206
|
def rows
|
@@ -260,7 +260,7 @@ module Cucumber
|
|
260
260
|
# table.hashes.keys
|
261
261
|
# # => ['phone number', 'ADDRESS']
|
262
262
|
#
|
263
|
-
def map_headers!(mappings={}, &block)
|
263
|
+
def map_headers!(mappings = {}, &block)
|
264
264
|
# TODO: Remove this method for 2.0
|
265
265
|
clear_cache!
|
266
266
|
@header_mappings = mappings
|
@@ -268,8 +268,8 @@ module Cucumber
|
|
268
268
|
end
|
269
269
|
|
270
270
|
# Returns a new Table where the headers are redefined. See #map_headers!
|
271
|
-
def map_headers(mappings={}, &block)
|
272
|
-
self.class.new(Core::
|
271
|
+
def map_headers(mappings = {}, &block)
|
272
|
+
self.class.new(Core::Test::DataTable.new(raw), @conversion_procs.dup, mappings, block)
|
273
273
|
end
|
274
274
|
|
275
275
|
# Change how #hashes converts column values. The +column_name+ argument identifies the column
|
@@ -284,17 +284,17 @@ module Cucumber
|
|
284
284
|
# end
|
285
285
|
# end
|
286
286
|
#
|
287
|
-
def map_column!(column_name, strict=true, &conversion_proc)
|
287
|
+
def map_column!(column_name, strict = true, &conversion_proc)
|
288
288
|
# TODO: Remove this method for 2.0
|
289
|
-
@conversion_procs[column_name.to_s] = { :
|
289
|
+
@conversion_procs[column_name.to_s] = { strict: strict, proc: conversion_proc }
|
290
290
|
self
|
291
291
|
end
|
292
292
|
|
293
293
|
# Returns a new Table with an additional column mapping. See #map_column!
|
294
|
-
def map_column(column_name, strict=true, &conversion_proc)
|
294
|
+
def map_column(column_name, strict = true, &conversion_proc)
|
295
295
|
conversion_procs = @conversion_procs.dup
|
296
|
-
conversion_procs[column_name.to_s] = { :
|
297
|
-
self.class.new(Core::
|
296
|
+
conversion_procs[column_name.to_s] = { strict: strict, proc: conversion_proc }
|
297
|
+
self.class.new(Core::Test::DataTable.new(raw), conversion_procs, @header_mappings.dup, @header_conversion_proc)
|
298
298
|
end
|
299
299
|
|
300
300
|
# Compares +other_table+ to self. If +other_table+ contains columns
|
@@ -333,7 +333,7 @@ module Cucumber
|
|
333
333
|
# Calling this method is particularly useful in <tt>Then</tt> steps that take
|
334
334
|
# a Table argument, if you want to compare that table to some actual values.
|
335
335
|
#
|
336
|
-
def diff!(other_table, options={})
|
336
|
+
def diff!(other_table, options = {})
|
337
337
|
other_table = ensure_table(other_table)
|
338
338
|
other_table.convert_headers!
|
339
339
|
other_table.convert_columns!
|
@@ -352,9 +352,13 @@ module Cucumber
|
|
352
352
|
end
|
353
353
|
end
|
354
354
|
|
355
|
-
def to_hash
|
356
|
-
|
357
|
-
|
355
|
+
def to_hash
|
356
|
+
cells_rows.map { |cells| cells.map(&:value) }
|
357
|
+
end
|
358
|
+
|
359
|
+
def cells_to_hash(cells) #:nodoc:
|
360
|
+
hash = Hash.new do |hash_inner, key|
|
361
|
+
hash_inner[key.to_s] if key.is_a?(Symbol)
|
358
362
|
end
|
359
363
|
column_names.each_with_index do |column_name, column_index|
|
360
364
|
hash[column_name] = cells.value(column_index)
|
@@ -367,19 +371,21 @@ module Cucumber
|
|
367
371
|
end
|
368
372
|
|
369
373
|
def verify_column(column_name) #:nodoc:
|
370
|
-
raise %
|
374
|
+
raise %(The column named "#{column_name}" does not exist) unless raw[0].include?(column_name)
|
371
375
|
end
|
372
376
|
|
373
377
|
def verify_table_width(width) #:nodoc:
|
374
|
-
raise %
|
378
|
+
raise %(The table must have exactly #{width} columns) unless raw[0].size == width
|
375
379
|
end
|
376
380
|
|
377
|
-
|
378
|
-
|
381
|
+
# TODO: remove the below function if it's not actually being used.
|
382
|
+
# Nothing else in this repo calls it.
|
383
|
+
def text?(text) #:nodoc:
|
384
|
+
raw.flatten.compact.detect { |cell_value| cell_value.index(text) }
|
379
385
|
end
|
380
386
|
|
381
387
|
def cells_rows #:nodoc:
|
382
|
-
@rows ||= cell_matrix.map do |cell_row|
|
388
|
+
@rows ||= cell_matrix.map do |cell_row| # rubocop:disable Naming/MemoizedInstanceVariableName
|
383
389
|
Cells.new(self, cell_row)
|
384
390
|
end
|
385
391
|
end
|
@@ -399,26 +405,48 @@ module Cucumber
|
|
399
405
|
end
|
400
406
|
|
401
407
|
def to_s(options = {}) #:nodoc:
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
options = {:color => true, :indent => 2, :prefixes => TO_S_PREFIXES}.merge(options)
|
406
|
-
io = StringIO.new
|
407
|
-
|
408
|
-
c = Cucumber::Term::ANSIColor.coloring?
|
409
|
-
Cucumber::Term::ANSIColor.coloring = options[:color]
|
410
|
-
runtime = Struct.new(:configuration).new(Configuration.new)
|
411
|
-
formatter = Formatter::Pretty.new(runtime, io, options)
|
412
|
-
formatter.instance_variable_set('@indent', options[:indent])
|
413
|
-
Formatter::LegacyApi::Ast::MultilineArg.for(self).accept(Formatter::Fanout.new([formatter]))
|
414
|
-
Cucumber::Term::ANSIColor.coloring = c
|
415
|
-
io.rewind
|
416
|
-
s = "\n" + io.read + (' ' * (options[:indent] - 2))
|
417
|
-
s
|
408
|
+
indentation = options.key?(:indent) ? options[:indent] : 2
|
409
|
+
prefixes = options.key?(:prefixes) ? options[:prefixes] : TO_S_PREFIXES
|
410
|
+
DataTablePrinter.new(self, indentation, prefixes).to_s
|
418
411
|
end
|
419
412
|
|
420
|
-
|
421
|
-
|
413
|
+
class DataTablePrinter #:nodoc:
|
414
|
+
include Cucumber::Gherkin::Formatter::Escaping
|
415
|
+
attr_reader :data_table, :indentation, :prefixes
|
416
|
+
private :data_table, :indentation, :prefixes
|
417
|
+
|
418
|
+
def initialize(data_table, indentation, prefixes)
|
419
|
+
@data_table = data_table
|
420
|
+
@indentation = indentation
|
421
|
+
@prefixes = prefixes
|
422
|
+
end
|
423
|
+
|
424
|
+
def to_s
|
425
|
+
leading_row = "\n"
|
426
|
+
end_indentation = indentation - 2
|
427
|
+
trailing_row = "\n" + (' ' * end_indentation)
|
428
|
+
table_rows = data_table.cell_matrix.map { |row| format_row(row) }
|
429
|
+
leading_row + table_rows.join("\n") + trailing_row
|
430
|
+
end
|
431
|
+
|
432
|
+
private
|
433
|
+
|
434
|
+
def format_row(row)
|
435
|
+
row_start = (' ' * indentation) + '| '
|
436
|
+
row_end = '|'
|
437
|
+
cells = row.map.with_index do |cell, i|
|
438
|
+
format_cell(cell, data_table.col_width(i))
|
439
|
+
end
|
440
|
+
row_start + cells.join('| ') + row_end
|
441
|
+
end
|
442
|
+
|
443
|
+
def format_cell(cell, col_width)
|
444
|
+
cell_text = escape_cell(cell.value.to_s)
|
445
|
+
cell_text_width = cell_text.unpack('U*').length
|
446
|
+
padded_text = cell_text + (' ' * (col_width - cell_text_width))
|
447
|
+
prefix = prefixes[cell.status]
|
448
|
+
"#{prefix}#{padded_text} "
|
449
|
+
end
|
422
450
|
end
|
423
451
|
|
424
452
|
def columns #:nodoc:
|
@@ -446,7 +474,11 @@ module Cucumber
|
|
446
474
|
|
447
475
|
def create_cell_matrix(ast_table) #:nodoc:
|
448
476
|
ast_table.raw.map do |raw_row|
|
449
|
-
line =
|
477
|
+
line = begin
|
478
|
+
raw_row.line
|
479
|
+
rescue StandardError
|
480
|
+
-1
|
481
|
+
end
|
450
482
|
raw_row.map do |raw_cell|
|
451
483
|
Cell.new(raw_cell, self, line)
|
452
484
|
end
|
@@ -476,22 +508,20 @@ module Cucumber
|
|
476
508
|
end
|
477
509
|
|
478
510
|
@header_mappings.each_pair do |pre, post|
|
479
|
-
mapped_cells = header_cells.
|
511
|
+
mapped_cells = header_cells.reject { |cell| cell.value.match(pre).nil? }
|
480
512
|
raise "No headers matched #{pre.inspect}" if mapped_cells.empty?
|
481
513
|
raise "#{mapped_cells.length} headers matched #{pre.inspect}: #{mapped_cells.map(&:value).inspect}" if mapped_cells.length > 1
|
482
514
|
mapped_cells[0].value = post
|
483
|
-
if @conversion_procs.key?(pre)
|
484
|
-
@conversion_procs[post] = @conversion_procs.delete(pre)
|
485
|
-
end
|
515
|
+
@conversion_procs[post] = @conversion_procs.delete(pre) if @conversion_procs.key?(pre)
|
486
516
|
end
|
487
517
|
end
|
488
518
|
|
489
519
|
def clear_cache! #:nodoc:
|
490
|
-
@hashes = @rows_hash = @
|
520
|
+
@hashes = @rows_hash = @column_names = @rows = @columns = nil
|
491
521
|
end
|
492
522
|
|
493
523
|
def ensure_table(table_or_array) #:nodoc:
|
494
|
-
return table_or_array if DataTable
|
524
|
+
return table_or_array if DataTable == table_or_array.class
|
495
525
|
DataTable.from(table_or_array)
|
496
526
|
end
|
497
527
|
|
@@ -507,7 +537,8 @@ module Cucumber
|
|
507
537
|
attr_reader :exception
|
508
538
|
|
509
539
|
def initialize(table, cells)
|
510
|
-
@table
|
540
|
+
@table = table
|
541
|
+
@cells = cells
|
511
542
|
end
|
512
543
|
|
513
544
|
def accept(visitor)
|
@@ -524,7 +555,7 @@ module Cucumber
|
|
524
555
|
end
|
525
556
|
|
526
557
|
def to_hash #:nodoc:
|
527
|
-
@to_hash ||= @table.
|
558
|
+
@to_hash ||= @table.cells_to_hash(self)
|
528
559
|
end
|
529
560
|
|
530
561
|
def value(n) #:nodoc:
|
@@ -554,7 +585,7 @@ module Cucumber
|
|
554
585
|
end
|
555
586
|
|
556
587
|
def width
|
557
|
-
map{|cell| cell.value ? escape_cell(cell.value.to_s).unpack('U*').length : 0}.max
|
588
|
+
map { |cell| cell.value ? escape_cell(cell.value.to_s).unpack('U*').length : 0 }.max
|
558
589
|
end
|
559
590
|
end
|
560
591
|
|
@@ -563,19 +594,21 @@ module Cucumber
|
|
563
594
|
attr_accessor :status, :value
|
564
595
|
|
565
596
|
def initialize(value, table, line)
|
566
|
-
@value
|
597
|
+
@value = value
|
598
|
+
@table = table
|
599
|
+
@line = line
|
567
600
|
end
|
568
601
|
|
569
602
|
def inspect!
|
570
603
|
@value = "(i) #{value.inspect}"
|
571
604
|
end
|
572
605
|
|
573
|
-
def ==(
|
574
|
-
SurplusCell
|
606
|
+
def ==(other)
|
607
|
+
SurplusCell == other.class || value == other.value
|
575
608
|
end
|
576
609
|
|
577
|
-
def eql?(
|
578
|
-
self ==
|
610
|
+
def eql?(other)
|
611
|
+
self == other
|
579
612
|
end
|
580
613
|
|
581
614
|
def hash
|
@@ -593,7 +626,7 @@ module Cucumber
|
|
593
626
|
:comment
|
594
627
|
end
|
595
628
|
|
596
|
-
def ==(
|
629
|
+
def ==(_other)
|
597
630
|
true
|
598
631
|
end
|
599
632
|
|