cucumber 2.0.0.beta.3 → 2.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.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/History.md +131 -32
  4. data/Rakefile +0 -2
  5. data/cucumber.gemspec +4 -3
  6. data/examples/i18n/ht/Rakefile +6 -0
  7. data/examples/i18n/ht/features/adisyon.feature +17 -0
  8. data/examples/i18n/ht/features/divizyon.feature +10 -0
  9. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
  10. data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
  11. data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
  12. data/features/docs/cli/dry_run.feature +48 -0
  13. data/features/docs/cli/exclude_files.feature +1 -2
  14. data/features/docs/cli/run_specific_scenarios.feature +28 -66
  15. data/features/docs/cli/strict_mode.feature +24 -1
  16. data/features/docs/defining_steps/nested_steps.feature +49 -0
  17. data/features/docs/defining_steps/skip_scenario.feature +31 -2
  18. data/features/docs/defining_steps/snippets.feature +15 -0
  19. data/features/docs/exception_in_after_step_hook.feature +1 -1
  20. data/features/docs/exception_in_around_hook.feature +80 -0
  21. data/features/docs/extending_cucumber/custom_filter.feature +29 -0
  22. data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
  23. data/features/docs/formatters/debug_formatter.feature +24 -17
  24. data/features/docs/formatters/json_formatter.feature +65 -1
  25. data/features/docs/formatters/junit_formatter.feature +40 -0
  26. data/features/docs/formatters/pretty_formatter.feature +42 -0
  27. data/features/docs/formatters/rerun_formatter.feature +3 -2
  28. data/features/docs/getting_started.feature +1 -1
  29. data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
  30. data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
  31. data/features/docs/wire_protocol/invoke_message.feature +216 -0
  32. data/features/docs/wire_protocol/readme.md +26 -0
  33. data/features/docs/wire_protocol/snippets_message.feature +51 -0
  34. data/features/docs/wire_protocol/step_matches_message.feature +81 -0
  35. data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
  36. data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
  37. data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
  38. data/features/docs/work_in_progress.feature +1 -1
  39. data/features/docs/writing_support_code/after_hooks.feature +24 -0
  40. data/features/docs/writing_support_code/around_hooks.feature +31 -0
  41. data/features/docs/writing_support_code/before_hook.feature +7 -3
  42. data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
  43. data/features/lib/step_definitions/wire_steps.rb +18 -1
  44. data/features/lib/support/fake_wire_server.rb +10 -7
  45. data/lib/cucumber/cli/configuration.rb +6 -11
  46. data/lib/cucumber/cli/main.rb +2 -2
  47. data/lib/cucumber/cli/options.rb +8 -1
  48. data/lib/cucumber/cli/profile_loader.rb +1 -1
  49. data/lib/cucumber/core_ext/instance_exec.rb +1 -1
  50. data/lib/cucumber/encoding.rb +5 -0
  51. data/lib/cucumber/errors.rb +8 -0
  52. data/lib/cucumber/file_specs.rb +3 -1
  53. data/lib/cucumber/filters/activate_steps.rb +33 -0
  54. data/lib/cucumber/filters/apply_after_hooks.rb +9 -0
  55. data/lib/cucumber/filters/apply_after_step_hooks.rb +12 -0
  56. data/lib/cucumber/filters/apply_around_hooks.rb +12 -0
  57. data/lib/cucumber/filters/apply_before_hooks.rb +9 -0
  58. data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
  59. data/lib/cucumber/filters/prepare_world.rb +45 -0
  60. data/lib/cucumber/filters/quit.rb +28 -0
  61. data/lib/cucumber/filters/randomizer.rb +40 -0
  62. data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
  63. data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
  64. data/lib/cucumber/filters/tag_limits.rb +45 -0
  65. data/lib/cucumber/filters.rb +9 -0
  66. data/lib/cucumber/formatter/ansicolor.rb +0 -8
  67. data/lib/cucumber/formatter/console.rb +37 -20
  68. data/lib/cucumber/formatter/debug.rb +1 -8
  69. data/lib/cucumber/formatter/fanout.rb +27 -0
  70. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +10 -9
  71. data/lib/cucumber/formatter/html.rb +31 -6
  72. data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
  73. data/lib/cucumber/formatter/junit.rb +97 -2
  74. data/lib/cucumber/formatter/legacy_api/adapter.rb +1060 -0
  75. data/lib/cucumber/formatter/legacy_api/ast.rb +376 -0
  76. data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
  77. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
  78. data/lib/cucumber/formatter/pretty.rb +14 -0
  79. data/lib/cucumber/formatter/progress.rb +10 -0
  80. data/lib/cucumber/formatter/rerun.rb +14 -88
  81. data/lib/cucumber/hooks.rb +97 -0
  82. data/lib/cucumber/language_support/language_methods.rb +0 -54
  83. data/lib/cucumber/multiline_argument/data_table.rb +41 -29
  84. data/lib/cucumber/platform.rb +3 -3
  85. data/lib/cucumber/project_initializer.rb +43 -0
  86. data/lib/cucumber/rb_support/rb_hook.rb +2 -2
  87. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
  88. data/lib/cucumber/rb_support/rb_transform.rb +3 -1
  89. data/lib/cucumber/rb_support/rb_world.rb +2 -2
  90. data/lib/cucumber/rb_support/snippet.rb +1 -1
  91. data/lib/cucumber/rspec/doubles.rb +1 -1
  92. data/lib/cucumber/running_test_case.rb +115 -0
  93. data/lib/cucumber/runtime/after_hooks.rb +24 -0
  94. data/lib/cucumber/runtime/before_hooks.rb +23 -0
  95. data/lib/cucumber/runtime/for_programming_languages.rb +4 -8
  96. data/lib/cucumber/runtime/step_hooks.rb +22 -0
  97. data/lib/cucumber/runtime/support_code.rb +70 -5
  98. data/lib/cucumber/runtime.rb +56 -112
  99. data/lib/cucumber/step_match.rb +26 -2
  100. data/lib/cucumber.rb +7 -3
  101. data/spec/cucumber/cli/configuration_spec.rb +16 -1
  102. data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
  103. data/spec/cucumber/core_ext/instance_exec_spec.rb +4 -0
  104. data/spec/cucumber/file_specs_spec.rb +21 -2
  105. data/spec/cucumber/filters/activate_steps_spec.rb +57 -0
  106. data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
  107. data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
  108. data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
  109. data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
  110. data/spec/cucumber/formatter/debug_spec.rb +25 -530
  111. data/spec/cucumber/formatter/html_spec.rb +140 -0
  112. data/spec/cucumber/formatter/junit_spec.rb +212 -156
  113. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +2090 -0
  114. data/spec/cucumber/formatter/pretty_spec.rb +248 -2
  115. data/spec/cucumber/formatter/rerun_spec.rb +107 -0
  116. data/spec/cucumber/formatter/spec_helper.rb +17 -8
  117. data/spec/cucumber/hooks_spec.rb +30 -0
  118. data/spec/cucumber/multiline_argument/data_table_spec.rb +53 -47
  119. data/spec/cucumber/project_initializer_spec.rb +87 -0
  120. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  121. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +32 -7
  122. data/spec/cucumber/rb_support/rb_transform_spec.rb +20 -0
  123. data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
  124. data/spec/cucumber/running_test_case_spec.rb +83 -0
  125. data/spec/cucumber/runtime_spec.rb +1 -5
  126. data/spec/spec_helper.rb +3 -4
  127. metadata +149 -107
  128. data/bin/cuke +0 -60
  129. data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
  130. data/features/docs/output_from_hooks.feature +0 -128
  131. data/features/docs/report_called_undefined_steps.feature +0 -57
  132. data/features/docs/wire_protocol.feature +0 -337
  133. data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  134. data/gem_tasks/yard/default/layout/html/footer.erb +0 -5
  135. data/gem_tasks/yard/default/layout/html/index.erb +0 -1
  136. data/gem_tasks/yard/default/layout/html/layout.erb +0 -25
  137. data/gem_tasks/yard/default/layout/html/logo.erb +0 -1
  138. data/gem_tasks/yard/default/layout/html/setup.rb +0 -4
  139. data/gem_tasks/yard.rake +0 -43
  140. data/lib/cucumber/mappings.rb +0 -238
  141. data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
  142. data/lib/cucumber/runtime/results.rb +0 -64
  143. data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
  144. data/lib/cucumber/runtime/tag_limits.rb +0 -15
  145. data/spec/cucumber/mappings_spec.rb +0 -180
  146. data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
  147. data/spec/cucumber/runtime/results_spec.rb +0 -88
@@ -0,0 +1,376 @@
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
+ legacy_multiline_arg = if multiline_arg.kind_of?(Core::Ast::EmptyMultilineArgument)
122
+ nil
123
+ else
124
+ step.multiline_arg
125
+ end
126
+ [keyword, step_match, legacy_multiline_arg, status, exception, source_indent, background, file_colon_line]
127
+ end
128
+
129
+ def failed?
130
+ status != :passed
131
+ end
132
+
133
+ def passed?
134
+ status == :passed
135
+ end
136
+
137
+ def dom_id
138
+
139
+ end
140
+
141
+ def actual_keyword(previous_step_keyword = nil)
142
+ step.actual_keyword(previous_step_keyword)
143
+ end
144
+
145
+ def file_colon_line
146
+ location.to_s
147
+ end
148
+
149
+ def backtrace_line
150
+ step_match.backtrace_line
151
+ end
152
+
153
+ def step_invocation
154
+ self
155
+ end
156
+
157
+ private
158
+
159
+ def source_indent
160
+ indent.of(self)
161
+ end
162
+
163
+ def print_step_name(formatter)
164
+ formatter.step_name(
165
+ keyword,
166
+ step_match,
167
+ status,
168
+ source_indent,
169
+ background,
170
+ location.to_s)
171
+ end
172
+
173
+ def print_exception(formatter)
174
+ return unless exception
175
+ raise exception if ENV['FAIL_FAST']
176
+ formatter.exception(exception, status)
177
+ end
178
+ end
179
+
180
+ class StepInvocations < Array
181
+ def failed?
182
+ any?(&:failed?)
183
+ end
184
+
185
+ def passed?
186
+ all?(&:passed?)
187
+ end
188
+
189
+ def status
190
+ return :passed if passed?
191
+ failed_step.status
192
+ end
193
+
194
+ def exception
195
+ failed_step.exception if failed_step
196
+ end
197
+
198
+ private
199
+
200
+ def failed_step
201
+ detect(&:failed?)
202
+ end
203
+ end
204
+
205
+ class DataTableRow
206
+ def initialize(row, line)
207
+ @values = row
208
+ @line = line
209
+ end
210
+
211
+ def dom_id
212
+ "row_#{line}"
213
+ end
214
+
215
+ def accept(formatter)
216
+ formatter.before_table_row(self)
217
+ values.each do |value|
218
+ formatter.before_table_cell(value)
219
+ formatter.table_cell_value(value, status)
220
+ formatter.after_table_cell(value)
221
+ end
222
+ formatter.after_table_row(self)
223
+ end
224
+
225
+ def status
226
+ :skipped
227
+ end
228
+
229
+ def exception
230
+ nil
231
+ end
232
+
233
+ attr_reader :values, :line
234
+ private :values, :line
235
+ end
236
+
237
+ ExampleTableRow = Struct.new(:exception, :status, :cells, :location, :language) do
238
+ def name
239
+ '| ' + cells.join(' | ') + ' |'
240
+ end
241
+
242
+ def failed?
243
+ status == :failed
244
+ end
245
+
246
+ def line
247
+ location.line
248
+ end
249
+
250
+ def keyword
251
+ # This method is only called when used for the scenario name line with
252
+ # the expand option, and on that line the keyword is "Scenario"
253
+ language.keywords('scenario')[0]
254
+ end
255
+ end
256
+
257
+ class LegacyTableRow < DataTableRow
258
+ def accept(formatter)
259
+ formatter.before_table_row(self)
260
+ values.each do |value|
261
+ formatter.before_table_cell(value.value)
262
+ formatter.table_cell_value(value.value, value.status)
263
+ formatter.after_table_cell(value.value)
264
+ end
265
+ formatter.after_table_row(self)
266
+ end
267
+ end
268
+
269
+ Tags = Struct.new(:tags) do
270
+ def accept(formatter)
271
+ formatter.before_tags tags
272
+ tags.each do |tag|
273
+ formatter.tag_name tag.name
274
+ end
275
+ formatter.after_tags tags
276
+ end
277
+ end
278
+
279
+ Scenario = Struct.new(:status, :name, :location) do
280
+ def backtrace_line(step_name = "#{name}", line = self.location.line)
281
+ "#{location.on_line(line)}:in `#{step_name}'"
282
+ end
283
+
284
+ def failed?
285
+ :failed == status
286
+ end
287
+
288
+ def line
289
+ location.line
290
+ end
291
+ end
292
+
293
+ ScenarioOutline = Struct.new(:status, :name, :location) do
294
+ def backtrace_line(step_name = "#{name}", line = self.location.line)
295
+ "#{location.on_line(line)}:in `#{step_name}'"
296
+ end
297
+
298
+ def failed?
299
+ :failed == status
300
+ end
301
+
302
+ def line
303
+ location.line
304
+ end
305
+ end
306
+
307
+ module MultilineArg
308
+ class << self
309
+ def for(node)
310
+ Builder.new(node).result
311
+ end
312
+ end
313
+
314
+ class Builder
315
+ def initialize(node)
316
+ node.describe_to(self)
317
+ end
318
+
319
+ def doc_string(node)
320
+ @result = DocString.new(node)
321
+ end
322
+
323
+ def data_table(node)
324
+ @result = DataTable.new(node)
325
+ end
326
+
327
+ def legacy_table(node)
328
+ @result = LegacyTable.new(node)
329
+ end
330
+
331
+ def result
332
+ @result || Node.new(nil)
333
+ end
334
+ end
335
+
336
+ class DocString < Node
337
+ def accept(formatter)
338
+ formatter.before_multiline_arg node
339
+ formatter.doc_string(node)
340
+ formatter.after_multiline_arg node
341
+ end
342
+ end
343
+
344
+ class DataTable < Cucumber::MultilineArgument::DataTable
345
+ def node
346
+ @ast_table
347
+ end
348
+
349
+ def accept(formatter)
350
+ formatter.before_multiline_arg self
351
+ node.raw.each_with_index do |row, index|
352
+ line = node.location.line + index
353
+ DataTableRow.new(row, line).accept(formatter)
354
+ end
355
+ formatter.after_multiline_arg self
356
+ end
357
+ end
358
+ end
359
+
360
+ class LegacyTable < SimpleDelegator
361
+ def accept(formatter)
362
+ formatter.before_multiline_arg self
363
+ cells_rows.each_with_index do |row, index|
364
+ line = location.line + index
365
+ LegacyTableRow.new(row, line).accept(formatter)
366
+ end
367
+ formatter.after_multiline_arg self
368
+ end
369
+ end
370
+
371
+ Features = Struct.new(:duration)
372
+
373
+ end
374
+ end
375
+ end
376
+ 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
@@ -26,6 +26,8 @@ module Cucumber
26
26
  @indent = 0
27
27
  @prefixes = options[:prefixes] || {}
28
28
  @delayed_messages = []
29
+ @previous_step_keyword = nil
30
+ @snippets_input = []
29
31
  end
30
32
 
31
33
  def before_features(features)
@@ -72,6 +74,7 @@ module Cucumber
72
74
  end
73
75
 
74
76
  def after_feature_element(feature_element)
77
+ print_messages
75
78
  @io.puts
76
79
  @io.flush
77
80
  end
@@ -83,6 +86,7 @@ module Cucumber
83
86
  end
84
87
 
85
88
  def after_background(background)
89
+ print_messages
86
90
  @in_background = nil
87
91
  @io.puts
88
92
  @io.flush
@@ -125,6 +129,7 @@ module Cucumber
125
129
  def before_step(step)
126
130
  @current_step = step
127
131
  @indent = 6
132
+ print_messages
128
133
  end
129
134
 
130
135
  def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
@@ -161,6 +166,7 @@ module Cucumber
161
166
 
162
167
  def exception(exception, status)
163
168
  return if @hide_this_step
169
+ print_messages
164
170
  print_exception(exception, status, @indent)
165
171
  @io.flush
166
172
  end
@@ -205,6 +211,14 @@ module Cucumber
205
211
  @io.flush
206
212
  end
207
213
 
214
+ def before_test_case(test_case)
215
+ @previous_step_keyword = nil
216
+ end
217
+
218
+ def after_test_step(test_step, result)
219
+ collect_snippet_data(test_step, result)
220
+ end
221
+
208
222
  private
209
223
 
210
224
  def print_feature_element_name(keyword, name, file_colon_line, source_indent)
@@ -11,6 +11,8 @@ module Cucumber
11
11
 
12
12
  def initialize(runtime, path_or_io, options)
13
13
  @runtime, @io, @options = runtime, ensure_io(path_or_io, "progress"), options
14
+ @previous_step_keyword = nil
15
+ @snippets_input = []
14
16
  end
15
17
 
16
18
  def before_features(features)
@@ -64,6 +66,14 @@ module Cucumber
64
66
  @exception_raised = true
65
67
  end
66
68
 
69
+ def before_test_case(test_case)
70
+ @previous_step_keyword = nil
71
+ end
72
+
73
+ def after_test_step(test_step, result)
74
+ collect_snippet_data(test_step, result)
75
+ end
76
+
67
77
  private
68
78
 
69
79
  def print_summary(features)
@@ -2,106 +2,32 @@ require 'cucumber/formatter/io'
2
2
 
3
3
  module Cucumber
4
4
  module Formatter
5
- # The formatter used for <tt>--format rerun</tt>
6
- #
7
- # This formatter keeps track of all failing features and print out their location.
8
- # Example:
9
- #
10
- # features/foo.feature:34 features/bar.feature:11:76:81
11
- #
12
- # This formatter is used by AutoTest - it will use the output to decide what
13
- # to run the next time, simply passing the output string on the command line.
14
- #
15
5
  class Rerun
16
- include Io
6
+ include Formatter::Io
17
7
 
18
8
  def initialize(runtime, path_or_io, options)
19
9
  @io = ensure_io(path_or_io, "rerun")
20
- @options = options
21
- @file_names = []
22
- @file_colon_lines = Hash.new{|h,k| h[k] = []}
10
+ @failures = {}
23
11
  end
24
12
 
25
- def before_feature(feature_element)
26
- @lines = []
27
- @file = feature_element.file
28
- # See https://github.com/cucumber/cucumber/issues/629
29
- if @file.include?(' ')
30
- warn("Filenames with spaces like '#{@file}' cause unexpected behaviour from the rerun formatter.")
31
- end
13
+ def after_test_case(test_case, result)
14
+ return if result.passed?
15
+ @failures[test_case.location.file] ||= []
16
+ @failures[test_case.location.file] << test_case.location.line
32
17
  end
33
18
 
34
- def after_feature(*)
35
- unless @lines.empty?
36
- after_first_time do
37
- @io.print ' '
38
- end
39
- @io.print "#{@file}:#{@lines.join(':')}"
40
- @io.flush
41
- end
19
+ def done
20
+ return if @failures.empty?
21
+ @io.print file_failures.join(' ')
42
22
  end
43
23
 
44
- def after_features(features)
45
- @io.close
24
+ [:before_test_case, :before_test_step, :after_test_step].each do |method|
25
+ define_method(method) { |*| }
46
26
  end
47
27
 
48
- def before_feature_element(feature_element)
49
- @rerun = false
50
- end
51
-
52
- def after_feature_element(feature_element)
53
- if (@rerun || feature_element.failed? || feature_element.status == :skipped) && !(Cucumber::Reports::Legacy::Ast::ScenarioOutline === feature_element)
54
- @lines << feature_element.line
55
- end
56
- end
57
-
58
- def after_table_row(table_row)
59
- return unless @in_examples and Cucumber::Reports::LegacyExampleTableRow === table_row
60
- unless @header_row
61
- if table_row.failed? || table_row.status == :skipped
62
- @rerun = true
63
- @lines << table_row.line
64
- end
65
- end
66
-
67
- @header_row = false if @header_row
68
- end
69
-
70
- def before_examples(*args)
71
- @header_row = true
72
- @in_examples = true
73
- @current_example_line = nil
74
- end
75
-
76
- def after_examples(*args)
77
- @in_examples = false
78
- if @current_example_line and @rerun
79
- @lines << @current_example_line
80
- end
81
- end
82
-
83
- def before_table_row(table_row)
84
- return unless @in_examples
85
- end
86
-
87
- def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
88
- @rerun = true if [:failed, :pending, :undefined].index(status)
89
- end
90
-
91
- def scenario_name(keyword, name, file_colon_line, source_indent)
92
- return unless @in_examples
93
- if @current_example_line and @rerun
94
- @lines << @current_example_line
95
- end
96
- @rerun = false
97
- @current_example_line = file_colon_line.split(':')[1]
98
- end
99
-
100
- private
101
-
102
- def after_first_time
103
- yield if @not_first_time
104
- @not_first_time = true
28
+ private
29
+ def file_failures
30
+ @failures.map { |file, lines| [file, lines].join(':') }
105
31
  end
106
32
  end
107
33
  end