cucumber 2.0.0.beta.3 → 2.0.0.beta.4
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 +4 -4
- data/History.md +20 -3
- data/cucumber.gemspec +2 -1
- data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
- data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
- data/features/docs/formatters/debug_formatter.feature +24 -17
- data/features/docs/formatters/pretty_formatter.feature +42 -0
- data/features/docs/formatters/rerun_formatter.feature +3 -2
- data/lib/cucumber/cli/configuration.rb +3 -7
- data/lib/cucumber/cli/main.rb +1 -1
- data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
- data/lib/cucumber/filters/quit.rb +24 -0
- data/lib/cucumber/filters/randomizer.rb +36 -0
- data/lib/cucumber/filters/tag_limits.rb +40 -0
- data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
- data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
- data/lib/cucumber/formatter/console.rb +2 -2
- data/lib/cucumber/formatter/debug.rb +1 -8
- data/lib/cucumber/formatter/fanout.rb +27 -0
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -3
- data/lib/cucumber/formatter/html.rb +12 -4
- data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
- data/lib/cucumber/formatter/junit.rb +2 -2
- data/lib/cucumber/formatter/legacy_api/adapter.rb +1008 -0
- data/lib/cucumber/formatter/legacy_api/ast.rb +374 -0
- data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
- data/lib/cucumber/formatter/pretty.rb +4 -0
- data/lib/cucumber/formatter/rerun.rb +14 -88
- data/lib/cucumber/language_support/language_methods.rb +0 -54
- data/lib/cucumber/multiline_argument/data_table.rb +3 -4
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/runtime.rb +41 -107
- data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
- data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
- data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
- data/spec/cucumber/formatter/debug_spec.rb +39 -530
- data/spec/cucumber/formatter/html_spec.rb +56 -0
- data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +1902 -0
- data/spec/cucumber/formatter/pretty_spec.rb +128 -0
- data/spec/cucumber/formatter/rerun_spec.rb +106 -0
- data/spec/cucumber/formatter/spec_helper.rb +6 -2
- data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
- data/spec/cucumber/runtime_spec.rb +1 -5
- data/spec/spec_helper.rb +2 -0
- metadata +44 -29
- data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
- data/features/docs/output_from_hooks.feature +0 -128
- data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
- data/lib/cucumber/runtime/results.rb +0 -64
- data/lib/cucumber/runtime/tag_limits.rb +0 -15
- data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
- data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
- data/spec/cucumber/runtime/results_spec.rb +0 -88
@@ -0,0 +1,374 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Formatter
|
3
|
+
module LegacyApi
|
4
|
+
# Adapters to pass to the legacy API formatters that provide the interface
|
5
|
+
# of the old AST classes
|
6
|
+
module Ast
|
7
|
+
|
8
|
+
# Acts as a null object, or a base class
|
9
|
+
class Node
|
10
|
+
def initialize(node = nil)
|
11
|
+
@node = node
|
12
|
+
end
|
13
|
+
|
14
|
+
def accept(formatter)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :node
|
18
|
+
private :node
|
19
|
+
end
|
20
|
+
|
21
|
+
# Null object for HeaderRow language.
|
22
|
+
# ExampleTableRow#keyword is never called on them,
|
23
|
+
# but this will pass silently if it happens anyway
|
24
|
+
class NullLanguage
|
25
|
+
def method_missing(*args, &block)
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_ary
|
30
|
+
['']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class HookResultCollection
|
35
|
+
def initialize
|
36
|
+
@children = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def accept(formatter)
|
40
|
+
@children.each { |child| child.accept(formatter) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def send_output_to(formatter)
|
44
|
+
@children.each { |child| child.send_output_to(formatter) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def describe_exception_to(formatter)
|
48
|
+
@children.each { |child| child.describe_exception_to(formatter) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def <<(child)
|
52
|
+
@children << child
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Comments = Struct.new(:comments) do
|
57
|
+
def accept(formatter)
|
58
|
+
return if comments.empty?
|
59
|
+
formatter.before_comment comments
|
60
|
+
comments.each do |comment|
|
61
|
+
formatter.comment_line comment.to_s.strip
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class HookResult
|
67
|
+
def initialize(result, messages, embeddings)
|
68
|
+
@result, @messages, @embeddings = result, messages, embeddings
|
69
|
+
@already_accepted = false
|
70
|
+
end
|
71
|
+
|
72
|
+
def accept(formatter)
|
73
|
+
unless @already_accepted
|
74
|
+
send_output_to(formatter)
|
75
|
+
describe_exception_to(formatter)
|
76
|
+
end
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def send_output_to(formatter)
|
81
|
+
unless @already_accepted
|
82
|
+
@messages.each { |message| formatter.puts(message) }
|
83
|
+
@embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def describe_exception_to(formatter)
|
88
|
+
unless @already_accepted
|
89
|
+
@result.describe_exception_to(formatter)
|
90
|
+
@already_accepted = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
StepInvocation = Struct.new(:step_match,
|
96
|
+
:status,
|
97
|
+
:duration,
|
98
|
+
:exception,
|
99
|
+
:indent,
|
100
|
+
:background,
|
101
|
+
:step,
|
102
|
+
:messages,
|
103
|
+
:embeddings) do
|
104
|
+
extend Forwardable
|
105
|
+
|
106
|
+
def_delegators :step, :keyword, :name, :multiline_arg, :location, :gherkin_statement
|
107
|
+
|
108
|
+
def accept(formatter)
|
109
|
+
formatter.before_step(self)
|
110
|
+
messages.each { |message| formatter.puts(message) }
|
111
|
+
embeddings.each { |embedding| embedding.send_to_formatter(formatter) }
|
112
|
+
formatter.before_step_result *step_result_attributes
|
113
|
+
print_step_name(formatter)
|
114
|
+
Ast::MultilineArg.for(multiline_arg).accept(formatter)
|
115
|
+
print_exception(formatter)
|
116
|
+
formatter.after_step_result *step_result_attributes
|
117
|
+
formatter.after_step(self)
|
118
|
+
end
|
119
|
+
|
120
|
+
def step_result_attributes
|
121
|
+
[keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line]
|
122
|
+
end
|
123
|
+
|
124
|
+
def failed?
|
125
|
+
status != :passed
|
126
|
+
end
|
127
|
+
|
128
|
+
def passed?
|
129
|
+
status == :passed
|
130
|
+
end
|
131
|
+
|
132
|
+
def dom_id
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
def actual_keyword
|
137
|
+
# TODO: This should return the keyword for the snippet
|
138
|
+
# `actual_keyword` translates 'And', 'But', etc. to 'Given', 'When',
|
139
|
+
# 'Then' as appropriate
|
140
|
+
"Given"
|
141
|
+
end
|
142
|
+
|
143
|
+
def file_colon_line
|
144
|
+
location.to_s
|
145
|
+
end
|
146
|
+
|
147
|
+
def backtrace_line
|
148
|
+
step_match.backtrace_line
|
149
|
+
end
|
150
|
+
|
151
|
+
def step_invocation
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def source_indent
|
158
|
+
indent.of(self)
|
159
|
+
end
|
160
|
+
|
161
|
+
def print_step_name(formatter)
|
162
|
+
formatter.step_name(
|
163
|
+
keyword,
|
164
|
+
step_match,
|
165
|
+
status,
|
166
|
+
source_indent,
|
167
|
+
background,
|
168
|
+
location.to_s)
|
169
|
+
end
|
170
|
+
|
171
|
+
def print_exception(formatter)
|
172
|
+
return unless exception
|
173
|
+
raise exception if ENV['FAIL_FAST']
|
174
|
+
formatter.exception(exception, status)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class StepInvocations < Array
|
179
|
+
def failed?
|
180
|
+
any?(&:failed?)
|
181
|
+
end
|
182
|
+
|
183
|
+
def passed?
|
184
|
+
all?(&:passed?)
|
185
|
+
end
|
186
|
+
|
187
|
+
def status
|
188
|
+
return :passed if passed?
|
189
|
+
failed_step.status
|
190
|
+
end
|
191
|
+
|
192
|
+
def exception
|
193
|
+
failed_step.exception if failed_step
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def failed_step
|
199
|
+
detect(&:failed?)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class DataTableRow
|
204
|
+
def initialize(row, line)
|
205
|
+
@values = row
|
206
|
+
@line = line
|
207
|
+
end
|
208
|
+
|
209
|
+
def dom_id
|
210
|
+
"row_#{line}"
|
211
|
+
end
|
212
|
+
|
213
|
+
def accept(formatter)
|
214
|
+
formatter.before_table_row(self)
|
215
|
+
values.each do |value|
|
216
|
+
formatter.before_table_cell(value)
|
217
|
+
formatter.table_cell_value(value, status)
|
218
|
+
formatter.after_table_cell(value)
|
219
|
+
end
|
220
|
+
formatter.after_table_row(self)
|
221
|
+
end
|
222
|
+
|
223
|
+
def status
|
224
|
+
:skipped
|
225
|
+
end
|
226
|
+
|
227
|
+
def exception
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
|
231
|
+
attr_reader :values, :line
|
232
|
+
private :values, :line
|
233
|
+
end
|
234
|
+
|
235
|
+
ExampleTableRow = Struct.new(:exception, :status, :cells, :location, :language) do
|
236
|
+
def name
|
237
|
+
'| ' + cells.join(' | ') + ' |'
|
238
|
+
end
|
239
|
+
|
240
|
+
def failed?
|
241
|
+
status == :failed
|
242
|
+
end
|
243
|
+
|
244
|
+
def line
|
245
|
+
location.line
|
246
|
+
end
|
247
|
+
|
248
|
+
def keyword
|
249
|
+
# This method is only called when used for the scenario name line with
|
250
|
+
# the expand option, and on that line the keyword is "Scenario"
|
251
|
+
language.keywords('scenario')[0]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class LegacyTableRow < DataTableRow
|
256
|
+
def accept(formatter)
|
257
|
+
formatter.before_table_row(self)
|
258
|
+
values.each do |value|
|
259
|
+
formatter.before_table_cell(value.value)
|
260
|
+
formatter.table_cell_value(value.value, value.status)
|
261
|
+
formatter.after_table_cell(value.value)
|
262
|
+
end
|
263
|
+
formatter.after_table_row(self)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
Tags = Struct.new(:tags) do
|
268
|
+
def accept(formatter)
|
269
|
+
formatter.before_tags tags
|
270
|
+
tags.each do |tag|
|
271
|
+
formatter.tag_name tag.name
|
272
|
+
end
|
273
|
+
formatter.after_tags tags
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
Scenario = Struct.new(:status, :name, :location) do
|
278
|
+
def backtrace_line(step_name = "#{name}", line = self.location.line)
|
279
|
+
"#{location.on_line(line)}:in `#{step_name}'"
|
280
|
+
end
|
281
|
+
|
282
|
+
def failed?
|
283
|
+
:failed == status
|
284
|
+
end
|
285
|
+
|
286
|
+
def line
|
287
|
+
location.line
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
ScenarioOutline = Struct.new(:status, :name, :location) do
|
292
|
+
def backtrace_line(step_name = "#{name}", line = self.location.line)
|
293
|
+
"#{location.on_line(line)}:in `#{step_name}'"
|
294
|
+
end
|
295
|
+
|
296
|
+
def failed?
|
297
|
+
:failed == status
|
298
|
+
end
|
299
|
+
|
300
|
+
def line
|
301
|
+
location.line
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
module MultilineArg
|
306
|
+
class << self
|
307
|
+
def for(node)
|
308
|
+
Builder.new(node).result
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class Builder
|
313
|
+
def initialize(node)
|
314
|
+
node.describe_to(self)
|
315
|
+
end
|
316
|
+
|
317
|
+
def doc_string(node)
|
318
|
+
@result = DocString.new(node)
|
319
|
+
end
|
320
|
+
|
321
|
+
def data_table(node)
|
322
|
+
@result = DataTable.new(node)
|
323
|
+
end
|
324
|
+
|
325
|
+
def legacy_table(node)
|
326
|
+
@result = LegacyTable.new(node)
|
327
|
+
end
|
328
|
+
|
329
|
+
def result
|
330
|
+
@result || Node.new(nil)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
class DocString < Node
|
335
|
+
def accept(formatter)
|
336
|
+
formatter.before_multiline_arg node
|
337
|
+
formatter.doc_string(node)
|
338
|
+
formatter.after_multiline_arg node
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
class DataTable < Cucumber::MultilineArgument::DataTable
|
343
|
+
def node
|
344
|
+
@ast_table
|
345
|
+
end
|
346
|
+
|
347
|
+
def accept(formatter)
|
348
|
+
formatter.before_multiline_arg self
|
349
|
+
node.raw.each_with_index do |row, index|
|
350
|
+
line = node.location.line + index
|
351
|
+
DataTableRow.new(row, line).accept(formatter)
|
352
|
+
end
|
353
|
+
formatter.after_multiline_arg self
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
class LegacyTable < SimpleDelegator
|
359
|
+
def accept(formatter)
|
360
|
+
formatter.before_multiline_arg self
|
361
|
+
cells_rows.each_with_index do |row, index|
|
362
|
+
line = location.line + index
|
363
|
+
LegacyTableRow.new(row, line).accept(formatter)
|
364
|
+
end
|
365
|
+
formatter.after_multiline_arg self
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
Features = Struct.new(:duration)
|
370
|
+
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Formatter
|
3
|
+
module LegacyApi
|
4
|
+
|
5
|
+
class Results
|
6
|
+
def initialize
|
7
|
+
# Optimization - quicker lookup.
|
8
|
+
@inserted_steps = {}
|
9
|
+
@inserted_scenarios = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def step_visited(step) #:nodoc:
|
13
|
+
step_id = step.object_id
|
14
|
+
|
15
|
+
unless @inserted_steps.has_key?(step_id)
|
16
|
+
@inserted_steps[step_id] = step
|
17
|
+
steps.push(step)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def scenario_visited(scenario) #:nodoc:
|
22
|
+
scenario_id = scenario.object_id
|
23
|
+
|
24
|
+
unless @inserted_scenarios.has_key?(scenario_id)
|
25
|
+
@inserted_scenarios[scenario_id] = scenario
|
26
|
+
scenarios.push(scenario)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def steps(status = nil) #:nodoc:
|
31
|
+
@steps ||= []
|
32
|
+
if(status)
|
33
|
+
@steps.select{|step| step.status == status}
|
34
|
+
else
|
35
|
+
@steps
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def scenarios(status = nil) #:nodoc:
|
40
|
+
@scenarios ||= []
|
41
|
+
if(status)
|
42
|
+
@scenarios.select{|scenario| scenario.status == status}
|
43
|
+
else
|
44
|
+
@scenarios
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Formatter
|
3
|
+
module LegacyApi
|
4
|
+
|
5
|
+
# This is what's passed to the constructor of the formatters
|
6
|
+
class RuntimeFacade < Struct.new(:results, :support_code, :configuration)
|
7
|
+
def unmatched_step_definitions
|
8
|
+
support_code.unmatched_step_definitions
|
9
|
+
end
|
10
|
+
|
11
|
+
def snippet_text(step_keyword, step_name, multiline_arg) #:nodoc:
|
12
|
+
support_code.snippet_text(::Gherkin::I18n.code_keyword_for(step_keyword), step_name, multiline_arg)
|
13
|
+
end
|
14
|
+
|
15
|
+
def unknown_programming_language?
|
16
|
+
support_code.unknown_programming_language?
|
17
|
+
end
|
18
|
+
|
19
|
+
def scenarios(status = nil)
|
20
|
+
results.scenarios(status)
|
21
|
+
end
|
22
|
+
|
23
|
+
def steps(status = nil)
|
24
|
+
results.steps(status)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|