cucumber 2.0.0.beta.2 → 2.0.0.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +25 -7
- data/cucumber.gemspec +1 -1
- data/features/docs/defining_steps/nested_steps.feature +0 -1
- data/features/docs/defining_steps/printing_messages.feature +1 -0
- data/features/docs/defining_steps/table_diffing.feature +9 -4
- data/features/docs/exception_in_after_step_hook.feature +1 -0
- data/features/docs/formatters/json_formatter.feature +51 -4
- data/features/docs/formatters/junit_formatter.feature +1 -0
- data/features/docs/gherkin/outlines.feature +4 -0
- data/features/docs/output_from_hooks.feature +128 -0
- data/features/docs/wire_protocol_table_diffing.feature +6 -2
- data/features/docs/writing_support_code/after_hooks.feature +56 -0
- data/lib/cucumber/cli/configuration.rb +0 -4
- data/lib/cucumber/cli/main.rb +0 -1
- data/lib/cucumber/cli/options.rb +0 -3
- data/lib/cucumber/formatter/console.rb +3 -1
- data/lib/cucumber/formatter/debug.rb +4 -0
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +26 -3
- data/lib/cucumber/formatter/html.rb +6 -2
- data/lib/cucumber/formatter/usage.rb +1 -58
- data/lib/cucumber/mappings.rb +25 -7
- data/lib/cucumber/multiline_argument.rb +40 -82
- data/lib/cucumber/multiline_argument/data_table.rb +719 -0
- data/lib/cucumber/multiline_argument/doc_string.rb +10 -0
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/rb_support/rb_world.rb +2 -4
- data/lib/cucumber/reports/legacy_formatter.rb +69 -22
- data/lib/cucumber/runtime.rb +0 -39
- data/lib/cucumber/runtime/for_programming_languages.rb +12 -10
- data/lib/cucumber/runtime/support_code.rb +11 -4
- data/lib/cucumber/wire_support/wire_protocol/requests.rb +2 -2
- data/spec/cucumber/formatter/pretty_spec.rb +5 -5
- data/spec/cucumber/mappings_spec.rb +137 -8
- data/spec/cucumber/multiline_argument/data_table_spec.rb +508 -0
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +3 -3
- data/spec/cucumber/rb_support/snippet_spec.rb +1 -1
- data/spec/cucumber/runtime/for_programming_languages_spec.rb +16 -12
- metadata +13 -6
- data/lib/cucumber/runtime/features_loader.rb +0 -62
data/lib/cucumber/cli/main.rb
CHANGED
data/lib/cucumber/cli/options.rb
CHANGED
@@ -223,9 +223,6 @@ module Cucumber
|
|
223
223
|
opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") do
|
224
224
|
@options[:expand] = true
|
225
225
|
end
|
226
|
-
opts.on("--dotcucumber DIR", "Write metadata to DIR") do |dir|
|
227
|
-
@options[:dotcucumber] = dir
|
228
|
-
end
|
229
226
|
opts.on("--order TYPE[:SEED]", "Run examples in the specified order. Available types:",
|
230
227
|
*<<-TEXT.split("\n")) do |order|
|
231
228
|
[defined] Run scenarios in the order they were defined (default).
|
@@ -139,7 +139,9 @@ module Cucumber
|
|
139
139
|
|
140
140
|
unknown_programming_language = runtime.unknown_programming_language?
|
141
141
|
snippets = undefined.map do |step|
|
142
|
-
step_name = Undefined === step.exception ? step.exception.step_name : step.name
|
142
|
+
# step_name = Undefined === step.exception ? step.exception.step_name : step.name
|
143
|
+
# TODO: This probably won't work for nested steps :( See above for old code.
|
144
|
+
step_name = step.name
|
143
145
|
@runtime.snippet_text(step.actual_keyword, step_name, step.multiline_arg)
|
144
146
|
end.compact.uniq
|
145
147
|
|
@@ -10,6 +10,8 @@ module Cucumber
|
|
10
10
|
@gf = gherkin_formatter
|
11
11
|
@print_empty_match = print_empty_match
|
12
12
|
@options = options
|
13
|
+
@delayed_messages = []
|
14
|
+
@delayed_embeddings = []
|
13
15
|
end
|
14
16
|
|
15
17
|
def before_feature(feature)
|
@@ -19,10 +21,12 @@ module Cucumber
|
|
19
21
|
|
20
22
|
def before_background(background)
|
21
23
|
@outline = false
|
24
|
+
@before_steps = true
|
22
25
|
@gf.background(background.gherkin_statement)
|
23
26
|
end
|
24
27
|
|
25
28
|
def before_feature_element(feature_element)
|
29
|
+
@before_steps = true
|
26
30
|
case(feature_element)
|
27
31
|
when Core::Ast::Scenario
|
28
32
|
@outline = false
|
@@ -65,6 +69,8 @@ module Cucumber
|
|
65
69
|
def before_step(step)
|
66
70
|
unless @outline and @options[:expand]
|
67
71
|
@gf.step(step.gherkin_statement)
|
72
|
+
pass_delayed_output
|
73
|
+
@before_steps = false
|
68
74
|
else
|
69
75
|
if @in_instantiated_scenario
|
70
76
|
@current_step_hash = to_hash(step.gherkin_statement)
|
@@ -111,9 +117,11 @@ module Cucumber
|
|
111
117
|
@current_step_hash['comments'],
|
112
118
|
@current_step_hash['keyword'],
|
113
119
|
step_match.format_args(),
|
114
|
-
|
120
|
+
file_colon_line.split(':')[1].to_i,
|
115
121
|
@current_step_hash['rows'],
|
116
122
|
@current_step_hash['doc_string']))
|
123
|
+
pass_delayed_output
|
124
|
+
@before_steps = false
|
117
125
|
@gf.match(@current_match)
|
118
126
|
@gf.result(@current_result)
|
119
127
|
end
|
@@ -159,11 +167,19 @@ module Cucumber
|
|
159
167
|
if defined?(JRUBY_VERSION)
|
160
168
|
data = data.to_java_bytes
|
161
169
|
end
|
162
|
-
@
|
170
|
+
unless @before_steps
|
171
|
+
@gf.embedding(mime_type, data)
|
172
|
+
else
|
173
|
+
@delayed_embeddings.push [mime_type, data]
|
174
|
+
end
|
163
175
|
end
|
164
176
|
|
165
177
|
def puts(message)
|
166
|
-
@
|
178
|
+
unless @before_steps
|
179
|
+
@gf.write(message)
|
180
|
+
else
|
181
|
+
@delayed_messages.push message
|
182
|
+
end
|
167
183
|
end
|
168
184
|
|
169
185
|
private
|
@@ -175,6 +191,13 @@ module Cucumber
|
|
175
191
|
gherkin_statement.to_hash
|
176
192
|
end
|
177
193
|
end
|
194
|
+
|
195
|
+
def pass_delayed_output
|
196
|
+
@delayed_messages.each { |message| @gf.write(message) }
|
197
|
+
@delayed_embeddings.each { |embed_data| @gf.embedding(embed_data[0], embed_data[1]) }
|
198
|
+
@delayed_messages = []
|
199
|
+
@delayed_embeddings = []
|
200
|
+
end
|
178
201
|
end
|
179
202
|
end
|
180
203
|
end
|
@@ -12,7 +12,7 @@ module Cucumber
|
|
12
12
|
Cucumber::Core::Ast::Scenario => 'scenario',
|
13
13
|
Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
|
14
14
|
}
|
15
|
-
AST_DATA_TABLE = Cucumber::
|
15
|
+
AST_DATA_TABLE = Cucumber::Reports::Legacy::Ast::MultilineArg::DataTable
|
16
16
|
|
17
17
|
include ERB::Util # for the #h method
|
18
18
|
include Duration
|
@@ -618,8 +618,12 @@ module Cucumber
|
|
618
618
|
|
619
619
|
def lines_around(file, line)
|
620
620
|
if File.file?(file)
|
621
|
+
begin
|
621
622
|
lines = File.open(file).read.split("\n")
|
622
|
-
|
623
|
+
rescue ArgumentError
|
624
|
+
return "# Couldn't get snippet for #{file}"
|
625
|
+
end
|
626
|
+
min = [0, line-3].max
|
623
627
|
max = [line+1, lines.length-1].min
|
624
628
|
selected_lines = []
|
625
629
|
selected_lines.join("\n")
|
@@ -21,36 +21,6 @@ module Cucumber
|
|
21
21
|
print_profile_information
|
22
22
|
end
|
23
23
|
|
24
|
-
def before_background(background)
|
25
|
-
@outline = false
|
26
|
-
end
|
27
|
-
|
28
|
-
def before_feature_element(feature_element)
|
29
|
-
case(feature_element)
|
30
|
-
when Core::Ast::Scenario
|
31
|
-
@outline = false
|
32
|
-
when Core::Ast::ScenarioOutline
|
33
|
-
@outline = true
|
34
|
-
if @options[:expand]
|
35
|
-
@in_instantiated_scenario = false
|
36
|
-
end
|
37
|
-
else
|
38
|
-
raise "Bad type: #{feature_element.class}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def scenario_name(keyword, name, file_colon_line, source_indent)
|
43
|
-
if @outline and @in_instantiated_scenario
|
44
|
-
if @new_example_table
|
45
|
-
@example_row = 1
|
46
|
-
@new_example_table = false
|
47
|
-
else
|
48
|
-
@example_row += 1
|
49
|
-
end
|
50
|
-
@example_line = @current_example_rows[@example_row].to_hash['line']
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
24
|
def before_step(step)
|
55
25
|
@step = step
|
56
26
|
@start_time = Time.now
|
@@ -65,30 +35,17 @@ module Cucumber
|
|
65
35
|
unless step_definition.nil? # nil if it's from a scenario outline
|
66
36
|
stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
|
67
37
|
|
68
|
-
file_colon_line = @step.file_colon_line
|
69
|
-
if @outline and @in_instantiated_scenario
|
70
|
-
file_colon_line = replace_line_number(@step.file_colon_line, @example_line)
|
71
|
-
end
|
72
|
-
|
73
38
|
@stepdef_to_match[stepdef_key] << {
|
74
39
|
:keyword => keyword,
|
75
40
|
:step_match => step_match,
|
76
41
|
:status => status,
|
77
|
-
:file_colon_line => file_colon_line,
|
42
|
+
:file_colon_line => @step.file_colon_line,
|
78
43
|
:duration => @duration
|
79
44
|
}
|
80
45
|
end
|
81
46
|
super
|
82
47
|
end
|
83
48
|
|
84
|
-
def before_examples(examples)
|
85
|
-
if @options[:expand]
|
86
|
-
@in_instantiated_scenario = true
|
87
|
-
@new_example_table = true
|
88
|
-
@current_example_rows = to_hash(examples.gherkin_statement)['rows']
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
49
|
def print_summary(features)
|
93
50
|
add_unused_stepdefs
|
94
51
|
aggregate_info
|
@@ -176,20 +133,6 @@ module Cucumber
|
|
176
133
|
@stepdef_to_match[stepdef_key] = []
|
177
134
|
end
|
178
135
|
end
|
179
|
-
|
180
|
-
private
|
181
|
-
|
182
|
-
def replace_line_number(file_colon_line, line)
|
183
|
-
file_colon_line.split(':')[0] + ':' + line.to_s
|
184
|
-
end
|
185
|
-
|
186
|
-
def to_hash(gherkin_statement)
|
187
|
-
if defined?(JRUBY_VERSION)
|
188
|
-
gherkin_statement.toMap()
|
189
|
-
else
|
190
|
-
gherkin_statement.to_hash
|
191
|
-
end
|
192
|
-
end
|
193
136
|
end
|
194
137
|
end
|
195
138
|
end
|
data/lib/cucumber/mappings.rb
CHANGED
@@ -68,13 +68,13 @@ module Cucumber
|
|
68
68
|
|
69
69
|
def map_test_case_hooks(mapper)
|
70
70
|
ruby.hooks_for(:before, scenario).each do |hook|
|
71
|
-
mapper.before do
|
72
|
-
hook.invoke('Before', scenario)
|
71
|
+
mapper.before do |result|
|
72
|
+
hook.invoke('Before', scenario.with_result(result))
|
73
73
|
end
|
74
74
|
end
|
75
75
|
ruby.hooks_for(:after, scenario).each do |hook|
|
76
|
-
mapper.after do
|
77
|
-
hook.invoke('After', scenario)
|
76
|
+
mapper.after do |result|
|
77
|
+
hook.invoke('After', scenario.with_result(result))
|
78
78
|
end
|
79
79
|
end
|
80
80
|
ruby.hooks_for(:around, scenario).each do |hook|
|
@@ -86,9 +86,10 @@ module Cucumber
|
|
86
86
|
|
87
87
|
# adapts our test_case to look like the Cucumber Runtime's old Scenario
|
88
88
|
class TestCase
|
89
|
-
def initialize(test_case, feature)
|
89
|
+
def initialize(test_case, feature, result = Core::Test::Result::Unknown.new)
|
90
90
|
@test_case = test_case
|
91
91
|
@feature = feature
|
92
|
+
@result = result
|
92
93
|
end
|
93
94
|
|
94
95
|
def accept_hook?(hook)
|
@@ -96,7 +97,7 @@ module Cucumber
|
|
96
97
|
end
|
97
98
|
|
98
99
|
def failed?
|
99
|
-
|
100
|
+
@result.failed?
|
100
101
|
end
|
101
102
|
|
102
103
|
def language
|
@@ -111,6 +112,11 @@ module Cucumber
|
|
111
112
|
@test_case.name
|
112
113
|
end
|
113
114
|
|
115
|
+
def title
|
116
|
+
warn("deprecated: call #name instead")
|
117
|
+
name
|
118
|
+
end
|
119
|
+
|
114
120
|
def source_tags
|
115
121
|
#warn('deprecated: call #tags instead')
|
116
122
|
tags
|
@@ -123,12 +129,24 @@ module Cucumber
|
|
123
129
|
def tags
|
124
130
|
@test_case.tags
|
125
131
|
end
|
132
|
+
|
133
|
+
def outline?
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
def with_result(result)
|
138
|
+
self.class.new(@test_case, @feature, result)
|
139
|
+
end
|
126
140
|
end
|
127
141
|
|
128
142
|
class Scenario < TestCase
|
129
143
|
end
|
130
144
|
|
131
145
|
class ScenarioOutlineExample < TestCase
|
146
|
+
def outline?
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
132
150
|
def scenario_outline
|
133
151
|
self
|
134
152
|
end
|
@@ -204,7 +222,7 @@ module Cucumber
|
|
204
222
|
|
205
223
|
private
|
206
224
|
def map_step(node, step_match)
|
207
|
-
multiline_arg = MultilineArgument.
|
225
|
+
multiline_arg = MultilineArgument.from_core(node.multiline_arg)
|
208
226
|
mapper.map { step_match.invoke(multiline_arg) }
|
209
227
|
end
|
210
228
|
|
@@ -1,104 +1,62 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
require 'cucumber/multiline_argument/data_table'
|
3
|
+
require 'cucumber/multiline_argument/doc_string'
|
4
|
+
require 'gherkin/rubify'
|
5
|
+
|
2
6
|
module Cucumber
|
3
7
|
module MultilineArgument
|
4
|
-
|
5
|
-
Builder.new(core_multiline_arg).result
|
6
|
-
end
|
7
|
-
|
8
|
-
class Builder
|
9
|
-
def initialize(multiline_arg)
|
10
|
-
multiline_arg.describe_to self
|
11
|
-
end
|
8
|
+
extend Gherkin::Rubify
|
12
9
|
|
13
|
-
|
14
|
-
|
10
|
+
class << self
|
11
|
+
def from_core(node)
|
12
|
+
builder.wrap(node)
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
|
15
|
+
def from(argument, location=nil)
|
16
|
+
location ||= Core::Ast::Location.of_caller
|
17
|
+
argument = rubify(argument)
|
18
|
+
case argument
|
19
|
+
when String
|
20
|
+
doc_string(argument, 'text/plain', location)
|
21
|
+
when Array
|
22
|
+
location = location.on_line(argument.first.line..argument.last.line)
|
23
|
+
data_table(argument.map{ |row| row.cells }, location)
|
24
|
+
when DataTable, DocString, None
|
25
|
+
argument
|
26
|
+
when nil
|
27
|
+
None.new
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Don't know how to convert #{argument.class} #{argument.inspect} into a MultilineArgument"
|
30
|
+
end
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
22
|
-
|
33
|
+
def doc_string(argument, content_type, location)
|
34
|
+
builder.doc_string(Core::Ast::DocString.new(argument, content_type, location))
|
23
35
|
end
|
24
|
-
end
|
25
36
|
|
26
|
-
|
27
|
-
|
28
|
-
array << self
|
37
|
+
def data_table(data, location)
|
38
|
+
builder.data_table(Core::Ast::DataTable.new(data, location))
|
29
39
|
end
|
30
|
-
end
|
31
40
|
|
32
|
-
|
33
|
-
def append_to(array)
|
34
|
-
array << self
|
35
|
-
end
|
41
|
+
private
|
36
42
|
|
37
|
-
def
|
38
|
-
|
43
|
+
def builder
|
44
|
+
@builder ||= Builder.new
|
39
45
|
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
require_diff_lcs
|
48
|
-
cell_matrix.extend(Diff::LCS)
|
49
|
-
|
50
|
-
changes = cell_matrix.diff(other_table_cell_matrix).flatten
|
51
|
-
|
52
|
-
return if changes.empty?
|
53
|
-
|
54
|
-
inserted = 0
|
55
|
-
missing = 0
|
56
|
-
|
57
|
-
changes.each do |change|
|
58
|
-
if(change.action == '-')
|
59
|
-
missing_row_pos = change.position + inserted
|
60
|
-
cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
|
61
|
-
|
62
|
-
missing += 1
|
63
|
-
else # '+'
|
64
|
-
inserted_row = change.element
|
65
|
-
inserted_row.each{|cell| cell.status = :comment}
|
66
|
-
|
67
|
-
insert_row_pos = change.position + missing
|
68
|
-
cell_matrix.insert(insert_row_pos, inserted_row)
|
69
|
-
|
70
|
-
inserted += 1
|
71
|
-
end
|
47
|
+
class Builder
|
48
|
+
def wrap(node)
|
49
|
+
@result = None.new
|
50
|
+
node.describe_to(self)
|
51
|
+
@result
|
72
52
|
end
|
73
53
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
def ensure_green! #:nodoc:
|
78
|
-
each_cell{|cell| cell.status = :passed}
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def ensure_table(table_or_array) #:nodoc:
|
84
|
-
return table_or_array if DataTable === table_or_array
|
85
|
-
DataTable.new(table_or_array)
|
86
|
-
end
|
87
|
-
|
88
|
-
def require_diff_lcs #:nodoc:
|
89
|
-
begin
|
90
|
-
require 'diff/lcs'
|
91
|
-
rescue LoadError => e
|
92
|
-
e.message << "\n Please gem install diff-lcs\n"
|
93
|
-
raise e
|
54
|
+
def doc_string(node, *args)
|
55
|
+
@result = DocString.new(node)
|
94
56
|
end
|
95
|
-
end
|
96
57
|
|
97
|
-
|
98
|
-
|
99
|
-
def initialize(table)
|
100
|
-
@table = table
|
101
|
-
super("Tables were not identical")
|
58
|
+
def data_table(node, *args)
|
59
|
+
@result = DataTable.new(node)
|
102
60
|
end
|
103
61
|
end
|
104
62
|
end
|