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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +20 -3
  3. data/cucumber.gemspec +2 -1
  4. data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
  5. data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
  6. data/features/docs/formatters/debug_formatter.feature +24 -17
  7. data/features/docs/formatters/pretty_formatter.feature +42 -0
  8. data/features/docs/formatters/rerun_formatter.feature +3 -2
  9. data/lib/cucumber/cli/configuration.rb +3 -7
  10. data/lib/cucumber/cli/main.rb +1 -1
  11. data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
  12. data/lib/cucumber/filters/quit.rb +24 -0
  13. data/lib/cucumber/filters/randomizer.rb +36 -0
  14. data/lib/cucumber/filters/tag_limits.rb +40 -0
  15. data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
  16. data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
  17. data/lib/cucumber/formatter/console.rb +2 -2
  18. data/lib/cucumber/formatter/debug.rb +1 -8
  19. data/lib/cucumber/formatter/fanout.rb +27 -0
  20. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -3
  21. data/lib/cucumber/formatter/html.rb +12 -4
  22. data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
  23. data/lib/cucumber/formatter/junit.rb +2 -2
  24. data/lib/cucumber/formatter/legacy_api/adapter.rb +1008 -0
  25. data/lib/cucumber/formatter/legacy_api/ast.rb +374 -0
  26. data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
  27. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
  28. data/lib/cucumber/formatter/pretty.rb +4 -0
  29. data/lib/cucumber/formatter/rerun.rb +14 -88
  30. data/lib/cucumber/language_support/language_methods.rb +0 -54
  31. data/lib/cucumber/multiline_argument/data_table.rb +3 -4
  32. data/lib/cucumber/platform.rb +1 -1
  33. data/lib/cucumber/runtime.rb +41 -107
  34. data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
  35. data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
  36. data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
  37. data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
  38. data/spec/cucumber/formatter/debug_spec.rb +39 -530
  39. data/spec/cucumber/formatter/html_spec.rb +56 -0
  40. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +1902 -0
  41. data/spec/cucumber/formatter/pretty_spec.rb +128 -0
  42. data/spec/cucumber/formatter/rerun_spec.rb +106 -0
  43. data/spec/cucumber/formatter/spec_helper.rb +6 -2
  44. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  45. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
  46. data/spec/cucumber/runtime_spec.rb +1 -5
  47. data/spec/spec_helper.rb +2 -0
  48. metadata +44 -29
  49. data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
  50. data/features/docs/output_from_hooks.feature +0 -128
  51. data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
  52. data/lib/cucumber/runtime/results.rb +0 -64
  53. data/lib/cucumber/runtime/tag_limits.rb +0 -15
  54. data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
  55. data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
  56. 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