cucumber-core 16.2.0 → 18.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -5
  3. data/LICENSE +14 -13
  4. data/lib/cucumber/core/compiler.rb +11 -10
  5. data/lib/cucumber/core/event.rb +12 -10
  6. data/lib/cucumber/core/event_bus.rb +1 -1
  7. data/lib/cucumber/core/events/base.rb +26 -0
  8. data/lib/cucumber/core/events/envelope.rb +13 -2
  9. data/lib/cucumber/core/events/gherkin_source_parsed.rb +12 -3
  10. data/lib/cucumber/core/events/test_case_created.rb +12 -6
  11. data/lib/cucumber/core/events/test_case_finished.rb +11 -1
  12. data/lib/cucumber/core/events/test_case_started.rb +12 -3
  13. data/lib/cucumber/core/events/test_step_created.rb +12 -6
  14. data/lib/cucumber/core/events/test_step_finished.rb +14 -4
  15. data/lib/cucumber/core/events/test_step_started.rb +12 -3
  16. data/lib/cucumber/core/gherkin/document.rb +16 -6
  17. data/lib/cucumber/core/gherkin/parser.rb +6 -10
  18. data/lib/cucumber/core/gherkin/writer/accepts_comments.rb +23 -0
  19. data/lib/cucumber/core/gherkin/writer/background.rb +3 -1
  20. data/lib/cucumber/core/gherkin/writer/doc_string.rb +3 -1
  21. data/lib/cucumber/core/gherkin/writer/example.rb +3 -1
  22. data/lib/cucumber/core/gherkin/writer/examples.rb +3 -1
  23. data/lib/cucumber/core/gherkin/writer/feature.rb +3 -1
  24. data/lib/cucumber/core/gherkin/writer/has_description.rb +21 -0
  25. data/lib/cucumber/core/gherkin/writer/has_elements.rb +47 -0
  26. data/lib/cucumber/core/gherkin/writer/has_options_initializer.rb +58 -0
  27. data/lib/cucumber/core/gherkin/writer/has_rows.rb +43 -0
  28. data/lib/cucumber/core/gherkin/writer/helpers.rb +6 -174
  29. data/lib/cucumber/core/gherkin/writer/indentation.rb +40 -0
  30. data/lib/cucumber/core/gherkin/writer/rule.rb +3 -1
  31. data/lib/cucumber/core/gherkin/writer/scenario.rb +3 -1
  32. data/lib/cucumber/core/gherkin/writer/scenario_outline.rb +3 -1
  33. data/lib/cucumber/core/gherkin/writer/step.rb +3 -1
  34. data/lib/cucumber/core/gherkin/writer/table.rb +4 -1
  35. data/lib/cucumber/core/report/summary.rb +2 -2
  36. data/lib/cucumber/core/test/action/defined.rb +3 -3
  37. data/lib/cucumber/core/test/action.rb +6 -6
  38. data/lib/cucumber/core/test/around_hook.rb +4 -4
  39. data/lib/cucumber/core/test/case.rb +27 -26
  40. data/lib/cucumber/core/test/data_table.rb +37 -39
  41. data/lib/cucumber/core/test/doc_string.rb +23 -23
  42. data/lib/cucumber/core/test/empty_multiline_argument.rb +8 -8
  43. data/lib/cucumber/core/test/filters/locations_filter.rb +1 -1
  44. data/lib/cucumber/core/test/filters/name_filter.rb +1 -1
  45. data/lib/cucumber/core/test/filters/tag_filter.rb +1 -1
  46. data/lib/cucumber/core/test/filters.rb +3 -3
  47. data/lib/cucumber/core/test/hook_step.rb +1 -1
  48. data/lib/cucumber/core/test/location.rb +1 -3
  49. data/lib/cucumber/core/test/result/ambiguous.rb +41 -0
  50. data/lib/cucumber/core/test/result/boolean_methods.rb +28 -0
  51. data/lib/cucumber/core/test/result/duration.rb +33 -0
  52. data/lib/cucumber/core/test/result/failed.rb +72 -0
  53. data/lib/cucumber/core/test/result/flaky.rb +21 -0
  54. data/lib/cucumber/core/test/result/passed.rb +57 -0
  55. data/lib/cucumber/core/test/result/pending.rb +41 -0
  56. data/lib/cucumber/core/test/result/raisable.rb +46 -0
  57. data/lib/cucumber/core/test/result/skipped.rb +41 -0
  58. data/lib/cucumber/core/test/result/summary.rb +89 -0
  59. data/lib/cucumber/core/test/result/undefined.rb +41 -0
  60. data/lib/cucumber/core/test/result/unknown.rb +40 -0
  61. data/lib/cucumber/core/test/result/unknown_duration.rb +26 -0
  62. data/lib/cucumber/core/test/result.rb +15 -458
  63. data/lib/cucumber/core/test/runner.rb +25 -22
  64. data/lib/cucumber/core/test/step.rb +22 -23
  65. data/lib/cucumber/core/test/tag.rb +2 -0
  66. data/lib/cucumber/core/test/timer.rb +2 -2
  67. data/lib/cucumber/core.rb +6 -5
  68. metadata +32 -16
  69. data/lib/cucumber/core/platform.rb +0 -17
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Gherkin
6
+ module Writer
7
+ module HasElements
8
+ include AcceptsComments
9
+
10
+ def self.included(base)
11
+ base.extend HasElementBuilders
12
+ end
13
+
14
+ def build(source = [])
15
+ elements.inject(source + statements) { |acc, el| el.build(acc) }
16
+ end
17
+
18
+ private
19
+
20
+ def elements
21
+ @elements ||= []
22
+ end
23
+
24
+ module HasElementBuilders
25
+ def elements(*names)
26
+ names.each { |name| element(name) }
27
+ end
28
+
29
+ private
30
+
31
+ def element(name)
32
+ define_method(name) do |*args, &source|
33
+ factory_name = String(name).split('_').map(&:capitalize).join
34
+ factory = Writer.const_get(factory_name)
35
+ factory.new(slurp_comments, *args).tap do |builder|
36
+ builder.instance_exec(&source) if source
37
+ elements << builder
38
+ end
39
+ self
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Gherkin
6
+ module Writer
7
+ module HasOptionsInitializer
8
+ def self.included(base)
9
+ base.extend HasDefaultKeyword
10
+ end
11
+
12
+ attr_reader :name, :options
13
+ private :name, :options
14
+
15
+ def initialize(*args)
16
+ @comments = args.shift if args.first.is_a?(Array)
17
+ @comments ||= []
18
+ @options = args.pop if args.last.is_a?(Hash)
19
+ @options ||= {}
20
+ @name = args.first
21
+ end
22
+
23
+ private
24
+
25
+ def comments_statement
26
+ @comments
27
+ end
28
+
29
+ def keyword
30
+ options.fetch(:keyword) { self.class.keyword }
31
+ end
32
+
33
+ def name_statement
34
+ "#{keyword}: #{name}".strip
35
+ end
36
+
37
+ def tag_statement
38
+ tags
39
+ end
40
+
41
+ def tags
42
+ options[:tags]
43
+ end
44
+
45
+ module HasDefaultKeyword
46
+ def default_keyword(keyword)
47
+ @keyword = keyword
48
+ end
49
+
50
+ def keyword
51
+ @keyword
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Gherkin
6
+ module Writer
7
+ module HasRows
8
+ def row(*cells)
9
+ rows << cells
10
+ end
11
+
12
+ def rows
13
+ @rows ||= []
14
+ end
15
+
16
+ private
17
+
18
+ def row_statements(indent = nil)
19
+ rows.map { |row| indent(table_row(row), indent) }
20
+ end
21
+
22
+ def table_row(row)
23
+ padded = pad(row)
24
+ "| #{padded.join(' | ')} |"
25
+ end
26
+
27
+ def pad(row)
28
+ row.map.with_index { |text, position| justify_cell(text, position) }
29
+ end
30
+
31
+ def column_length(column)
32
+ lengths = rows.transpose.map { |r| r.map(&:length).max }
33
+ lengths[column]
34
+ end
35
+
36
+ def justify_cell(cell, position)
37
+ cell.ljust(column_length(position))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,177 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Cucumber
4
- module Core
5
- module Gherkin
6
- module Writer
7
- module HasOptionsInitializer
8
- def self.included(base)
9
- base.extend HasDefaultKeyword
10
- end
3
+ require_relative 'accepts_comments'
11
4
 
12
- attr_reader :name, :options
13
- private :name, :options
14
-
15
- def initialize(*args)
16
- @comments = args.shift if args.first.is_a?(Array)
17
- @comments ||= []
18
- @options = args.pop if args.last.is_a?(Hash)
19
- @options ||= {}
20
- @name = args.first
21
- end
22
-
23
- private
24
-
25
- def comments_statement
26
- @comments
27
- end
28
-
29
- def keyword
30
- options.fetch(:keyword) { self.class.keyword }
31
- end
32
-
33
- def name_statement
34
- "#{keyword}: #{name}".strip
35
- end
36
-
37
- def tag_statement
38
- tags
39
- end
40
-
41
- def tags
42
- options[:tags]
43
- end
44
-
45
- module HasDefaultKeyword
46
- def default_keyword(keyword)
47
- @keyword = keyword
48
- end
49
-
50
- def keyword
51
- @keyword
52
- end
53
- end
54
- end
55
-
56
- module AcceptsComments
57
- def comment(line)
58
- comment_lines << "# #{line}"
59
- end
60
-
61
- def comment_lines
62
- @comment_lines ||= []
63
- end
64
-
65
- def slurp_comments
66
- comment_lines.tap { @comment_lines = nil }
67
- end
68
- end
69
-
70
- module HasElements
71
- include AcceptsComments
72
-
73
- def self.included(base)
74
- base.extend HasElementBuilders
75
- end
76
-
77
- def build(source = [])
78
- elements.inject(source + statements) { |acc, el| el.build(acc) }
79
- end
80
-
81
- private
82
-
83
- def elements
84
- @elements ||= []
85
- end
86
-
87
- module HasElementBuilders
88
- def elements(*names)
89
- names.each { |name| element(name) }
90
- end
91
-
92
- private
93
-
94
- def element(name)
95
- define_method(name) do |*args, &source|
96
- factory_name = String(name).split('_').map(&:capitalize).join
97
- factory = Writer.const_get(factory_name)
98
- factory.new(slurp_comments, *args).tap do |builder|
99
- builder.instance_exec(&source) if source
100
- elements << builder
101
- end
102
- self
103
- end
104
- end
105
- end
106
- end
107
-
108
- module Indentation
109
- def self.level(number)
110
- Module.new do
111
- define_method(:indent) do |string, amount = nil|
112
- return string if string.nil? || string.empty?
113
-
114
- amount ||= number
115
- "#{' ' * amount}#{string}"
116
- end
117
-
118
- define_method(:indent_level) do
119
- number
120
- end
121
-
122
- define_method(:prepare_statements) do |*statements|
123
- statements.flatten.compact.map { |s| indent(s) }
124
- end
125
- end
126
- end
127
- end
128
-
129
- module HasDescription
130
- private
131
-
132
- def description
133
- options.fetch(:description, '').split("\n").map(&:strip)
134
- end
135
-
136
- def description_statement
137
- description.map { |s| indent(s, 2) } unless description.empty?
138
- end
139
- end
140
-
141
- module HasRows
142
- def row(*cells)
143
- rows << cells
144
- end
145
-
146
- def rows
147
- @rows ||= []
148
- end
149
-
150
- private
151
-
152
- def row_statements(indent = nil)
153
- rows.map { |row| indent(table_row(row), indent) }
154
- end
155
-
156
- def table_row(row)
157
- padded = pad(row)
158
- "| #{padded.join(' | ')} |"
159
- end
160
-
161
- def pad(row)
162
- row.map.with_index { |text, position| justify_cell(text, position) }
163
- end
164
-
165
- def column_length(column)
166
- lengths = rows.transpose.map { |r| r.map(&:length).max }
167
- lengths[column]
168
- end
169
-
170
- def justify_cell(cell, position)
171
- cell.ljust(column_length(position))
172
- end
173
- end
174
- end
175
- end
176
- end
177
- end
5
+ require_relative 'has_description'
6
+ require_relative 'has_elements'
7
+ require_relative 'has_options_initializer'
8
+ require_relative 'has_rows'
9
+ require_relative 'indentation'
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Gherkin
6
+ module Writer
7
+ module Indentation
8
+ def indentation_level(number)
9
+ create_indent(number)
10
+ create_indent_level(number)
11
+ create_prepare_statements
12
+ end
13
+
14
+ private
15
+
16
+ def create_indent(number)
17
+ define_method(:indent) do |string, amount = nil|
18
+ return string if string.nil? || string.empty?
19
+
20
+ amount ||= number
21
+ "#{' ' * amount}#{string}"
22
+ end
23
+ end
24
+
25
+ def create_indent_level(number)
26
+ define_method(:indent_level) do
27
+ number
28
+ end
29
+ end
30
+
31
+ def create_prepare_statements
32
+ define_method(:prepare_statements) do |*statements|
33
+ statements.flatten.compact.map { |s| indent(s) }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -12,7 +12,9 @@ module Cucumber
12
12
  include HasElements
13
13
  include HasOptionsInitializer
14
14
  include HasDescription
15
- include Indentation.level 2
15
+ extend Indentation
16
+
17
+ indentation_level 2
16
18
 
17
19
  default_keyword 'Rule'
18
20
 
@@ -10,7 +10,9 @@ module Cucumber
10
10
  include HasElements
11
11
  include HasOptionsInitializer
12
12
  include HasDescription
13
- include Indentation.level 2
13
+ extend Indentation
14
+
15
+ indentation_level 2
14
16
 
15
17
  default_keyword 'Scenario'
16
18
 
@@ -10,7 +10,9 @@ module Cucumber
10
10
  include HasElements
11
11
  include HasOptionsInitializer
12
12
  include HasDescription
13
- include Indentation.level 2
13
+ extend Indentation
14
+
15
+ indentation_level 2
14
16
 
15
17
  default_keyword 'Scenario Outline'
16
18
 
@@ -11,7 +11,9 @@ module Cucumber
11
11
  class Step
12
12
  include HasElements
13
13
  include HasOptionsInitializer
14
- include Indentation.level 4
14
+ extend Indentation
15
+
16
+ indentation_level 4
15
17
 
16
18
  default_keyword 'Given'
17
19
 
@@ -7,7 +7,10 @@ module Cucumber
7
7
  module Gherkin
8
8
  module Writer
9
9
  class Table
10
- include Indentation.level(6)
10
+ extend Indentation
11
+
12
+ indentation_level 6
13
+
11
14
  include HasRows
12
15
 
13
16
  def initialize(*); end
@@ -13,8 +13,8 @@ module Cucumber
13
13
  subscribe_to(event_bus)
14
14
  end
15
15
 
16
- def ok?(strict: Test::Result::StrictConfiguration.new)
17
- test_cases.ok?(strict: strict)
16
+ def ok?
17
+ test_cases.ok?
18
18
  end
19
19
 
20
20
  private
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cucumber/core/test/location'
4
- require 'cucumber/core/test/result'
5
- require 'cucumber/core/test/timer'
3
+ require_relative '../location'
4
+ require_relative '../result'
5
+ require_relative '../timer'
6
6
 
7
7
  module Cucumber
8
8
  module Core
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cucumber/core/test/location'
4
- require 'cucumber/core/test/result'
5
- require 'cucumber/core/test/timer'
3
+ require_relative 'location'
4
+ require_relative 'result'
5
+ require_relative 'timer'
6
6
 
7
- require 'cucumber/core/test/action/defined'
8
- require 'cucumber/core/test/action/undefined'
9
- require 'cucumber/core/test/action/unskippable'
7
+ require_relative 'action/defined'
8
+ require_relative 'action/undefined'
9
+ require_relative 'action/unskippable'
@@ -13,10 +13,6 @@ module Cucumber
13
13
  visitor.around_hook(self, *, &)
14
14
  end
15
15
 
16
- def hook?
17
- true
18
- end
19
-
20
16
  def execute(*_args, &continue)
21
17
  @timer.start
22
18
  @block.call(continue)
@@ -27,6 +23,10 @@ module Cucumber
27
23
  failed(e)
28
24
  end
29
25
 
26
+ def hook?
27
+ true
28
+ end
29
+
30
30
  private
31
31
 
32
32
  def failed(exception)
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cucumber/core/test/result'
4
3
  require 'cucumber/tag_expressions'
5
4
 
5
+ require_relative 'result'
6
+
6
7
  module Cucumber
7
8
  module Core
8
9
  module Test
@@ -22,8 +23,8 @@ module Cucumber
22
23
  @around_hooks = around_hooks
23
24
  end
24
25
 
25
- def step_count
26
- test_steps.count
26
+ def ==(other)
27
+ eql?(other)
27
28
  end
28
29
 
29
30
  def describe_to(visitor, *args)
@@ -37,20 +38,25 @@ module Cucumber
37
38
  self
38
39
  end
39
40
 
40
- def with_steps(test_steps)
41
- self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
41
+ def eql?(other)
42
+ other.hash == hash
42
43
  end
43
44
 
44
- def with_around_hooks(around_hooks)
45
- self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
45
+ def hash
46
+ location.hash
46
47
  end
47
48
 
48
- def match_tags?(*expressions)
49
- expressions.flatten.all? { |expression| match_single_tag_expression?(expression) }
49
+ def inspect
50
+ "#<#{self.class}: #{location}>"
50
51
  end
51
52
 
52
- def match_name?(name_regexp)
53
- name =~ name_regexp
53
+ def matching_locations
54
+ [
55
+ parent_locations,
56
+ location,
57
+ tags.map(&:location),
58
+ test_steps.map(&:matching_locations)
59
+ ].flatten
54
60
  end
55
61
 
56
62
  def match_locations?(queried_locations)
@@ -61,29 +67,24 @@ module Cucumber
61
67
  end
62
68
  end
63
69
 
64
- def matching_locations
65
- [
66
- parent_locations,
67
- location,
68
- tags.map(&:location),
69
- test_steps.map(&:matching_locations)
70
- ].flatten
70
+ def match_name?(name_regexp)
71
+ name =~ name_regexp
71
72
  end
72
73
 
73
- def inspect
74
- "#<#{self.class}: #{location}>"
74
+ def match_tags?(*expressions)
75
+ expressions.flatten.all? { |expression| match_single_tag_expression?(expression) }
75
76
  end
76
77
 
77
- def hash
78
- location.hash
78
+ def step_count
79
+ test_steps.count
79
80
  end
80
81
 
81
- def eql?(other)
82
- other.hash == hash
82
+ def with_around_hooks(around_hooks)
83
+ self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
83
84
  end
84
85
 
85
- def ==(other)
86
- eql?(other)
86
+ def with_steps(test_steps)
87
+ self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
87
88
  end
88
89
 
89
90
  private