cucumber-core 5.0.2 → 9.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -0
  3. data/CONTRIBUTING.md +3 -3
  4. data/README.md +0 -2
  5. data/lib/cucumber/core.rb +8 -6
  6. data/lib/cucumber/core/compiler.rb +35 -14
  7. data/lib/cucumber/core/event.rb +3 -5
  8. data/lib/cucumber/core/event_bus.rb +1 -1
  9. data/lib/cucumber/core/events.rb +25 -1
  10. data/lib/cucumber/core/gherkin/parser.rb +10 -8
  11. data/lib/cucumber/core/gherkin/writer.rb +15 -5
  12. data/lib/cucumber/core/gherkin/writer/helpers.rb +2 -2
  13. data/lib/cucumber/core/test/action.rb +1 -2
  14. data/lib/cucumber/core/test/case.rb +5 -4
  15. data/lib/cucumber/core/test/data_table.rb +6 -10
  16. data/lib/cucumber/core/test/doc_string.rb +3 -6
  17. data/lib/cucumber/core/test/filters/activate_steps_for_self_test.rb +0 -1
  18. data/lib/cucumber/core/test/result.rb +68 -7
  19. data/lib/cucumber/core/test/step.rb +6 -5
  20. data/lib/cucumber/core/test/timer.rb +2 -2
  21. data/lib/cucumber/core/version.rb +1 -1
  22. data/spec/coverage.rb +1 -0
  23. data/spec/cucumber/core/compiler_spec.rb +66 -3
  24. data/spec/cucumber/core/event_bus_spec.rb +2 -2
  25. data/spec/cucumber/core/event_spec.rb +3 -3
  26. data/spec/cucumber/core/filter_spec.rb +2 -2
  27. data/spec/cucumber/core/gherkin/parser_spec.rb +18 -2
  28. data/spec/cucumber/core/gherkin/writer_spec.rb +0 -1
  29. data/spec/cucumber/core/test/action_spec.rb +1 -2
  30. data/spec/cucumber/core/test/case_spec.rb +3 -2
  31. data/spec/cucumber/core/test/data_table_spec.rb +10 -12
  32. data/spec/cucumber/core/test/doc_string_spec.rb +8 -11
  33. data/spec/cucumber/core/test/location_spec.rb +7 -7
  34. data/spec/cucumber/core/test/result_spec.rb +41 -11
  35. data/spec/cucumber/core/test/runner_spec.rb +23 -21
  36. data/spec/cucumber/core/test/step_spec.rb +10 -9
  37. data/spec/cucumber/core_spec.rb +2 -2
  38. metadata +91 -53
  39. data/spec/capture_warnings.rb +0 -74
@@ -126,11 +126,11 @@ module Cucumber
126
126
  module HasDescription
127
127
  private
128
128
  def description
129
- options.fetch(:description) { '' }.split("\n").map(&:strip)
129
+ options.fetch(:description, '').split("\n").map(&:strip)
130
130
  end
131
131
 
132
132
  def description_statement
133
- description.map { |s| indent(s,2) } unless description.empty?
133
+ description.map { |s| indent(s, 2) } unless description.empty?
134
134
  end
135
135
  end
136
136
 
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
+ require 'cucumber/core/test/location'
2
3
  require 'cucumber/core/test/result'
3
4
  require 'cucumber/core/test/timer'
4
- require 'cucumber/core/test/result'
5
- require 'cucumber/core/test/location'
6
5
 
7
6
  module Cucumber
8
7
  module Core
@@ -7,10 +7,11 @@ module Cucumber
7
7
  module Core
8
8
  module Test
9
9
  class Case
10
- attr_reader :name, :test_steps, :location, :tags, :language, :around_hooks
10
+ attr_reader :id, :name, :test_steps, :location, :tags, :language, :around_hooks
11
11
 
12
- def initialize(name, test_steps, location, tags, language, around_hooks = [])
12
+ def initialize(id, name, test_steps, location, tags, language, around_hooks = [])
13
13
  raise ArgumentError.new("test_steps should be an Array but is a #{test_steps.class}") unless test_steps.is_a?(Array)
14
+ @id = id
14
15
  @name = name
15
16
  @test_steps = test_steps
16
17
  @location = location
@@ -35,11 +36,11 @@ module Cucumber
35
36
  end
36
37
 
37
38
  def with_steps(test_steps)
38
- self.class.new(name, test_steps, location, tags, language, around_hooks)
39
+ self.class.new(id, name, test_steps, location, tags, language, around_hooks)
39
40
  end
40
41
 
41
42
  def with_around_hooks(around_hooks)
42
- self.class.new(name, test_steps, location, tags, language, around_hooks)
43
+ self.class.new(id, name, test_steps, location, tags, language, around_hooks)
43
44
  end
44
45
 
45
46
  def match_tags?(*expressions)
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'cucumber/core/test/location'
3
2
 
4
3
  module Cucumber
5
4
  module Core
@@ -24,18 +23,15 @@ module Cucumber
24
23
  # This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
25
24
  #
26
25
  class DataTable
27
- include HasLocation
28
-
29
26
  # Creates a new instance. +raw+ should be an Array of Array of String
30
27
  # or an Array of Hash
31
28
  # You don't typically create your own DataTable objects - Cucumber will do
32
29
  # it internally and pass them to your Step Definitions.
33
30
  #
34
- def initialize(rows, location)
31
+ def initialize(rows)
35
32
  raw = ensure_array_of_array(rows)
36
33
  verify_rows_are_same_length(raw)
37
34
  @raw = raw.freeze
38
- @location = location
39
35
  end
40
36
  attr_reader :raw
41
37
 
@@ -58,7 +54,7 @@ module Cucumber
58
54
  # Creates a copy of this table
59
55
  #
60
56
  def dup
61
- self.class.new(raw.dup, location)
57
+ self.class.new(raw.dup)
62
58
  end
63
59
 
64
60
  # Returns a new, transposed table. Example:
@@ -73,7 +69,7 @@ module Cucumber
73
69
  # | 4 | 2 |
74
70
  #
75
71
  def transpose
76
- self.class.new(raw.transpose, location)
72
+ self.class.new(raw.transpose)
77
73
  end
78
74
 
79
75
  def map(&block)
@@ -81,7 +77,7 @@ module Cucumber
81
77
  row.map(&block)
82
78
  end
83
79
 
84
- self.class.new(new_raw, location)
80
+ self.class.new(new_raw)
85
81
  end
86
82
 
87
83
  def ==(other)
@@ -89,7 +85,7 @@ module Cucumber
89
85
  end
90
86
 
91
87
  def inspect
92
- %{#<#{self.class} #{raw.inspect} (#{location})>}
88
+ %{#<#{self.class} #{raw.inspect})>}
93
89
  end
94
90
 
95
91
  private
@@ -108,7 +104,7 @@ module Cucumber
108
104
 
109
105
  def hashes_to_array(hashes)
110
106
  header = hashes[0].keys.sort
111
- [header] + hashes.map{|hash| header.map{|key| hash[key]}}
107
+ [header] + hashes.map {|hash| header.map {|key| hash[key]}}
112
108
  end
113
109
 
114
110
  end
@@ -20,14 +20,11 @@ module Cucumber
20
20
  # Note how the indentation from the source is stripped away.
21
21
  #
22
22
  class DocString < SimpleDelegator
23
- include HasLocation
24
-
25
23
  attr_reader :content_type, :content
26
24
 
27
- def initialize(content, content_type, location)
25
+ def initialize(content, content_type)
28
26
  @content = content
29
27
  @content_type = content_type
30
- @location = location
31
28
  super @content
32
29
  end
33
30
 
@@ -46,7 +43,7 @@ module Cucumber
46
43
  def map
47
44
  raise ArgumentError, "No block given" unless block_given?
48
45
  new_content = yield content
49
- self.class.new(new_content, content_type, location)
46
+ self.class.new(new_content, content_type)
50
47
  end
51
48
 
52
49
  def to_step_definition_arg
@@ -65,7 +62,7 @@ module Cucumber
65
62
 
66
63
  def inspect
67
64
  [
68
- %{#<#{self.class} (#{location})},
65
+ %{#<#{self.class}},
69
66
  %{ """#{content_type}},
70
67
  %{ #{@content}},
71
68
  %{ """>}
@@ -33,4 +33,3 @@ module Cucumber
33
33
  end
34
34
  end
35
35
  end
36
-
@@ -9,7 +9,6 @@ module Cucumber
9
9
  STRICT_AFFECTED_TYPES = [:flaky, :undefined, :pending].freeze
10
10
 
11
11
  def self.ok?(type, be_strict = StrictConfiguration.new)
12
- private
13
12
  class_name = type.to_s.slice(0, 1).capitalize + type.to_s.slice(1..-1)
14
13
  const_get(class_name).ok?(be_strict.strict?(type))
15
14
  end
@@ -43,6 +42,13 @@ module Cucumber
43
42
  def with_filtered_backtrace(filter)
44
43
  self
45
44
  end
45
+
46
+ def to_message
47
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
48
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::UNKNOWN,
49
+ duration: UnknownDuration.new.to_message_duration
50
+ )
51
+ end
46
52
  end
47
53
 
48
54
  class Passed
@@ -68,6 +74,13 @@ module Cucumber
68
74
  "✓"
69
75
  end
70
76
 
77
+ def to_message
78
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
79
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::PASSED,
80
+ duration: duration.to_message_duration
81
+ )
82
+ end
83
+
71
84
  def ok?(be_strict = nil)
72
85
  self.class.ok?
73
86
  end
@@ -83,6 +96,7 @@ module Cucumber
83
96
 
84
97
  class Failed
85
98
  include Result.query_methods :failed
99
+
86
100
  attr_reader :duration, :exception
87
101
 
88
102
  def self.ok?(be_strict = false)
@@ -107,6 +121,20 @@ module Cucumber
107
121
  "✗"
108
122
  end
109
123
 
124
+ def to_message
125
+ begin
126
+ message = exception.backtrace.join("\n")
127
+ rescue NoMethodError
128
+ message = ""
129
+ end
130
+
131
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
132
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::FAILED,
133
+ duration: duration.to_message_duration,
134
+ message: message
135
+ )
136
+ end
137
+
110
138
  def ok?(be_strict = nil)
111
139
  self.class.ok?
112
140
  end
@@ -186,6 +214,13 @@ module Cucumber
186
214
  def to_s
187
215
  "?"
188
216
  end
217
+
218
+ def to_message
219
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
220
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::UNDEFINED,
221
+ duration: duration.to_message_duration
222
+ )
223
+ end
189
224
  end
190
225
 
191
226
  class Skipped < Raisable
@@ -204,6 +239,13 @@ module Cucumber
204
239
  def to_s
205
240
  "-"
206
241
  end
242
+
243
+ def to_message
244
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
245
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::SKIPPED,
246
+ duration: duration.to_message_duration
247
+ )
248
+ end
207
249
  end
208
250
 
209
251
  class Pending < Raisable
@@ -222,6 +264,13 @@ module Cucumber
222
264
  def to_s
223
265
  "P"
224
266
  end
267
+
268
+ def to_message
269
+ Cucumber::Messages::TestStepFinished::TestStepResult.new(
270
+ status: Cucumber::Messages::TestStepFinished::TestStepResult::Status::PENDING,
271
+ duration: duration.to_message_duration
272
+ )
273
+ end
225
274
  end
226
275
 
227
276
  # Handles the strict settings for the result types that are
@@ -229,9 +278,9 @@ module Cucumber
229
278
  class StrictConfiguration
230
279
  attr_accessor :settings
231
280
  private :settings
232
-
281
+
233
282
  def initialize(strict_types = [])
234
- @settings = Hash[STRICT_AFFECTED_TYPES.map { |t| [t, :default] }]
283
+ @settings = STRICT_AFFECTED_TYPES.map { |t| [t, :default] }.to_h
235
284
  strict_types.each do |type|
236
285
  set_strict(true, type)
237
286
  end
@@ -261,7 +310,7 @@ module Cucumber
261
310
  end
262
311
 
263
312
  def merge!(other)
264
- settings.keys.each do |type|
313
+ settings.each_key do |type|
265
314
  set_strict(other.strict?(type), type) if other.set?(type)
266
315
  end
267
316
  self
@@ -320,7 +369,7 @@ module Cucumber
320
369
 
321
370
  def total(for_status = nil)
322
371
  if for_status
323
- @totals.fetch(for_status) { 0 }
372
+ @totals.fetch(for_status, 0)
324
373
  else
325
374
  @totals.reduce(0) { |total, status| total += status[1] }
326
375
  end
@@ -329,12 +378,12 @@ module Cucumber
329
378
  def decrement_failed
330
379
  @totals[:failed] -= 1
331
380
  end
332
-
381
+
333
382
  private
334
383
 
335
384
  def get_total(method_name)
336
385
  status = method_name.to_s.gsub('total_', '').to_sym
337
- return @totals.fetch(status) { 0 }
386
+ return @totals.fetch(status, 0)
338
387
  end
339
388
 
340
389
  def increment_total(status)
@@ -344,14 +393,22 @@ module Cucumber
344
393
  end
345
394
 
346
395
  class Duration
396
+ include Cucumber::Messages::TimeConversion
397
+
347
398
  attr_reader :nanoseconds
348
399
 
349
400
  def initialize(nanoseconds)
350
401
  @nanoseconds = nanoseconds
351
402
  end
403
+
404
+ def to_message_duration
405
+ seconds_to_duration(nanoseconds.to_f / NANOSECONDS_PER_SECOND)
406
+ end
352
407
  end
353
408
 
354
409
  class UnknownDuration
410
+ include Cucumber::Messages::TimeConversion
411
+
355
412
  def tap(&block)
356
413
  self
357
414
  end
@@ -359,6 +416,10 @@ module Cucumber
359
416
  def nanoseconds
360
417
  raise "#nanoseconds only allowed to be used in #tap block"
361
418
  end
419
+
420
+ def to_message_duration
421
+ seconds_to_duration(0)
422
+ end
362
423
  end
363
424
  end
364
425
  end
@@ -8,10 +8,11 @@ module Cucumber
8
8
  module Core
9
9
  module Test
10
10
  class Step
11
- attr_reader :text, :location, :multiline_arg
11
+ attr_reader :id, :text, :location, :multiline_arg
12
12
 
13
- def initialize(text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
13
+ def initialize(id, text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
14
14
  raise ArgumentError if text.nil? || text.empty?
15
+ @id = id
15
16
  @text = text
16
17
  @location = location
17
18
  @multiline_arg = multiline_arg
@@ -35,7 +36,7 @@ module Cucumber
35
36
  end
36
37
 
37
38
  def with_action(action_location = nil, &block)
38
- self.class.new(text, location, multiline_arg, Test::Action.new(action_location, &block))
39
+ self.class.new(id, text, location, multiline_arg, Test::Action.new(action_location, &block))
39
40
  end
40
41
 
41
42
  def backtrace_line
@@ -56,8 +57,8 @@ module Cucumber
56
57
  end
57
58
 
58
59
  class HookStep < Step
59
- def initialize(text, location, action)
60
- super(text, location, Test::EmptyMultilineArgument.new, action)
60
+ def initialize(id, text, location, action)
61
+ super(id, text, location, Test::EmptyMultilineArgument.new, action)
61
62
  end
62
63
 
63
64
  def hook?
@@ -19,7 +19,7 @@ module Cucumber
19
19
  end
20
20
 
21
21
  def sec
22
- nsec / 10 ** 9.0
22
+ nsec / 10**9.0
23
23
  end
24
24
 
25
25
  private
@@ -42,7 +42,7 @@ module Cucumber
42
42
  else
43
43
  def time_in_nanoseconds
44
44
  t = Time.now
45
- t.to_i * 10 ** 9 + t.nsec
45
+ t.to_i * 10**9 + t.nsec
46
46
  end
47
47
  end
48
48
  end
@@ -3,7 +3,7 @@ module Cucumber
3
3
  module Core
4
4
  class Version
5
5
  def self.to_s
6
- "5.0.2"
6
+ "9.0.0"
7
7
  end
8
8
  end
9
9
  end
data/spec/coverage.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'rubygems'
2
3
  require 'simplecov'
3
4
  formatters = [ SimpleCov::Formatter::HTMLFormatter ]
4
5
 
@@ -31,6 +31,60 @@ module Cucumber::Core
31
31
  end
32
32
  end
33
33
 
34
+ context "when the event_bus is provided" do
35
+ let(:event_bus) { double }
36
+
37
+ before do
38
+ allow( event_bus ).to receive(:envelope)
39
+ allow( event_bus ).to receive(:gherkin_source_parsed).and_return(nil)
40
+ allow( event_bus ).to receive(:test_case_created).and_return(nil)
41
+ allow( event_bus ).to receive(:test_step_created).and_return(nil)
42
+ end
43
+
44
+ it "emits a TestCaseCreated event with the created Test::Case and Pickle" do
45
+ gherkin_documents = [
46
+ gherkin do
47
+ feature do
48
+ scenario do
49
+ step 'passing'
50
+ end
51
+ end
52
+ end
53
+ ]
54
+
55
+ compile(gherkin_documents, event_bus) do |visitor|
56
+ allow( visitor ).to receive(:test_case)
57
+ allow( visitor ).to receive(:test_step)
58
+ allow( visitor ).to receive(:done)
59
+ allow( event_bus ).to receive(:envelope)
60
+
61
+ expect( event_bus ).to receive(:test_case_created).once
62
+ end
63
+ end
64
+
65
+ it "emits a TestStepCreated event with the created Test::Step and PickleStep" do
66
+ gherkin_documents = [
67
+ gherkin do
68
+ feature do
69
+ scenario do
70
+ step 'passing'
71
+ step 'passing'
72
+ end
73
+ end
74
+ end
75
+ ]
76
+
77
+ compile(gherkin_documents, event_bus) do |visitor|
78
+ allow( visitor ).to receive(:test_case)
79
+ allow( visitor ).to receive(:test_step)
80
+ allow( visitor ).to receive(:done)
81
+ allow( event_bus ).to receive(:envelope)
82
+
83
+ expect( event_bus ).to receive(:test_step_created).twice
84
+ end
85
+ end
86
+ end
87
+
34
88
  it "compiles a feature with a background" do
35
89
  gherkin_documents = [
36
90
  gherkin do
@@ -166,13 +220,22 @@ module Cucumber::Core
166
220
  end
167
221
  end
168
222
 
169
- def compile(gherkin_documents)
223
+ def compile(gherkin_documents, event_bus = nil)
170
224
  visitor = double
171
225
  allow( visitor ).to receive(:test_suite).and_yield(visitor)
172
226
  allow( visitor ).to receive(:test_case).and_yield(visitor)
227
+
228
+ if event_bus.nil?
229
+ event_bus = double
230
+ allow( event_bus ).to receive(:envelope).and_return(nil)
231
+ allow( event_bus ).to receive(:gherkin_source_parsed).and_return(nil)
232
+ allow( event_bus ).to receive(:test_case_created).and_return(nil)
233
+ allow( event_bus ).to receive(:test_step_created).and_return(nil)
234
+ allow( event_bus ).to receive(:envelope).and_return(nil)
235
+ end
236
+
173
237
  yield visitor
174
- super(gherkin_documents, visitor)
238
+ super(gherkin_documents, visitor, [], event_bus)
175
239
  end
176
-
177
240
  end
178
241
  end