cucumber-core 5.0.2 → 6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ab18c1635eeda0fbd575d01a83bafc96a0073a1ec0ba1249e4bf26b9c60f914
4
- data.tar.gz: 1dccc021f15d75d76c2c3974049f768ee926e0dd7ced151cc9b46a2b422b6906
3
+ metadata.gz: 1b9ecd1991c28bb04a27496f473972f9da886f102c94ac5a6176d4167773afb3
4
+ data.tar.gz: f833220cdb22fd26e68b3457c0c8ced6cc574227c8dc6dd30a540680a09ea8d2
5
5
  SHA512:
6
- metadata.gz: 81461cf45c9616e3e36fc70a25da1b3c0e30e709cc12e675994e6fd0f730ff4e68f9680453e31ecb4814d69a9a79a98ceeb0691a7365fc660fe9e4cad7462092
7
- data.tar.gz: 3a8cc3c74351d91f90c36f509a813b56cab9a333057de9b3b596de4b1feaa8dc912d87827d2682f1fc3f2b2eca2f82c75f38bd2f75204119eb21bcbcf0b8507a
6
+ metadata.gz: d720066139dee301d46a5bb64e2c9e630d599d4750ca5026a40e70cb5c547b14301aee31bdbe12627f043d9df0b427c87444adfa24b2d01c463e484feba2e724
7
+ data.tar.gz: 9d7e4f57de2b4c84c2e8a94bf68bc22aea34d058c8ef6bead5e975866a0bcaed53d5d987c0884d6db42e496eddf46273a946aba13565f78ba34b2eb9d22df265
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.
2
2
 
3
+ ## [6.0.0](https://github.com/cucumber/cucumber-ruby-core/compare/v5.0.2...v6.0.0)
4
+
5
+ ### Changed
6
+
7
+ * Update to Gherkin 10
8
+
9
+ ### Added
10
+
11
+ * Add `envelope` event, which are used when emitting `Cucumber::Messages`
12
+ * Add `TestCaseCreated` and `TestStepCreated` events, emitted when compiling a `Pickle`
13
+ * Add `Id` field to `TestCase` and `TestStep`
14
+ * Added rubocop (with todo file), and removed backports gems
15
+ ([#186](https://github.com/cucumber/cucumber-ruby-core/pull/186),
16
+ [#182](https://github.com/cucumber/cucumber-ruby-core/issues/182)
17
+ [tas50](https://github.com/tas50),
18
+ [luke-hill](https://github.com/luke-hill))
19
+
20
+ ### Removed
21
+
22
+ * Remove location for MultiLine arguments
23
+
24
+
3
25
  ## [5.0.2](https://github.com/cucumber/cucumber-ruby-core/compare/v5.0.1...v5.0.2)
4
26
 
5
27
  ### Changed
data/lib/cucumber/core.rb CHANGED
@@ -4,6 +4,8 @@ require 'cucumber/core/gherkin/parser'
4
4
  require 'cucumber/core/gherkin/document'
5
5
  require 'cucumber/core/compiler'
6
6
  require 'cucumber/core/test/runner'
7
+ require 'cucumber/messages'
8
+ require 'gherkin/query'
7
9
 
8
10
  module Cucumber
9
11
  module Core
@@ -11,21 +13,22 @@ module Cucumber
11
13
  def execute(gherkin_documents, filters = [], event_bus = EventBus.new)
12
14
  yield event_bus if block_given?
13
15
  receiver = Test::Runner.new(event_bus)
14
- compile gherkin_documents, receiver, filters
16
+ compile gherkin_documents, receiver, filters, event_bus
15
17
  self
16
18
  end
17
19
 
18
20
  def compile(gherkin_documents, last_receiver, filters = [], event_bus = EventBus.new)
19
21
  first_receiver = compose(filters, last_receiver)
20
- compiler = Compiler.new(first_receiver)
21
- parse gherkin_documents, compiler, event_bus
22
+ gherkin_query = ::Gherkin::Query.new
23
+ compiler = Compiler.new(first_receiver, gherkin_query, event_bus)
24
+ parse gherkin_documents, compiler, event_bus, gherkin_query
22
25
  self
23
26
  end
24
27
 
25
28
  private
26
29
 
27
- def parse(gherkin_documents, compiler, event_bus)
28
- parser = Core::Gherkin::Parser.new(compiler, event_bus)
30
+ def parse(gherkin_documents, compiler, event_bus, gherkin_query)
31
+ parser = Core::Gherkin::Parser.new(compiler, event_bus, gherkin_query)
29
32
  gherkin_documents.each do |document|
30
33
  parser.document document
31
34
  end
@@ -38,6 +41,5 @@ module Cucumber
38
41
  filter.with_receiver(receiver)
39
42
  end
40
43
  end
41
-
42
44
  end
43
45
  end
@@ -6,16 +6,20 @@ require 'cucumber/core/test/tag'
6
6
  require 'cucumber/core/test/doc_string'
7
7
  require 'cucumber/core/test/data_table'
8
8
  require 'cucumber/core/test/empty_multiline_argument'
9
+ require 'cucumber/messages'
9
10
 
10
11
  module Cucumber
11
12
  module Core
12
13
  # Compiles the Pickles into test cases
13
14
  class Compiler
14
- attr_reader :receiver
15
- private :receiver
15
+ attr_reader :receiver, :gherkin_query, :id_generator
16
+ private :receiver, :gherkin_query, :id_generator
16
17
 
17
- def initialize(receiver)
18
+ def initialize(receiver, gherkin_query, event_bus = nil)
18
19
  @receiver = receiver
20
+ @id_generator = Cucumber::Messages::IdGenerator::UUID.new
21
+ @gherkin_query = gherkin_query
22
+ @event_bus = event_bus
19
23
  end
20
24
 
21
25
  def pickle(pickle)
@@ -33,15 +37,19 @@ module Cucumber
33
37
  def create_test_case(pickle)
34
38
  uri = pickle.uri
35
39
  test_steps = pickle.steps.map { |step| create_test_step(step, uri) }
36
- lines = pickle.locations.map { |location| location.line }.sort.reverse
37
- tags = pickle.tags.map { |tag| Test::Tag.new(Test::Location.new(uri, tag.location.line), tag.name) }
38
- Test::Case.new(pickle.name, test_steps, Test::Location.new(uri, lines), tags, pickle.language)
40
+ lines = source_lines_for_pickle(pickle).sort.reverse
41
+ tags = pickle.tags.map { |tag| Test::Tag.new(Test::Location.new(uri, source_line_for_pickle_tag(tag)), tag.name) }
42
+ test_case = Test::Case.new(id_generator.new_id, pickle.name, test_steps, Test::Location.new(uri, lines), tags, pickle.language)
43
+ @event_bus.test_case_created(test_case, pickle) unless @event_bus.nil?
44
+ test_case
39
45
  end
40
46
 
41
47
  def create_test_step(pickle_step, uri)
42
- lines = pickle_step.locations.map { |location| location.line }.sort.reverse
48
+ lines = source_lines_for_pickle_step(pickle_step).sort.reverse
43
49
  multiline_arg = create_multiline_arg(pickle_step, uri)
44
- Test::Step.new(pickle_step.text, Test::Location.new(uri, lines), multiline_arg)
50
+ step = Test::Step.new(id_generator.new_id, pickle_step.text, Test::Location.new(uri, lines), multiline_arg)
51
+ @event_bus.test_step_created(step, pickle_step) unless @event_bus.nil?
52
+ step
45
53
  end
46
54
 
47
55
  def create_multiline_arg(pickle_step, uri)
@@ -50,21 +58,34 @@ module Cucumber
50
58
  doc_string = pickle_step.argument.doc_string
51
59
  Test::DocString.new(
52
60
  doc_string.content,
53
- doc_string.contentType,
54
- Test::Location.new(uri, doc_string.location.line)
61
+ doc_string.media_type
55
62
  )
56
63
  elsif pickle_step.argument.data_table
57
64
  data_table = pickle_step.argument.data_table
58
- first_cell = data_table.rows.first.cells.first
59
65
  Test::DataTable.new(
60
- data_table.rows.map { |row| row.cells.map { |cell| cell.value } },
61
- Test::Location.new(uri, first_cell.location.line)
66
+ data_table.rows.map { |row| row.cells.map { |cell| cell.value } }
62
67
  )
63
68
  end
64
69
  else
65
70
  Test::EmptyMultilineArgument.new
66
71
  end
67
72
  end
73
+
74
+ def source_lines_for_pickle(pickle)
75
+ pickle.ast_node_ids.map { |id| source_line(id) }
76
+ end
77
+
78
+ def source_lines_for_pickle_step(pickle_step)
79
+ pickle_step.ast_node_ids.map { |id| source_line(id) }
80
+ end
81
+
82
+ def source_line_for_pickle_tag(tag)
83
+ source_line(tag.ast_node_id)
84
+ end
85
+
86
+ def source_line(id)
87
+ gherkin_query.location(id).line
88
+ end
68
89
  end
69
90
  end
70
91
  end
@@ -1,5 +1,3 @@
1
- require 'backports/2.1.0/array/to_h'
2
-
3
1
  module Cucumber
4
2
  module Core
5
3
  class Event
@@ -5,6 +5,10 @@ module Cucumber
5
5
  module Core
6
6
  module Events
7
7
 
8
+ class Envelope < Event.new(:envelope)
9
+ attr_reader :envelope
10
+ end
11
+
8
12
  # Signals that a gherkin source has been parsed
9
13
  class GherkinSourceParsed < Event.new(:gherkin_document)
10
14
  # @return [GherkinDocument] the GherkinDocument Ast Node
@@ -12,6 +16,24 @@ module Cucumber
12
16
 
13
17
  end
14
18
 
19
+ # Signals that a Test::Step was created from a PickleStep
20
+ class TestStepCreated < Event.new(:test_step, :pickle_step)
21
+ # The created test step
22
+ attr_reader :test_step
23
+
24
+ # The source pickle step
25
+ attr_reader :pickle_step
26
+ end
27
+
28
+ # Signals that a Test::Case was created from a Pickle
29
+ class TestCaseCreated < Event.new(:test_case, :pickle)
30
+ # The created test step
31
+ attr_reader :test_case
32
+
33
+ # The source pickle step
34
+ attr_reader :pickle
35
+ end
36
+
15
37
  # Signals that a {Test::Case} is about to be executed
16
38
  class TestCaseStarted < Event.new(:test_case)
17
39
 
@@ -55,7 +77,10 @@ module Cucumber
55
77
  # that will be used by the {EventBus} by default.
56
78
  def self.registry
57
79
  build_registry(
80
+ Envelope,
58
81
  GherkinSourceParsed,
82
+ TestStepCreated,
83
+ TestCaseCreated,
59
84
  TestCaseStarted,
60
85
  TestStepStarted,
61
86
  TestStepFinished,
@@ -7,24 +7,27 @@ module Cucumber
7
7
  ParseError = Class.new(StandardError)
8
8
 
9
9
  class Parser
10
- attr_reader :receiver, :event_bus
11
- private :receiver, :event_bus
10
+ attr_reader :receiver, :event_bus, :gherkin_query
11
+ private :receiver, :event_bus, :gherkin_query
12
12
 
13
- def initialize(receiver, event_bus)
13
+ def initialize(receiver, event_bus, gherkin_query)
14
14
  @receiver = receiver
15
15
  @event_bus = event_bus
16
+ @gherkin_query = gherkin_query
16
17
  end
17
18
 
18
19
  def document(document)
19
20
  messages = ::Gherkin.from_source(document.uri, document.body, gherkin_options(document))
20
21
  messages.each do |message|
21
- if !message.gherkinDocument.nil?
22
- event_bus.gherkin_source_parsed(message.gherkinDocument)
22
+ event_bus.envelope(message)
23
+ gherkin_query.update(message)
24
+ if !message.gherkin_document.nil?
25
+ event_bus.gherkin_source_parsed(message.gherkin_document)
23
26
  elsif !message.pickle.nil?
24
27
  receiver.pickle(message.pickle)
25
28
  elsif !message.attachment.nil?
26
29
  # Parse error
27
- raise Core::Gherkin::ParseError.new("#{document.uri}: #{message.attachment.data}")
30
+ raise Core::Gherkin::ParseError.new("#{document.uri}: #{message.attachment.text}")
28
31
  else
29
32
  raise "Unknown message: #{message.to_hash}"
30
33
  end
@@ -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
@@ -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
  %{ """>}
@@ -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::TestStepResult.new(
48
+ status: Cucumber::Messages::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::TestStepResult.new(
79
+ status: Cucumber::Messages::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::TestStepResult.new(
132
+ status: Cucumber::Messages::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::TestStepResult.new(
220
+ status: Cucumber::Messages::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::TestStepResult.new(
245
+ status: Cucumber::Messages::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::TestStepResult.new(
270
+ status: Cucumber::Messages::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,7 +278,7 @@ module Cucumber
229
278
  class StrictConfiguration
230
279
  attr_accessor :settings
231
280
  private :settings
232
-
281
+
233
282
  def initialize(strict_types = [])
234
283
  @settings = Hash[STRICT_AFFECTED_TYPES.map { |t| [t, :default] }]
235
284
  strict_types.each do |type|
@@ -329,7 +378,7 @@ 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)
@@ -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