cucumber 6.0.0 → 8.0.0.rc.1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +371 -168
  3. data/CONTRIBUTING.md +216 -55
  4. data/README.md +139 -21
  5. data/lib/autotest/cucumber_mixin.rb +5 -2
  6. data/lib/autotest/discover.rb +3 -2
  7. data/lib/cucumber/cli/configuration.rb +4 -1
  8. data/lib/cucumber/cli/main.rb +4 -3
  9. data/lib/cucumber/cli/options.rb +14 -4
  10. data/lib/cucumber/cli/profile_loader.rb +1 -5
  11. data/lib/cucumber/cli/rerun_file.rb +1 -1
  12. data/lib/cucumber/configuration.rb +5 -4
  13. data/lib/cucumber/constantize.rb +1 -1
  14. data/lib/cucumber/deprecate.rb +2 -1
  15. data/lib/cucumber/errors.rb +1 -1
  16. data/lib/cucumber/events/hook_test_step_created.rb +1 -2
  17. data/lib/cucumber/events/step_activated.rb +0 -6
  18. data/lib/cucumber/events/step_definition_registered.rb +0 -5
  19. data/lib/cucumber/events/test_case_created.rb +1 -2
  20. data/lib/cucumber/events/test_run_finished.rb +2 -1
  21. data/lib/cucumber/events/test_step_created.rb +1 -2
  22. data/lib/cucumber/events/undefined_parameter_type.rb +1 -2
  23. data/lib/cucumber/events.rb +2 -2
  24. data/lib/cucumber/file_specs.rb +2 -1
  25. data/lib/cucumber/filters/activate_steps.rb +1 -0
  26. data/lib/cucumber/filters/tag_limits/verifier.rb +1 -3
  27. data/lib/cucumber/filters/tag_limits.rb +1 -3
  28. data/lib/cucumber/formatter/ansicolor.rb +63 -70
  29. data/lib/cucumber/formatter/ast_lookup.rb +2 -2
  30. data/lib/cucumber/formatter/backtrace_filter.rb +1 -1
  31. data/lib/cucumber/formatter/console.rb +20 -4
  32. data/lib/cucumber/formatter/console_issues.rb +6 -1
  33. data/lib/cucumber/formatter/duration_extractor.rb +1 -0
  34. data/lib/cucumber/formatter/errors.rb +1 -0
  35. data/lib/cucumber/formatter/fanout.rb +1 -1
  36. data/lib/cucumber/formatter/http_io.rb +6 -1
  37. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  38. data/lib/cucumber/formatter/io.rb +3 -1
  39. data/lib/cucumber/formatter/json.rb +32 -26
  40. data/lib/cucumber/formatter/junit.rb +6 -3
  41. data/lib/cucumber/formatter/message.rb +2 -1
  42. data/lib/cucumber/formatter/message_builder.rb +11 -10
  43. data/lib/cucumber/formatter/pretty.rb +34 -23
  44. data/lib/cucumber/formatter/progress.rb +1 -0
  45. data/lib/cucumber/formatter/publish_banner_printer.rb +1 -1
  46. data/lib/cucumber/formatter/query/hook_by_test_step.rb +1 -0
  47. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +2 -0
  48. data/lib/cucumber/formatter/rerun.rb +2 -0
  49. data/lib/cucumber/formatter/steps.rb +5 -2
  50. data/lib/cucumber/formatter/summary.rb +1 -0
  51. data/lib/cucumber/formatter/unicode.rb +4 -4
  52. data/lib/cucumber/formatter/usage.rb +9 -7
  53. data/lib/cucumber/gherkin/data_table_parser.rb +2 -1
  54. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +2 -2
  55. data/lib/cucumber/gherkin/steps_parser.rb +1 -1
  56. data/lib/cucumber/glue/dsl.rb +19 -5
  57. data/lib/cucumber/glue/hook.rb +2 -1
  58. data/lib/cucumber/glue/invoke_in_world.rb +4 -4
  59. data/lib/cucumber/glue/proto_world.rb +12 -9
  60. data/lib/cucumber/glue/registry_and_more.rb +20 -5
  61. data/lib/cucumber/glue/registry_wrapper.rb +31 -0
  62. data/lib/cucumber/glue/step_definition.rb +9 -7
  63. data/lib/cucumber/hooks.rb +1 -0
  64. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -1
  65. data/lib/cucumber/multiline_argument/data_table.rb +58 -71
  66. data/lib/cucumber/platform.rb +2 -2
  67. data/lib/cucumber/rake/task.rb +10 -7
  68. data/lib/cucumber/rspec/disable_option_parser.rb +6 -3
  69. data/lib/cucumber/running_test_case.rb +1 -0
  70. data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
  71. data/lib/cucumber/runtime/support_code.rb +3 -0
  72. data/lib/cucumber/runtime/user_interface.rb +5 -4
  73. data/lib/cucumber/runtime.rb +42 -23
  74. data/lib/cucumber/step_match.rb +6 -10
  75. data/lib/cucumber/step_match_search.rb +3 -2
  76. data/lib/cucumber/term/ansicolor.rb +74 -50
  77. data/lib/cucumber/term/banner.rb +1 -0
  78. data/lib/cucumber/version +1 -1
  79. data/lib/cucumber.rb +2 -1
  80. data/lib/simplecov_setup.rb +1 -1
  81. metadata +90 -89
  82. data/lib/cucumber/core_ext/string.rb +0 -11
@@ -2,15 +2,17 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'cucumber/configuration'
5
- require 'cucumber/create_meta'
5
+ require 'cucumber/deprecate'
6
6
  require 'cucumber/load_path'
7
7
  require 'cucumber/formatter/duration'
8
8
  require 'cucumber/file_specs'
9
9
  require 'cucumber/filters'
10
10
  require 'cucumber/formatter/fanout'
11
11
  require 'cucumber/gherkin/i18n'
12
+ require 'cucumber/glue/registry_wrapper'
12
13
  require 'cucumber/step_match_search'
13
14
  require 'cucumber/messages'
15
+ require 'cucumber/runtime/meta_message_builder'
14
16
  require 'sys/uname'
15
17
 
16
18
  module Cucumber
@@ -24,8 +26,8 @@ module Cucumber
24
26
  attr_reader :path
25
27
 
26
28
  def initialize(original_exception, path)
27
- super(original_exception)
28
29
  @path = path
30
+ super(original_exception)
29
31
  end
30
32
  end
31
33
 
@@ -35,6 +37,7 @@ module Cucumber
35
37
  class FeatureFolderNotFoundException < RuntimeError
36
38
  def initialize(path)
37
39
  @path = path
40
+ super
38
41
  end
39
42
 
40
43
  def message
@@ -63,21 +66,22 @@ module Cucumber
63
66
  @support_code.configure(@configuration)
64
67
  end
65
68
 
66
- require 'cucumber/wire/plugin'
67
69
  def run!
68
70
  @configuration.notify :envelope, Cucumber::Messages::Envelope.new(
69
- meta: Cucumber::CreateMeta.create_meta('cucumber-ruby', Cucumber::VERSION)
71
+ meta: MetaMessageBuilder.build_meta_message
70
72
  )
71
73
 
72
74
  load_step_definitions
73
- install_wire_plugin
74
- fire_after_configuration_hook
75
+ fire_install_plugin_hook
76
+ fire_before_all_hook unless dry_run?
75
77
  # TODO: can we remove this state?
76
78
  self.visitor = report
77
79
 
78
80
  receiver = Test::Runner.new(@configuration.event_bus)
79
81
  compile features, receiver, filters, @configuration.event_bus
80
- @configuration.notify :test_run_finished
82
+ @configuration.notify :test_run_finished, !failure?
83
+
84
+ fire_after_all_hook unless dry_run?
81
85
  end
82
86
 
83
87
  def features_paths
@@ -106,10 +110,26 @@ module Cucumber
106
110
  Core::Test::DocString.new(string_without_triple_quotes, content_type)
107
111
  end
108
112
 
113
+ def failure?
114
+ if @configuration.wip?
115
+ summary_report.test_cases.total_passed > 0
116
+ else
117
+ !summary_report.ok?(@configuration.strict)
118
+ end
119
+ end
120
+
109
121
  private
110
122
 
111
- def fire_after_configuration_hook #:nodoc:
112
- @support_code.fire_hook(:after_configuration, @configuration)
123
+ def fire_install_plugin_hook # :nodoc:
124
+ @support_code.fire_hook(:install_plugin, @configuration, registry_wrapper)
125
+ end
126
+
127
+ def fire_before_all_hook # :nodoc:
128
+ @support_code.fire_hook(:before_all)
129
+ end
130
+
131
+ def fire_after_all_hook # :nodoc:
132
+ @support_code.fire_hook(:after_all)
113
133
  end
114
134
 
115
135
  require 'cucumber/core/gherkin/document'
@@ -130,8 +150,8 @@ module Cucumber
130
150
  end
131
151
 
132
152
  class NormalisedEncodingFile
133
- COMMENT_OR_EMPTY_LINE_PATTERN = /^\s*#|^\s*$/ #:nodoc:
134
- ENCODING_PATTERN = /^\s*#\s*encoding\s*:\s*([^\s]+)/ #:nodoc:
153
+ COMMENT_OR_EMPTY_LINE_PATTERN = /^\s*#|^\s*$/ # :nodoc:
154
+ ENCODING_PATTERN = /^\s*#\s*encoding\s*:\s*([^\s]+)/ # :nodoc:
135
155
 
136
156
  def self.read(path)
137
157
  new(path).read
@@ -171,6 +191,7 @@ module Cucumber
171
191
 
172
192
  def report
173
193
  return @report if @report
194
+
174
195
  reports = [summary_report] + formatters
175
196
  reports << fail_fast_report if @configuration.fail_fast?
176
197
  reports << publish_banner_printer unless @configuration.publish_quiet?
@@ -199,10 +220,12 @@ module Cucumber
199
220
  def create_formatter(factory, formatter_options, path_or_io)
200
221
  if accept_options?(factory)
201
222
  return factory.new(@configuration, formatter_options) if path_or_io.nil?
223
+
202
224
  factory.new(@configuration.with_options(out_stream: path_or_io),
203
225
  formatter_options)
204
226
  else
205
227
  return factory.new(@configuration) if path_or_io.nil?
228
+
206
229
  factory.new(@configuration.with_options(out_stream: path_or_io))
207
230
  end
208
231
  end
@@ -211,15 +234,6 @@ module Cucumber
211
234
  factory.instance_method(:initialize).arity > 1
212
235
  end
213
236
 
214
- def failure?
215
- if @configuration.wip?
216
- summary_report.test_cases.total_passed > 0
217
- else
218
- !summary_report.ok?(@configuration.strict)
219
- end
220
- end
221
- public :failure?
222
-
223
237
  require 'cucumber/core/test/filters'
224
238
  def filters # rubocop:disable Metrics/AbcSize
225
239
  tag_expressions = @configuration.tag_expressions
@@ -235,12 +249,17 @@ module Cucumber
235
249
  step_match_search = StepMatchSearch.new(@support_code.registry.method(:step_matches), @configuration)
236
250
  filters << Filters::ActivateSteps.new(step_match_search, @configuration)
237
251
  @configuration.filters.each { |filter| filters << filter }
252
+
238
253
  unless configuration.dry_run?
239
254
  filters << Filters::ApplyAfterStepHooks.new(@support_code)
240
255
  filters << Filters::ApplyBeforeHooks.new(@support_code)
241
256
  filters << Filters::ApplyAfterHooks.new(@support_code)
242
257
  filters << Filters::ApplyAroundHooks.new(@support_code)
243
- filters << Filters::BroadcastTestCaseReadyEvent.new(@configuration)
258
+ end
259
+
260
+ filters << Filters::BroadcastTestCaseReadyEvent.new(@configuration)
261
+
262
+ unless configuration.dry_run?
244
263
  filters << Filters::BroadcastTestRunStartedEvent.new(@configuration)
245
264
  filters << Filters::Quit.new
246
265
  filters << Filters::Retry.new(@configuration)
@@ -255,8 +274,8 @@ module Cucumber
255
274
  @support_code.load_files!(files)
256
275
  end
257
276
 
258
- def install_wire_plugin
259
- Cucumber::Wire::Plugin.new(@configuration, @support_code.registry).install if @configuration.all_files_to_load.any? { |f| f =~ /\.wire$/ }
277
+ def registry_wrapper
278
+ Cucumber::Glue::RegistryWrapper.new(@support_code.registry)
260
279
  end
261
280
 
262
281
  def log
@@ -4,11 +4,12 @@ require 'cucumber/multiline_argument'
4
4
 
5
5
  module Cucumber
6
6
  # Represents the match found between a Test Step and its activation
7
- class StepMatch #:nodoc:
7
+ class StepMatch # :nodoc:
8
8
  attr_reader :step_definition, :step_arguments
9
9
 
10
10
  def initialize(step_definition, step_name, step_arguments)
11
11
  raise "step_arguments can't be nil (but it can be an empty array)" if step_arguments.nil?
12
+
12
13
  @step_definition = step_definition
13
14
  @name_to_match = step_name
14
15
  @step_arguments = step_arguments
@@ -28,7 +29,7 @@ module Cucumber
28
29
  end
29
30
 
30
31
  def invoke(multiline_arg)
31
- all_args = deep_clone_args
32
+ all_args = args
32
33
  multiline_arg.append_to(all_args)
33
34
  @step_definition.invoke(all_args)
34
35
  end
@@ -90,15 +91,9 @@ module Cucumber
90
91
  s
91
92
  end
92
93
 
93
- def inspect #:nodoc:
94
+ def inspect # :nodoc:
94
95
  "#<#{self.class}: #{location}>"
95
96
  end
96
-
97
- private
98
-
99
- def deep_clone_args
100
- Marshal.load(Marshal.dump(args))
101
- end
102
97
  end
103
98
 
104
99
  class SkippingStepMatch
@@ -107,7 +102,7 @@ module Cucumber
107
102
  end
108
103
  end
109
104
 
110
- class NoStepMatch #:nodoc:
105
+ class NoStepMatch # :nodoc:
111
106
  attr_reader :step_definition, :name
112
107
 
113
108
  def initialize(step, name)
@@ -121,6 +116,7 @@ module Cucumber
121
116
 
122
117
  def location
123
118
  raise "No location for #{@step}" unless @step.location
119
+
124
120
  @step.location
125
121
  end
126
122
 
@@ -20,6 +20,7 @@ module Cucumber
20
20
  def call(step_name)
21
21
  result = @search.call(step_name)
22
22
  raise Cucumber::Ambiguous.new(step_name, result, @configuration.guess?) if result.length > 1
23
+
23
24
  result
24
25
  end
25
26
  end
@@ -35,7 +36,7 @@ module Cucumber
35
36
 
36
37
  private
37
38
 
38
- def best_matches(_step_name, step_matches) #:nodoc:
39
+ def best_matches(_step_name, step_matches) # :nodoc:
39
40
  no_groups = step_matches.select { |step_match| step_match.args.empty? }
40
41
  max_arg_length = step_matches.map { |step_match| step_match.args.length }.max
41
42
  top_groups = step_matches.select { |step_match| step_match.args.length == max_arg_length }
@@ -54,7 +55,7 @@ module Cucumber
54
55
 
55
56
  require 'delegate'
56
57
  class CachesStepMatch < SimpleDelegator
57
- def call(step_name) #:nodoc:
58
+ def call(step_name) # :nodoc:
58
59
  @match_cache ||= {}
59
60
 
60
61
  matches = @match_cache[step_name]
@@ -2,8 +2,28 @@
2
2
 
3
3
  module Cucumber
4
4
  module Term
5
- # The ANSIColor module can be used for namespacing and mixed into your own
6
- # classes.
5
+ # This module allows to colorize text using ANSI escape sequences.
6
+ #
7
+ # Include the module in your class and use its methods to colorize text.
8
+ #
9
+ # Example:
10
+ #
11
+ # require 'cucumber/term/ansicolor'
12
+ #
13
+ # class MyFormatter
14
+ # include Cucumber::Term::ANSIColor
15
+ #
16
+ # def initialize(config)
17
+ # $stdout.puts yellow("Initializing formatter")
18
+ # $stdout.puts green("Coloring is active \o/") if Cucumber::Term::ANSIColor.coloring?
19
+ # $stdout.puts grey("Feature path:") + blue(bold(config.feature_dirs))
20
+ # end
21
+ # end
22
+ #
23
+ # To see what colours and effects are available, just run this in your shell:
24
+ #
25
+ # ruby -e "require 'rubygems'; require 'cucumber/term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
26
+ #
7
27
  module ANSIColor
8
28
  # :stopdoc:
9
29
  ATTRIBUTES = [
@@ -27,6 +47,7 @@ module Cucumber
27
47
  [:magenta, 35],
28
48
  [:cyan, 36],
29
49
  [:white, 37],
50
+ [:grey, 90],
30
51
  [:on_black, 40],
31
52
  [:on_red, 41],
32
53
  [:on_green, 42],
@@ -40,72 +61,75 @@ module Cucumber
40
61
  ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
41
62
  # :startdoc:
42
63
 
43
- # Returns true, if the coloring function of this module
44
- # is switched on, false otherwise.
45
- def self.coloring?
46
- @coloring
47
- end
48
-
49
- # Turns the coloring on or off globally, so you can easily do
50
- # this for example:
51
- # Cucumber::Term::ANSIColor::coloring = STDOUT.isatty
52
- def self.coloring=(val)
53
- @coloring = val
54
- end
55
- self.coloring = true
56
-
57
- # rubocop:disable Security/Eval
58
- ATTRIBUTES.each do |c, v|
59
- eval <<-END_EVAL, binding, __FILE__, __LINE__ + 1
60
- def #{c}(string = nil)
61
- result = String.new
62
- result << "\e[#{v}m" if Cucumber::Term::ANSIColor.coloring?
63
- if block_given?
64
- result << yield
65
- elsif string
66
- result << string
67
- elsif respond_to?(:to_str)
68
- result << to_str
69
- else
70
- return result #only switch on
71
- end
72
- result << "\e[0m" if Cucumber::Term::ANSIColor.coloring?
73
- result
74
- end
75
- END_EVAL
76
- end
77
- # rubocop:enable Security/Eval
78
-
79
64
  # Regular expression that is used to scan for ANSI-sequences while
80
65
  # uncoloring strings.
81
66
  COLORED_REGEXP = /\e\[(?:[34][0-7]|[0-9])?m/
82
67
 
83
- def self.included(klass)
84
- return unless klass == String
85
- ATTRIBUTES.delete(:clear)
86
- ATTRIBUTE_NAMES.delete(:clear)
68
+ @coloring = true
69
+
70
+ class << self
71
+ # Turns the coloring on or off globally, so you can easily do
72
+ # this for example:
73
+ # Cucumber::Term::ANSIColor::coloring = $stdout.isatty
74
+ attr_accessor :coloring
75
+
76
+ # Returns true, if the coloring function of this module
77
+ # is switched on, false otherwise.
78
+ alias coloring? :coloring
79
+
80
+ def included(klass)
81
+ return unless klass == String
82
+
83
+ ATTRIBUTES.delete(:clear)
84
+ ATTRIBUTE_NAMES.delete(:clear)
85
+ end
87
86
  end
88
87
 
89
- # Returns an uncolored version of the string, that is all
88
+ ATTRIBUTES.each do |color_name, color_code|
89
+ define_method(color_name) do |text = nil, &block|
90
+ if block
91
+ colorize(block.call, color_code)
92
+ elsif text
93
+ colorize(text, color_code)
94
+ elsif respond_to?(:to_str)
95
+ colorize(to_str, color_code)
96
+ else
97
+ colorize(nil, color_code) # switch coloration on
98
+ end
99
+ end
100
+ end
101
+
102
+ # Returns an uncolored version of the string
90
103
  # ANSI-sequences are stripped from the string.
91
- def uncolored(string = nil)
104
+ def uncolored(text = nil)
92
105
  if block_given?
93
- yield.gsub(COLORED_REGEXP, '')
94
- elsif string
95
- string.gsub(COLORED_REGEXP, '')
106
+ uncolorize(yield)
107
+ elsif text
108
+ uncolorize(text)
96
109
  elsif respond_to?(:to_str)
97
- to_str.gsub(COLORED_REGEXP, '')
110
+ uncolorize(to_str)
98
111
  else
99
112
  ''
100
113
  end
101
114
  end
102
115
 
103
- module_function
104
-
105
116
  # Returns an array of all Cucumber::Term::ANSIColor attributes as symbols.
106
117
  def attributes
107
118
  ATTRIBUTE_NAMES
108
119
  end
120
+
121
+ private
122
+
123
+ def colorize(text, color_code)
124
+ return String.new(text || '') unless Cucumber::Term::ANSIColor.coloring?
125
+ return "\e[#{color_code}m" unless text
126
+
127
+ "\e[#{color_code}m#{text}\e[0m"
128
+ end
129
+
130
+ def uncolorize(string)
131
+ string.gsub(COLORED_REGEXP, '')
132
+ end
109
133
  end
110
134
  end
111
135
  end
@@ -30,6 +30,7 @@ module Cucumber
30
30
 
31
31
  def display_span(span)
32
32
  return apply_modifiers(span.shift, span) if span.is_a?(Array)
33
+
33
34
  span
34
35
  end
35
36
 
data/lib/cucumber/version CHANGED
@@ -1 +1 @@
1
- 6.0.0
1
+ 8.0.0.rc.1
data/lib/cucumber.rb CHANGED
@@ -14,7 +14,8 @@ module Cucumber
14
14
 
15
15
  def logger
16
16
  return @log if @log
17
- @log = Logger.new(STDOUT)
17
+
18
+ @log = Logger.new($stdout)
18
19
  @log.level = Logger::INFO
19
20
  @log
20
21
  end
@@ -7,7 +7,7 @@ if ENV['SIMPLECOV']
7
7
 
8
8
  require 'simplecov'
9
9
 
10
- SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/..'))
10
+ SimpleCov.root(File.expand_path("#{File.dirname(__FILE__)}/.."))
11
11
  SimpleCov.start do
12
12
  add_filter 'iso-8859-1_steps.rb'
13
13
  add_filter '.-ruby-core/'