cucumber 3.2.0 → 5.2.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +280 -19
  3. data/CONTRIBUTING.md +11 -25
  4. data/README.md +4 -5
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber_mixin.rb +46 -53
  7. data/lib/cucumber/cli/configuration.rb +5 -5
  8. data/lib/cucumber/cli/main.rb +12 -12
  9. data/lib/cucumber/cli/options.rb +90 -73
  10. data/lib/cucumber/cli/profile_loader.rb +49 -26
  11. data/lib/cucumber/configuration.rb +44 -29
  12. data/lib/cucumber/constantize.rb +2 -5
  13. data/lib/cucumber/deprecate.rb +31 -7
  14. data/lib/cucumber/errors.rb +5 -7
  15. data/lib/cucumber/events/envelope.rb +9 -0
  16. data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
  17. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  18. data/lib/cucumber/events/step_activated.rb +2 -1
  19. data/lib/cucumber/events/test_case_created.rb +13 -0
  20. data/lib/cucumber/events/test_case_ready.rb +12 -0
  21. data/lib/cucumber/events/test_step_created.rb +13 -0
  22. data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
  23. data/lib/cucumber/events.rb +13 -6
  24. data/lib/cucumber/file_specs.rb +6 -6
  25. data/lib/cucumber/filters/activate_steps.rb +5 -3
  26. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  27. data/lib/cucumber/filters/prepare_world.rb +5 -9
  28. data/lib/cucumber/filters/quit.rb +1 -3
  29. data/lib/cucumber/filters/tag_limits/verifier.rb +2 -4
  30. data/lib/cucumber/filters.rb +1 -0
  31. data/lib/cucumber/formatter/ansicolor.rb +40 -45
  32. data/lib/cucumber/formatter/ast_lookup.rb +163 -0
  33. data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
  34. data/lib/cucumber/formatter/console.rb +58 -66
  35. data/lib/cucumber/formatter/console_counts.rb +4 -9
  36. data/lib/cucumber/formatter/console_issues.rb +6 -3
  37. data/lib/cucumber/formatter/duration.rb +1 -1
  38. data/lib/cucumber/formatter/duration_extractor.rb +3 -1
  39. data/lib/cucumber/formatter/errors.rb +6 -0
  40. data/lib/cucumber/formatter/fanout.rb +2 -0
  41. data/lib/cucumber/formatter/html.rb +11 -598
  42. data/lib/cucumber/formatter/http_io.rb +43 -42
  43. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  44. data/lib/cucumber/formatter/interceptor.rb +11 -30
  45. data/lib/cucumber/formatter/io.rb +46 -10
  46. data/lib/cucumber/formatter/json.rb +102 -116
  47. data/lib/cucumber/formatter/junit.rb +55 -55
  48. data/lib/cucumber/formatter/message.rb +22 -0
  49. data/lib/cucumber/formatter/message_builder.rb +255 -0
  50. data/lib/cucumber/formatter/pretty.rb +359 -153
  51. data/lib/cucumber/formatter/progress.rb +30 -32
  52. data/lib/cucumber/formatter/publish_banner_printer.rb +77 -0
  53. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  54. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  55. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  56. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  57. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  58. data/lib/cucumber/formatter/rerun.rb +22 -4
  59. data/lib/cucumber/formatter/stepdefs.rb +1 -2
  60. data/lib/cucumber/formatter/steps.rb +3 -4
  61. data/lib/cucumber/formatter/summary.rb +16 -8
  62. data/lib/cucumber/formatter/unicode.rb +15 -17
  63. data/lib/cucumber/formatter/url_reporter.rb +17 -0
  64. data/lib/cucumber/formatter/usage.rb +11 -10
  65. data/lib/cucumber/gherkin/data_table_parser.rb +17 -6
  66. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +13 -17
  67. data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
  68. data/lib/cucumber/gherkin/steps_parser.rb +17 -8
  69. data/lib/cucumber/glue/hook.rb +34 -11
  70. data/lib/cucumber/glue/invoke_in_world.rb +13 -18
  71. data/lib/cucumber/glue/proto_world.rb +42 -33
  72. data/lib/cucumber/glue/registry_and_more.rb +42 -12
  73. data/lib/cucumber/glue/snippet.rb +23 -22
  74. data/lib/cucumber/glue/step_definition.rb +42 -19
  75. data/lib/cucumber/glue/world_factory.rb +1 -1
  76. data/lib/cucumber/hooks.rb +11 -11
  77. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -2
  78. data/lib/cucumber/multiline_argument/data_table.rb +97 -64
  79. data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
  80. data/lib/cucumber/multiline_argument.rb +4 -6
  81. data/lib/cucumber/platform.rb +3 -3
  82. data/lib/cucumber/rake/task.rb +16 -18
  83. data/lib/cucumber/rspec/disable_option_parser.rb +9 -8
  84. data/lib/cucumber/rspec/doubles.rb +3 -5
  85. data/lib/cucumber/running_test_case.rb +2 -53
  86. data/lib/cucumber/runtime/after_hooks.rb +8 -4
  87. data/lib/cucumber/runtime/before_hooks.rb +8 -4
  88. data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
  89. data/lib/cucumber/runtime/step_hooks.rb +6 -2
  90. data/lib/cucumber/runtime/support_code.rb +13 -15
  91. data/lib/cucumber/runtime/user_interface.rb +6 -16
  92. data/lib/cucumber/runtime.rb +41 -58
  93. data/lib/cucumber/step_definition_light.rb +4 -3
  94. data/lib/cucumber/step_definitions.rb +2 -2
  95. data/lib/cucumber/step_match.rb +12 -11
  96. data/lib/cucumber/step_match_search.rb +2 -1
  97. data/lib/cucumber/term/ansicolor.rb +9 -9
  98. data/lib/cucumber/term/banner.rb +56 -0
  99. data/lib/cucumber/version +1 -1
  100. data/lib/cucumber.rb +1 -1
  101. metadata +253 -80
  102. data/lib/cucumber/formatter/cucumber.css +0 -286
  103. data/lib/cucumber/formatter/cucumber.sass +0 -247
  104. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
  105. data/lib/cucumber/formatter/html_builder.rb +0 -121
  106. data/lib/cucumber/formatter/inline-js.js +0 -30
  107. data/lib/cucumber/formatter/jquery-min.js +0 -154
  108. data/lib/cucumber/formatter/json_pretty.rb +0 -11
  109. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  110. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  111. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  112. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  113. data/lib/cucumber/step_argument.rb +0 -25
@@ -5,9 +5,7 @@ require 'cucumber/gherkin/formatter/ansi_escapes'
5
5
  begin
6
6
  # Support Rake > 0.8.7
7
7
  require 'rake/dsl_definition'
8
- # rubocop:disable Lint/HandleExceptions
9
8
  rescue LoadError
10
- # rubocop:enable Lint/HandleExceptions
11
9
  end
12
10
 
13
11
  module Cucumber
@@ -38,8 +36,8 @@ module Cucumber
38
36
  attr_reader :args
39
37
 
40
38
  def initialize(libs, cucumber_opts, feature_files)
41
- raise 'libs must be an Array when running in-process' unless Array === libs
42
- libs.reverse.each { |lib| $LOAD_PATH.unshift(lib) }
39
+ raise 'libs must be an Array when running in-process' unless Array == libs.class
40
+ libs.reverse_each { |lib| $LOAD_PATH.unshift(lib) }
43
41
  @args = (
44
42
  cucumber_opts +
45
43
  feature_files
@@ -65,11 +63,11 @@ module Cucumber
65
63
  end
66
64
 
67
65
  def load_path
68
- [format('"%s"', @libs.join(File::PATH_SEPARATOR))]
66
+ [format('"%<path>s"', path: @libs.join(File::PATH_SEPARATOR))]
69
67
  end
70
68
 
71
69
  def quoted_binary(cucumber_bin)
72
- [format('"%s"', cucumber_bin)]
70
+ [format('"%<path>s"', path: cucumber_bin)]
73
71
  end
74
72
 
75
73
  def use_bundler
@@ -98,9 +96,7 @@ module Cucumber
98
96
 
99
97
  def run
100
98
  sh cmd.join(' ') do |ok, res|
101
- if !ok
102
- exit res.exitstatus
103
- end
99
+ exit res.exitstatus unless ok
104
100
  end
105
101
  end
106
102
  end
@@ -113,9 +109,9 @@ module Cucumber
113
109
 
114
110
  # Extra options to pass to the cucumber binary. Can be overridden by the CUCUMBER_OPTS environment variable.
115
111
  # It's recommended to pass an Array, but if it's a String it will be #split by ' '.
116
- attr_accessor :cucumber_opts
112
+ attr_reader :cucumber_opts
117
113
  def cucumber_opts=(opts) #:nodoc:
118
- @cucumber_opts = String === opts ? opts.split(' ') : opts
114
+ @cucumber_opts = String == opts.class ? opts.split(' ') : opts
119
115
  end
120
116
 
121
117
  # Whether or not to fork a new ruby interpreter. Defaults to true. You may gain
@@ -134,12 +130,16 @@ module Cucumber
134
130
  # Note that this attribute has no effect if you don't run in forked mode.
135
131
  attr_accessor :bundler
136
132
 
133
+ # Name of the running task
134
+ attr_reader :task_name
135
+
137
136
  # Define Cucumber Rake task
138
137
  def initialize(task_name = 'cucumber', desc = 'Run Cucumber features')
139
- @task_name, @desc = task_name, desc
138
+ @task_name = task_name
139
+ @desc = desc
140
140
  @fork = true
141
141
  @libs = ['lib']
142
- @rcov_opts = %w{--rails --exclude osx\/objc,gems\/}
142
+ @rcov_opts = %w[--rails --exclude osx\/objc,gems\/]
143
143
  yield self if block_given?
144
144
  @binary = binary.nil? ? Cucumber::BINARY : File.expand_path(binary)
145
145
  define_task
@@ -154,18 +154,16 @@ module Cucumber
154
154
 
155
155
  def runner(_task_args = nil) #:nodoc:
156
156
  cucumber_opts = [(ENV['CUCUMBER_OPTS'] ? ENV['CUCUMBER_OPTS'].split(/\s+/) : nil) || cucumber_opts_with_profile]
157
- if @fork
158
- return ForkedCucumberRunner.new(libs, binary, cucumber_opts, bundler, feature_files)
159
- end
157
+ return ForkedCucumberRunner.new(libs, binary, cucumber_opts, bundler, feature_files) if fork
160
158
  InProcessCucumberRunner.new(libs, cucumber_opts, feature_files)
161
159
  end
162
160
 
163
161
  def cucumber_opts_with_profile #:nodoc:
164
- Array(cucumber_opts).concat Array(@profile).flat_map { |p| ['--profile', p] }
162
+ Array(cucumber_opts).concat(Array(@profile).flat_map { |p| ['--profile', p] })
165
163
  end
166
164
 
167
165
  def feature_files #:nodoc:
168
- make_command_line_safe(FileList[ ENV['FEATURE'] || [] ])
166
+ make_command_line_safe(FileList[ENV['FEATURE'] || []])
169
167
  end
170
168
 
171
169
  def make_command_line_safe(list)
@@ -9,16 +9,17 @@ module Spec #:nodoc:
9
9
  # will fail when running cucumber)
10
10
  class OptionParser < ::OptionParser #:nodoc:
11
11
  NEUTERED_RSPEC = Object.new
12
- def NEUTERED_RSPEC.method_missing(_m, *_args); self; end
12
+ def NEUTERED_RSPEC.method_missing(_method, *_args) # rubocop:disable Style/MissingRespondToMissing
13
+ self || super
14
+ end
13
15
 
14
- def self.method_added(m)
15
- unless @__neutering_rspec
16
- @__neutering_rspec = true
17
- define_method(m) do |*a|
18
- NEUTERED_RSPEC
19
- end
20
- @__neutering_rspec = false
16
+ def self.method_added(method)
17
+ return if @__neutering_rspec
18
+ @__neutering_rspec = true
19
+ define_method(method) do |*_a|
20
+ NEUTERED_RSPEC
21
21
  end
22
+ @__neutering_rspec = false
22
23
  end
23
24
  end
24
25
  end
@@ -13,9 +13,7 @@ Before do
13
13
  end
14
14
 
15
15
  After do
16
- begin
17
- RSpec::Mocks.verify
18
- ensure
19
- RSpec::Mocks.teardown
20
- end
16
+ RSpec::Mocks.verify
17
+ ensure
18
+ RSpec::Mocks.teardown
21
19
  end
@@ -15,45 +15,12 @@ module Cucumber
15
15
  # the passed / failed / undefined / skipped status of
16
16
  # the test case.
17
17
  #
18
- # The test case might come from a regular Scenario or
19
- # a Scenario outline. You can call the `#outline?`
20
- # predicate to find out. If it's from an outline,
21
- # you get a couple of extra methods.
22
18
  module RunningTestCase
23
19
  def self.new(test_case)
24
- Builder.new(test_case).running_test_case
20
+ TestCase.new(test_case)
25
21
  end
26
22
 
27
- class Builder
28
- def initialize(test_case)
29
- @test_case = test_case
30
- test_case.describe_source_to(self)
31
- end
32
-
33
- def feature(feature)
34
- end
35
-
36
- def scenario(_scenario)
37
- @factory = Scenario
38
- end
39
-
40
- def scenario_outline(_scenario)
41
- @factory = ScenarioOutlineExample
42
- end
43
-
44
- def examples_table(examples_table)
45
- end
46
-
47
- def examples_table_row(row)
48
- end
49
-
50
- def running_test_case
51
- @factory.new(@test_case)
52
- end
53
- end
54
- private_constant :Builder
55
-
56
- class Scenario < SimpleDelegator
23
+ class TestCase < SimpleDelegator
57
24
  def initialize(test_case, result = Core::Test::Result::Unknown.new)
58
25
  @test_case = test_case
59
26
  @result = result
@@ -85,27 +52,9 @@ module Cucumber
85
52
  tags.map &:name
86
53
  end
87
54
 
88
- def outline?
89
- false
90
- end
91
-
92
55
  def with_result(result)
93
56
  self.class.new(@test_case, result)
94
57
  end
95
58
  end
96
-
97
- class ScenarioOutlineExample < Scenario
98
- def outline?
99
- true
100
- end
101
-
102
- def scenario_outline
103
- self
104
- end
105
-
106
- def cell_values
107
- source.last.values
108
- end
109
- end
110
59
  end
111
60
  end
@@ -3,23 +3,27 @@
3
3
  module Cucumber
4
4
  class Runtime
5
5
  class AfterHooks
6
- def initialize(hooks, scenario)
6
+ def initialize(id_generator, hooks, scenario, event_bus)
7
7
  @hooks = hooks
8
8
  @scenario = scenario
9
+ @id_generator = id_generator
10
+ @event_bus = event_bus
9
11
  end
10
12
 
11
13
  def apply_to(test_case)
12
14
  test_case.with_steps(
13
- test_case.test_steps + after_hooks(test_case.source).reverse
15
+ test_case.test_steps + after_hooks.reverse
14
16
  )
15
17
  end
16
18
 
17
19
  private
18
20
 
19
- def after_hooks(source)
21
+ def after_hooks
20
22
  @hooks.map do |hook|
21
23
  action = ->(result) { hook.invoke('After', @scenario.with_result(result)) }
22
- Hooks.after_hook(source, hook.location, &action)
24
+ hook_step = Hooks.after_hook(@id_generator.new_id, hook.location, &action)
25
+ @event_bus.hook_test_step_created(hook_step, hook)
26
+ hook_step
23
27
  end
24
28
  end
25
29
  end
@@ -5,23 +5,27 @@ require 'cucumber/hooks'
5
5
  module Cucumber
6
6
  class Runtime
7
7
  class BeforeHooks
8
- def initialize(hooks, scenario)
8
+ def initialize(id_generator, hooks, scenario, event_bus)
9
9
  @hooks = hooks
10
10
  @scenario = scenario
11
+ @id_generator = id_generator
12
+ @event_bus = event_bus
11
13
  end
12
14
 
13
15
  def apply_to(test_case)
14
16
  test_case.with_steps(
15
- before_hooks(test_case.source) + test_case.test_steps
17
+ before_hooks + test_case.test_steps
16
18
  )
17
19
  end
18
20
 
19
21
  private
20
22
 
21
- def before_hooks(source)
23
+ def before_hooks
22
24
  @hooks.map do |hook|
23
25
  action_block = ->(result) { hook.invoke('Before', @scenario.with_result(result)) }
24
- Hooks.before_hook(source, hook.location, &action_block)
26
+ hook_step = Hooks.before_hook(@id_generator.new_id, hook.location, &action_block)
27
+ @event_bus.hook_test_step_created(hook_step, hook)
28
+ hook_step
25
29
  end
26
30
  end
27
31
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
- require 'cucumber/core/ast/doc_string'
4
+ require 'cucumber/core/test/doc_string'
5
5
 
6
6
  module Cucumber
7
7
  class Runtime
@@ -15,11 +15,13 @@ module Cucumber
15
15
  attr_reader :support_code
16
16
 
17
17
  def initialize(support_code, user_interface)
18
- @support_code, @user_interface = support_code, user_interface
18
+ @support_code = support_code
19
+ @user_interface = user_interface
19
20
  end
20
21
 
21
22
  def_delegators :@user_interface,
22
23
  :embed,
24
+ :attach,
23
25
  :ask,
24
26
  :puts,
25
27
  :features_paths,
@@ -3,8 +3,10 @@
3
3
  module Cucumber
4
4
  class Runtime
5
5
  class StepHooks
6
- def initialize(hooks)
6
+ def initialize(id_generator, hooks, event_bus)
7
7
  @hooks = hooks
8
+ @id_generator = id_generator
9
+ @event_bus = event_bus
8
10
  end
9
11
 
10
12
  def apply(test_steps)
@@ -18,7 +20,9 @@ module Cucumber
18
20
  def after_step_hooks(test_step)
19
21
  @hooks.map do |hook|
20
22
  action = ->(*args) { hook.invoke('AfterStep', [args, test_step]) }
21
- Hooks.after_step_hook(test_step.source, hook.location, &action)
23
+ hook_step = Hooks.after_step_hook(@id_generator.new_id, test_step, hook.location, &action)
24
+ @event_bus.hook_test_step_created(hook_step, hook)
25
+ hook_step
22
26
  end
23
27
  end
24
28
  end
@@ -22,19 +22,15 @@ module Cucumber
22
22
  end
23
23
 
24
24
  def step(step)
25
- location = Core::Ast::Location.of_caller
25
+ location = Core::Test::Location.of_caller
26
26
  @support_code.invoke_dynamic_step(step[:text], multiline_arg(step, location))
27
27
  end
28
28
 
29
29
  def multiline_arg(step, location)
30
- argument = step[:argument]
31
-
32
- if argument
33
- if argument[:type] == :DocString
34
- MultilineArgument.from(argument[:content], location, argument[:content_type])
35
- else
36
- MultilineArgument::DataTable.from(argument[:rows].map { |row| row[:cells].map { |cell| cell[:value] } })
37
- end
30
+ if !step[:doc_string].nil?
31
+ MultilineArgument.from(step[:doc_string][:content], location, step[:doc_string][:content_type])
32
+ elsif !step[:data_table].nil?
33
+ MultilineArgument::DataTable.from(step[:data_table][:rows].map { |row| row[:cells].map { |cell| cell[:value] } })
38
34
  else
39
35
  MultilineArgument.from(nil)
40
36
  end
@@ -62,8 +58,8 @@ module Cucumber
62
58
  # Given I have 8 cukes in my belly
63
59
  # Then I should not be thirsty
64
60
  # })
65
- def invoke_dynamic_steps(steps_text, i18n, _location)
66
- parser = Cucumber::Gherkin::StepsParser.new(StepInvoker.new(self), i18n.iso_code)
61
+ def invoke_dynamic_steps(steps_text, iso_code, _location)
62
+ parser = Cucumber::Gherkin::StepsParser.new(StepInvoker.new(self), iso_code)
67
63
  parser.parse(steps_text)
68
64
  end
69
65
 
@@ -108,26 +104,28 @@ module Cucumber
108
104
  def find_after_step_hooks(test_case)
109
105
  scenario = RunningTestCase.new(test_case)
110
106
  hooks = registry.hooks_for(:after_step, scenario)
111
- StepHooks.new hooks
107
+ StepHooks.new(@configuration.id_generator, hooks, @configuration.event_bus)
112
108
  end
113
109
 
114
110
  def apply_before_hooks(test_case)
111
+ return test_case if test_case.test_steps.empty?
115
112
  scenario = RunningTestCase.new(test_case)
116
113
  hooks = registry.hooks_for(:before, scenario)
117
- BeforeHooks.new(hooks, scenario).apply_to(test_case)
114
+ BeforeHooks.new(@configuration.id_generator, hooks, scenario, @configuration.event_bus).apply_to(test_case)
118
115
  end
119
116
 
120
117
  def apply_after_hooks(test_case)
118
+ return test_case if test_case.test_steps.empty?
121
119
  scenario = RunningTestCase.new(test_case)
122
120
  hooks = registry.hooks_for(:after, scenario)
123
- AfterHooks.new(hooks, scenario).apply_to(test_case)
121
+ AfterHooks.new(@configuration.id_generator, hooks, scenario, @configuration.event_bus).apply_to(test_case)
124
122
  end
125
123
 
126
124
  def find_around_hooks(test_case)
127
125
  scenario = RunningTestCase.new(test_case)
128
126
 
129
127
  registry.hooks_for(:around, scenario).map do |hook|
130
- Hooks.around_hook(test_case.source) do |run_scenario|
128
+ Hooks.around_hook do |run_scenario|
131
129
  hook.invoke('Around', scenario, &run_scenario)
132
130
  end
133
131
  end
@@ -7,14 +7,6 @@ module Cucumber
7
7
  module UserInterface
8
8
  attr_writer :visitor
9
9
 
10
- # Output +messages+ alongside the formatted output.
11
- # This is an alternative to using Kernel#puts - it will display
12
- # nicer, and in all outputs (in case you use several formatters)
13
- #
14
- def puts(*messages)
15
- @visitor.puts(*messages)
16
- end
17
-
18
10
  # Suspends execution and prompts +question+ to the console (STDOUT).
19
11
  # An operator (manual tester) can then enter a line of text and hit
20
12
  # <ENTER>. The entered text is returned, and both +question+ and
@@ -48,20 +40,18 @@ module Cucumber
48
40
  # be a path to a file, or if it's an image it may also be a Base64 encoded image.
49
41
  # The embedded data may or may not be ignored, depending on what kind of formatter(s) are active.
50
42
  #
51
- def embed(src, mime_type, label)
52
- @visitor.embed(src, mime_type, label)
43
+ def attach(src, media_type)
44
+ @visitor.attach(src, media_type)
53
45
  end
54
46
 
55
47
  private
56
48
 
57
49
  def mri_gets(timeout_seconds)
58
- begin
59
- Timeout.timeout(timeout_seconds) do
60
- STDIN.gets
61
- end
62
- rescue Timeout::Error
63
- nil
50
+ Timeout.timeout(timeout_seconds) do
51
+ STDIN.gets
64
52
  end
53
+ rescue Timeout::Error
54
+ nil
65
55
  end
66
56
 
67
57
  def jruby_gets(timeout_seconds)
@@ -1,9 +1,8 @@
1
- # -*- coding: utf-8 -*-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'fileutils'
5
- require 'multi_json'
6
4
  require 'cucumber/configuration'
5
+ require 'cucumber/create_meta'
7
6
  require 'cucumber/load_path'
8
7
  require 'cucumber/formatter/duration'
9
8
  require 'cucumber/file_specs'
@@ -11,6 +10,8 @@ require 'cucumber/filters'
11
10
  require 'cucumber/formatter/fanout'
12
11
  require 'cucumber/gherkin/i18n'
13
12
  require 'cucumber/step_match_search'
13
+ require 'cucumber/messages'
14
+ require 'sys/uname'
14
15
 
15
16
  module Cucumber
16
17
  module FixRuby21Bug9285
@@ -19,8 +20,8 @@ module Cucumber
19
20
  end
20
21
  end
21
22
 
22
- class FileException < Exception
23
- attr :path
23
+ class FileException < RuntimeError
24
+ attr_reader :path
24
25
 
25
26
  def initialize(original_exception, path)
26
27
  super(original_exception)
@@ -31,7 +32,7 @@ module Cucumber
31
32
  class FileNotFoundException < FileException
32
33
  end
33
34
 
34
- class FeatureFolderNotFoundException < Exception
35
+ class FeatureFolderNotFoundException < RuntimeError
35
36
  def initialize(path)
36
37
  @path = path
37
38
  end
@@ -54,7 +55,6 @@ module Cucumber
54
55
  def initialize(configuration = Configuration.default)
55
56
  @configuration = Configuration.new(configuration)
56
57
  @support_code = SupportCode.new(self, @configuration)
57
- @results = Formatter::LegacyApi::Results.new
58
58
  end
59
59
 
60
60
  # Allows you to take an existing runtime and change its configuration
@@ -65,6 +65,10 @@ module Cucumber
65
65
 
66
66
  require 'cucumber/wire/plugin'
67
67
  def run!
68
+ @configuration.notify :envelope, Cucumber::Messages::Envelope.new(
69
+ meta: Cucumber::CreateMeta.create_meta('cucumber-ruby', Cucumber::VERSION)
70
+ )
71
+
68
72
  load_step_definitions
69
73
  install_wire_plugin
70
74
  fire_after_configuration_hook
@@ -72,7 +76,7 @@ module Cucumber
72
76
  self.visitor = report
73
77
 
74
78
  receiver = Test::Runner.new(@configuration.event_bus)
75
- compile features, receiver, filters
79
+ compile features, receiver, filters, @configuration.event_bus
76
80
  @configuration.notify :test_run_finished
77
81
  end
78
82
 
@@ -84,14 +88,6 @@ module Cucumber
84
88
  @configuration.dry_run?
85
89
  end
86
90
 
87
- def scenarios(status = nil)
88
- @results.scenarios(status)
89
- end
90
-
91
- def steps(status = nil)
92
- @results.steps(status)
93
- end
94
-
95
91
  def unmatched_step_definitions
96
92
  @support_code.unmatched_step_definitions
97
93
  end
@@ -107,13 +103,12 @@ module Cucumber
107
103
  # Returns Ast::DocString for +string_without_triple_quotes+.
108
104
  #
109
105
  def doc_string(string_without_triple_quotes, content_type = '', _line_offset = 0)
110
- location = Core::Ast::Location.of_caller
111
- Core::Ast::DocString.new(string_without_triple_quotes, content_type, location)
106
+ Core::Test::DocString.new(string_without_triple_quotes, content_type)
112
107
  end
113
108
 
114
109
  private
115
110
 
116
- def fire_after_configuration_hook #:nodoc
111
+ def fire_after_configuration_hook #:nodoc:
117
112
  @support_code.fire_hook(:after_configuration, @configuration)
118
113
  end
119
114
 
@@ -143,14 +138,12 @@ module Cucumber
143
138
  end
144
139
 
145
140
  def initialize(path)
146
- begin
147
- @file = File.new(path)
148
- set_encoding
149
- rescue Errno::EACCES => e
150
- raise FileNotFoundException.new(e, File.expand_path(path))
151
- rescue Errno::ENOENT
152
- raise FeatureFolderNotFoundException.new(path)
153
- end
141
+ @file = File.new(path)
142
+ set_encoding
143
+ rescue Errno::EACCES => e
144
+ raise FileNotFoundException.new(e, File.expand_path(path))
145
+ rescue Errno::ENOENT
146
+ raise FeatureFolderNotFoundException, path
154
147
  end
155
148
 
156
149
  def read
@@ -162,7 +155,7 @@ module Cucumber
162
155
  def set_encoding
163
156
  @file.each do |line|
164
157
  if ENCODING_PATTERN =~ line
165
- @file.set_encoding $1
158
+ @file.set_encoding Regexp.last_match(1)
166
159
  break
167
160
  end
168
161
  break unless COMMENT_OR_EMPTY_LINE_PATTERN =~ line
@@ -171,16 +164,16 @@ module Cucumber
171
164
  end
172
165
  end
173
166
 
174
- require 'cucumber/formatter/legacy_api/adapter'
175
- require 'cucumber/formatter/legacy_api/runtime_facade'
176
- require 'cucumber/formatter/legacy_api/results'
177
167
  require 'cucumber/formatter/ignore_missing_messages'
178
168
  require 'cucumber/formatter/fail_fast'
169
+ require 'cucumber/formatter/publish_banner_printer'
179
170
  require 'cucumber/core/report/summary'
171
+
180
172
  def report
181
173
  return @report if @report
182
174
  reports = [summary_report] + formatters
183
175
  reports << fail_fast_report if @configuration.fail_fast?
176
+ reports << publish_banner_printer unless @configuration.publish_quiet?
184
177
  @report ||= Formatter::Fanout.new(reports)
185
178
  end
186
179
 
@@ -192,41 +185,32 @@ module Cucumber
192
185
  @fail_fast_report ||= Formatter::FailFast.new(@configuration)
193
186
  end
194
187
 
188
+ def publish_banner_printer
189
+ @publish_banner_printer ||= Formatter::PublishBannerPrinter.new(@configuration)
190
+ end
191
+
195
192
  def formatters
196
193
  @formatters ||=
197
- @configuration.formatter_factories do |factory, formatter_options, path_or_io, options|
198
- create_formatter(factory, formatter_options, path_or_io, options)
194
+ @configuration.formatter_factories do |factory, formatter_options, path_or_io|
195
+ create_formatter(factory, formatter_options, path_or_io)
199
196
  end
200
197
  end
201
198
 
202
- def create_formatter(factory, formatter_options, path_or_io, cli_options)
203
- if !legacy_formatter?(factory)
204
- if accept_options?(factory)
205
- return factory.new(@configuration, formatter_options) if path_or_io.nil?
206
- return factory.new(@configuration.with_options(out_stream: path_or_io),
207
- formatter_options)
208
- else
209
- return factory.new(@configuration) if path_or_io.nil?
210
- return factory.new(@configuration.with_options(out_stream: path_or_io))
211
- end
199
+ def create_formatter(factory, formatter_options, path_or_io)
200
+ if accept_options?(factory)
201
+ return factory.new(@configuration, formatter_options) if path_or_io.nil?
202
+ factory.new(@configuration.with_options(out_stream: path_or_io),
203
+ formatter_options)
204
+ else
205
+ return factory.new(@configuration) if path_or_io.nil?
206
+ factory.new(@configuration.with_options(out_stream: path_or_io))
212
207
  end
213
- results = Formatter::LegacyApi::Results.new
214
- runtime_facade = Formatter::LegacyApi::RuntimeFacade.new(results, @support_code, @configuration)
215
- formatter = factory.new(runtime_facade, path_or_io, cli_options)
216
- Formatter::LegacyApi::Adapter.new(
217
- Formatter::IgnoreMissingMessages.new(formatter),
218
- results, @configuration
219
- )
220
208
  end
221
209
 
222
210
  def accept_options?(factory)
223
211
  factory.instance_method(:initialize).arity > 1
224
212
  end
225
213
 
226
- def legacy_formatter?(factory)
227
- factory.instance_method(:initialize).arity > 2
228
- end
229
-
230
214
  def failure?
231
215
  if @configuration.wip?
232
216
  summary_report.test_cases.total_passed > 0
@@ -237,7 +221,7 @@ module Cucumber
237
221
  public :failure?
238
222
 
239
223
  require 'cucumber/core/test/filters'
240
- def filters
224
+ def filters # rubocop:disable Metrics/AbcSize
241
225
  tag_expressions = @configuration.tag_expressions
242
226
  name_regexps = @configuration.name_regexps
243
227
  tag_limits = @configuration.tag_limits
@@ -250,14 +234,13 @@ module Cucumber
250
234
  # TODO: can we just use Glue::RegistryAndMore's step definitions directly?
251
235
  step_match_search = StepMatchSearch.new(@support_code.registry.method(:step_matches), @configuration)
252
236
  filters << Filters::ActivateSteps.new(step_match_search, @configuration)
253
- @configuration.filters.each do |filter|
254
- filters << filter
255
- end
237
+ @configuration.filters.each { |filter| filters << filter }
256
238
  unless configuration.dry_run?
257
239
  filters << Filters::ApplyAfterStepHooks.new(@support_code)
258
240
  filters << Filters::ApplyBeforeHooks.new(@support_code)
259
241
  filters << Filters::ApplyAfterHooks.new(@support_code)
260
242
  filters << Filters::ApplyAroundHooks.new(@support_code)
243
+ filters << Filters::BroadcastTestCaseReadyEvent.new(@configuration)
261
244
  filters << Filters::BroadcastTestRunStartedEvent.new(@configuration)
262
245
  filters << Filters::Quit.new
263
246
  filters << Filters::Retry.new(@configuration)
@@ -273,7 +256,7 @@ module Cucumber
273
256
  end
274
257
 
275
258
  def install_wire_plugin
276
- Cucumber::Wire::Plugin.new(@configuration).install if @configuration.all_files_to_load.any? { |f| f =~ %r{\.wire$} }
259
+ Cucumber::Wire::Plugin.new(@configuration, @support_code.registry).install if @configuration.all_files_to_load.any? { |f| f =~ /\.wire$/ }
277
260
  end
278
261
 
279
262
  def log