cucumber 6.0.0 → 8.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -24,8 +24,12 @@ module Cucumber
24
24
  "#{INDENT}the usage formatter, except that steps are not printed."],
25
25
  'junit' => ['Cucumber::Formatter::Junit', "Generates a report similar to Ant+JUnit. Use\n" \
26
26
  "#{INDENT}junit,fileattribute=true to include a file attribute."],
27
- 'json' => ['Cucumber::Formatter::Json', '[DEPRECATED] Prints the feature as JSON'],
28
- 'message' => ['Cucumber::Formatter::Message', 'Outputs protobuf messages'],
27
+ 'json' => ['Cucumber::Formatter::Json', "Prints the feature as JSON.\n" \
28
+ "#{INDENT}The JSON format is in maintenance mode.\n" \
29
+ "#{INDENT}Please consider using the message formatter\n"\
30
+ "#{INDENT}with the standalone json-formatter\n" \
31
+ "#{INDENT}(https://github.com/cucumber/cucumber/tree/master/json-formatter)."],
32
+ 'message' => ['Cucumber::Formatter::Message', 'Prints each message in NDJSON form, which can then be consumed by other tools.'],
29
33
  'html' => ['Cucumber::Formatter::HTML', 'Outputs HTML report'],
30
34
  'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
31
35
  }.freeze
@@ -59,13 +63,13 @@ module Cucumber
59
63
  '--lines', '--port', '-I', '--snippet-type'
60
64
  ].freeze
61
65
  ORDER_TYPES = %w[defined random].freeze
62
- TAG_LIMIT_MATCHER = /(?<tag_name>\@\w+):(?<limit>\d+)/x
66
+ TAG_LIMIT_MATCHER = /(?<tag_name>@\w+):(?<limit>\d+)/x
63
67
 
64
68
  def self.parse(args, out_stream, error_stream, options = {})
65
69
  new(out_stream, error_stream, options).parse!(args)
66
70
  end
67
71
 
68
- def initialize(out_stream = STDOUT, error_stream = STDERR, options = {})
72
+ def initialize(out_stream = $stdout, error_stream = $stderr, options = {})
69
73
  @out_stream = out_stream
70
74
  @error_stream = error_stream
71
75
 
@@ -176,6 +180,7 @@ Specify SEED to reproduce the shuffling from a previous run.
176
180
  def check_formatter_stream_conflicts
177
181
  streams = @options[:formats].uniq.map { |(_, _, stream)| stream }
178
182
  return if streams == streams.uniq
183
+
179
184
  raise 'All but one formatter must use --out, only one can print to each stream (or STDOUT)'
180
185
  end
181
186
 
@@ -199,6 +204,7 @@ Specify SEED to reproduce the shuffling from a previous run.
199
204
 
200
205
  def truthy_string?(str)
201
206
  return false if str.nil?
207
+
202
208
  str !~ /^(false|no|0)$/i
203
209
  end
204
210
 
@@ -363,6 +369,7 @@ Specify SEED to reproduce the shuffling from a previous run.
363
369
  def require_files(v)
364
370
  @options[:require] << v
365
371
  return unless Cucumber::JRUBY && File.directory?(v)
372
+
366
373
  require 'java'
367
374
  $CLASSPATH << v
368
375
  end
@@ -381,6 +388,7 @@ Specify SEED to reproduce the shuffling from a previous run.
381
388
  require 'gherkin/dialect'
382
389
 
383
390
  return indicate_invalid_language_and_exit(lang) unless ::Gherkin::DIALECTS.key?(lang)
391
+
384
392
  list_keywords_and_exit(lang)
385
393
  end
386
394
 
@@ -399,6 +407,7 @@ Specify SEED to reproduce the shuffling from a previous run.
399
407
  def add_tag(value)
400
408
  raise("Found tags option '#{value}'. '~@tag' is no longer supported, use 'not @tag' instead.") if value.include?('~')
401
409
  raise("Found tags option '#{value}'. '@tag1,@tag2' is no longer supported, use '@tag or @tag2' instead.") if value.include?(',')
410
+
402
411
  @options[:tag_expressions] << value.gsub(/(@\w+)(:\d+)?/, '\1')
403
412
  add_tag_limits(value)
404
413
  end
@@ -411,6 +420,7 @@ Specify SEED to reproduce the shuffling from a previous run.
411
420
 
412
421
  def add_tag_limit(tag_limits, tag_name, limit)
413
422
  raise "Inconsistent tag limits for #{tag_name}: #{tag_limits[tag_name]} and #{limit}" if tag_limits[tag_name] && tag_limits[tag_name] != limit
423
+
414
424
  tag_limits[tag_name] = limit
415
425
  end
416
426
 
@@ -75,11 +75,7 @@ Defined profiles in cucumber.yml:
75
75
  def process_configuration_file_with_erb
76
76
  require 'erb'
77
77
  begin
78
- @cucumber_erb = if RUBY_VERSION >= '2.6'
79
- ERB.new(IO.read(cucumber_file), trim_mode: '%').result(binding)
80
- else
81
- ERB.new(IO.read(cucumber_file), nil, '%').result(binding)
82
- end
78
+ @cucumber_erb = ERB.new(IO.read(cucumber_file), trim_mode: '%').result(binding)
83
79
  rescue StandardError
84
80
  raise(YmlLoadError, "cucumber.yml was found, but could not be parsed with ERB. Please refer to cucumber's documentation on correct profile usage.\n#{$ERROR_INFO.inspect}")
85
81
  end
@@ -10,7 +10,7 @@ module Cucumber
10
10
  end
11
11
 
12
12
  def self.real_path(path)
13
- path[1..-1] # remove leading @
13
+ path[1..]
14
14
  end
15
15
 
16
16
  def initialize(path)
@@ -176,12 +176,12 @@ module Cucumber
176
176
  end
177
177
 
178
178
  def support_to_load
179
- support_files = all_files_to_load.select { |f| f =~ %r{/support/} }
179
+ support_files = all_files_to_load.select { |f| f =~ /\/support\// }
180
180
 
181
181
  # env_files are separated from other_files so we can ensure env files
182
182
  # load first.
183
183
  #
184
- env_files = support_files.select { |f| f =~ %r{/support/env\..*} }
184
+ env_files = support_files.select { |f| f =~ /\/support\/env\..*/ }
185
185
  other_files = support_files - env_files
186
186
  env_files.reverse + other_files.reverse
187
187
  end
@@ -189,7 +189,7 @@ module Cucumber
189
189
  def all_files_to_load
190
190
  files = require_dirs.map do |path|
191
191
  path = path.tr('\\', '/') # In case we're on windows. Globs don't work with backslashes.
192
- path = path.gsub(/\/$/, '') # Strip trailing slash. # rubocop:disable Style/RegexpLiteral
192
+ path = path.gsub(/\/$/, '') # Strip trailing slash.
193
193
  File.directory?(path) ? Dir["#{path}/**/*"] : path
194
194
  end.flatten.uniq
195
195
  remove_excluded_files_from(files)
@@ -200,7 +200,7 @@ module Cucumber
200
200
  end
201
201
 
202
202
  def step_defs_to_load
203
- all_files_to_load.reject { |f| f =~ %r{/support/} }
203
+ all_files_to_load.reject { |f| f =~ /\/support\// }
204
204
  end
205
205
 
206
206
  def formatter_factories
@@ -283,6 +283,7 @@ module Cucumber
283
283
 
284
284
  def with_default_features_path(paths)
285
285
  return default_features_paths if paths.empty?
286
+
286
287
  paths
287
288
  end
288
289
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'cucumber/platform'
4
4
  module Cucumber
5
- module Constantize #:nodoc:
5
+ module Constantize # :nodoc:
6
6
  def constantize(camel_cased_word)
7
7
  try = 0
8
8
  begin
@@ -20,6 +20,7 @@ module Cucumber
20
20
  class CliOption
21
21
  def self.deprecate(stream, option, message, remove_after_version)
22
22
  return if stream.nil?
23
+
23
24
  stream.puts(
24
25
  AnsiString.failure_message(
25
26
  "\nWARNING: #{option} is deprecated" \
@@ -31,7 +32,7 @@ module Cucumber
31
32
 
32
33
  module ForUsers
33
34
  def self.call(message, method, remove_after_version)
34
- STDERR.puts AnsiString.failure_message(
35
+ $stderr.puts AnsiString.failure_message(
35
36
  "\nWARNING: ##{method} is deprecated" \
36
37
  " and will be removed after version #{remove_after_version}. #{message}.\n" \
37
38
  "(Called from #{caller(3..3).first})"
@@ -9,7 +9,7 @@ module Cucumber
9
9
  return result.with_message(with_prefix(result.message)) if result.is_a?(self)
10
10
 
11
11
  begin
12
- raise new(with_prefix(step_name)) # rubocop:disable Style/RaiseArgs
12
+ raise self, with_prefix(step_name)
13
13
  rescue StandardError => e
14
14
  e
15
15
  end
@@ -6,8 +6,7 @@ module Cucumber
6
6
  module Events
7
7
  # Event fired when a step is created from a hook
8
8
  class HookTestStepCreated < Core::Event.new(:test_step, :hook)
9
- attr_reader :test_step
10
- attr_reader :hook
9
+ attr_reader :test_step, :hook
11
10
  end
12
11
  end
13
12
  end
@@ -15,12 +15,6 @@ module Cucumber
15
15
  #
16
16
  # @return [Cucumber::StepMatch]
17
17
  attr_reader :step_match
18
-
19
- # @private
20
- def initialize(test_step, step_match)
21
- @test_step = test_step
22
- @step_match = step_match
23
- end
24
18
  end
25
19
  end
26
20
  end
@@ -10,11 +10,6 @@ module Cucumber
10
10
  #
11
11
  # @return [RbSupport::RbStepDefinition]
12
12
  attr_reader :step_definition
13
-
14
- # _@private
15
- def initialize(step_definition)
16
- @step_definition = step_definition
17
- end
18
13
  end
19
14
  end
20
15
  end
@@ -6,8 +6,7 @@ module Cucumber
6
6
  module Events
7
7
  # Event fired when a Test::Case is created from a Pickle
8
8
  class TestCaseCreated < Core::Event.new(:test_case, :pickle)
9
- attr_reader :test_case
10
- attr_reader :pickle
9
+ attr_reader :test_case, :pickle
11
10
  end
12
11
  end
13
12
  end
@@ -5,7 +5,8 @@ require 'cucumber/core/events'
5
5
  module Cucumber
6
6
  module Events
7
7
  # Event fired after all test cases have finished executing
8
- class TestRunFinished < Core::Event.new
8
+ class TestRunFinished < Core::Event.new(:success)
9
+ attr_reader :success
9
10
  end
10
11
  end
11
12
  end
@@ -6,8 +6,7 @@ module Cucumber
6
6
  module Events
7
7
  # Event fired when a TestStep is created from a PickleStep
8
8
  class TestStepCreated < Core::Event.new(:test_step, :pickle_step)
9
- attr_reader :test_step
10
- attr_reader :pickle_step
9
+ attr_reader :test_step, :pickle_step
11
10
  end
12
11
  end
13
12
  end
@@ -3,8 +3,7 @@ require 'cucumber/core/events'
3
3
  module Cucumber
4
4
  module Events
5
5
  class UndefinedParameterType < Core::Event.new(:type_name, :expression)
6
- attr_reader :type_name
7
- attr_reader :expression
6
+ attr_reader :type_name, :expression
8
7
  end
9
8
  end
10
9
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir[File.dirname(__FILE__) + '/events/*.rb'].map(&method(:require))
3
+ Dir["#{File.dirname(__FILE__)}/events/*.rb"].map(&method(:require))
4
4
 
5
5
  module Cucumber
6
6
  # Events tell you what's happening while Cucumber runs your features.
@@ -11,7 +11,7 @@ module Cucumber
11
11
  # To subscribe to an event, use {Cucumber::Configuration#on_event}
12
12
  #
13
13
  # @example
14
- # AfterConfiguration do |config|
14
+ # InstallPlugin do |config|
15
15
  # config.on_event :test_case_finished do |event|
16
16
  # puts event.result
17
17
  # end
@@ -5,7 +5,7 @@ require 'cucumber/core/test/location'
5
5
 
6
6
  module Cucumber
7
7
  class FileSpecs
8
- FILE_COLON_LINE_PATTERN = /^([\w\W]*?)(?::([\d:]+))?$/ #:nodoc:
8
+ FILE_COLON_LINE_PATTERN = /^([\w\W]*?)(?::([\d:]+))?$/ # :nodoc:
9
9
 
10
10
  def initialize(file_specs)
11
11
  Cucumber.logger.debug("Features:\n")
@@ -32,6 +32,7 @@ module Cucumber
32
32
 
33
33
  def locations
34
34
  return [Core::Test::Location.new(@file)] if @lines.empty?
35
+
35
36
  @lines.map { |line| Core::Test::Location.new(@file, line) }
36
37
  end
37
38
  end
@@ -52,6 +52,7 @@ module Cucumber
52
52
  end
53
53
  configuration.notify :step_activated, test_step, match
54
54
  return SkippingStepMatch.new if configuration.dry_run?
55
+
55
56
  match
56
57
  end
57
58
 
@@ -47,9 +47,7 @@ module Cucumber
47
47
  locations.count
48
48
  end
49
49
 
50
- attr_reader :tag_name
51
- attr_reader :limit
52
- attr_reader :locations
50
+ attr_reader :tag_name, :limit, :locations
53
51
  end
54
52
  end
55
53
  end
@@ -38,9 +38,7 @@ module Cucumber
38
38
 
39
39
  private
40
40
 
41
- attr_reader :gated_receiver
42
- attr_reader :test_case_index
43
- attr_reader :verifier
41
+ attr_reader :gated_receiver, :test_case_index, :verifier
44
42
  end
45
43
  end
46
44
  end
@@ -3,28 +3,48 @@
3
3
  require 'cucumber/platform'
4
4
  require 'cucumber/term/ansicolor'
5
5
 
6
- if Cucumber::WINDOWS_MRI
7
- unless ENV['ANSICON']
8
- STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows}
9
- Cucumber::Term::ANSIColor.coloring = false
10
- end
11
- end
12
-
13
- Cucumber::Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.key?('AUTOTEST')
6
+ Cucumber::Term::ANSIColor.coloring = false if !$stdout.tty? && !ENV.key?('AUTOTEST')
14
7
 
15
8
  module Cucumber
16
9
  module Formatter
17
- # Defines aliases for coloured output. You don't invoke any methods from this
18
- # module directly, but you can change the output colours by defining
19
- # a <tt>CUCUMBER_COLORS</tt> variable in your shell, very much like how you can
20
- # tweak the familiar POSIX command <tt>ls</tt> with
21
- # <a href="http://mipsisrisc.com/rambling/2008/06/27/lscolorsls_colors-now-with-linux-support/">$LSCOLORS/$LS_COLORS</a>
10
+ # This module allows to format cucumber related outputs using ANSI escape sequences.
11
+ #
12
+ # For example, it provides a `passed` method which returns the string with
13
+ # the ANSI escape sequence to format it green per default.
14
+ #
15
+ # To use this, include or extend it in your class.
16
+ #
17
+ # Example:
18
+ #
19
+ # require 'cucumber/formatter/ansicolor'
20
+ #
21
+ # class MyFormatter
22
+ # extend Cucumber::Term::ANSIColor
23
+ #
24
+ # def on_test_step_finished(event)
25
+ # $stdout.puts undefined(event.test_step) if event.result.undefined?
26
+ # $stdout.puts passed(event.test_step) if event.result.passed?
27
+ # end
28
+ # end
29
+ #
30
+ # This module also allows the user to customize the format of cucumber outputs
31
+ # using environment variables.
32
+ #
33
+ # For instance, if your shell has a black background and a green font (like the
34
+ # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
35
+ # steps to be white instead of green.
36
+ #
37
+ # Example:
38
+ #
39
+ # export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
22
40
  #
23
41
  # The colours that you can change are:
24
42
  #
25
43
  # * <tt>undefined</tt> - defaults to <tt>yellow</tt>
26
44
  # * <tt>pending</tt> - defaults to <tt>yellow</tt>
27
45
  # * <tt>pending_param</tt> - defaults to <tt>yellow,bold</tt>
46
+ # * <tt>flaky</tt> - defaults to <tt>yellow</tt>
47
+ # * <tt>flaky_param</tt> - defaults to <tt>yellow,bold</tt>
28
48
  # * <tt>failed</tt> - defaults to <tt>red</tt>
29
49
  # * <tt>failed_param</tt> - defaults to <tt>red,bold</tt>
30
50
  # * <tt>passed</tt> - defaults to <tt>green</tt>
@@ -36,26 +56,18 @@ module Cucumber
36
56
  # * <tt>comment</tt> - defaults to <tt>grey</tt>
37
57
  # * <tt>tag</tt> - defaults to <tt>cyan</tt>
38
58
  #
39
- # For instance, if your shell has a black background and a green font (like the
40
- # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
41
- # steps to be white instead of green.
42
- #
43
- # Although not listed, you can also use <tt>grey</tt>.
44
- #
45
- # Examples: (On Windows, use SET instead of export.)
46
- #
47
- # export CUCUMBER_COLORS="passed=white"
48
- # export CUCUMBER_COLORS="passed=white,bold:passed_param=white,bold,underline"
49
- #
50
59
  # To see what colours and effects are available, just run this in your shell:
51
60
  #
52
- # ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
61
+ # ruby -e "require 'rubygems'; require 'cucumber/term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
53
62
  #
54
63
  module ANSIColor
55
64
  include Cucumber::Term::ANSIColor
56
65
 
66
+ # :stopdoc:
57
67
  ALIASES = Hash.new do |h, k|
58
- h[Regexp.last_match(1)] + ',bold' if k.to_s =~ /(.*)_param/
68
+ next unless k.to_s =~ /(.*)_param/
69
+
70
+ "#{h[Regexp.last_match(1)]},bold"
59
71
  end.merge(
60
72
  'undefined' => 'yellow',
61
73
  'pending' => 'yellow',
@@ -67,15 +79,22 @@ module Cucumber
67
79
  'comment' => 'grey',
68
80
  'tag' => 'cyan'
69
81
  )
82
+ # :startdoc:
70
83
 
71
- if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
72
- ENV['CUCUMBER_COLORS'].split(':').each do |pair|
84
+ # Apply the custom color scheme
85
+ #
86
+ # example:
87
+ #
88
+ # apply_custom_colors('passed=white')
89
+ def apply_custom_colors(colors)
90
+ colors.split(':').each do |pair|
73
91
  a = pair.split('=')
74
92
  ALIASES[a[0]] = a[1]
75
93
  end
76
94
  end
95
+ apply_custom_colors(ENV['CUCUMBER_COLORS']) if ENV['CUCUMBER_COLORS']
77
96
 
78
- # Eval to define the color-named methods required by Term::ANSIColor.
97
+ # Define the color-named methods required by Term::ANSIColor.
79
98
  #
80
99
  # Examples:
81
100
  #
@@ -87,53 +106,18 @@ module Cucumber
87
106
  # red(bold(string, &proc)) + red
88
107
  # end
89
108
  ALIASES.each_key do |method_name|
90
- next if method_name =~ /.*_param/
91
- code = <<-COLOR
92
- def #{method_name}(string=nil, &proc)
93
- #{ALIASES[method_name].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name].split(',').length}
94
- end
95
- # This resets the colour to the non-param colour
96
- def #{method_name}_param(string=nil, &proc)
97
- #{ALIASES[method_name + '_param'].split(',').join('(') + '(string, &proc' + ')' * ALIASES[method_name + '_param'].split(',').length} + #{ALIASES[method_name].split(',').join(' + ')}
98
- end
99
- COLOR
100
- eval(code) # rubocop:disable Security/Eval
101
- end
109
+ next if method_name.end_with?('_param')
102
110
 
103
- def self.define_grey #:nodoc:
104
- gem 'genki-ruby-terminfo'
105
- require 'terminfo'
106
- case TermInfo.default_object.tigetnum('colors')
107
- when 0
108
- raise "Your terminal doesn't support colours."
109
- when 1
110
- ::Cucumber::Term::ANSIColor.coloring = false
111
- alias_method :grey, :white
112
- when 2..8
113
- alias_method :grey, :white # rubocop:disable Lint/DuplicateMethods
114
- else
115
- define_real_grey
116
- end
117
- rescue Exception => e # rubocop:disable Lint/RescueException
118
- if e.class.name == 'TermInfo::TermInfoError'
119
- STDERR.puts '*** WARNING ***'
120
- STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
121
- STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
122
- STDERR.puts "\n"
123
- alias_method :grey, :white
124
- else
125
- define_real_grey
111
+ define_method(method_name) do |text = nil, &proc|
112
+ apply_styles(ALIASES[method_name], text, &proc)
126
113
  end
127
- end
128
114
 
129
- def self.define_real_grey #:nodoc:
130
- define_method :grey do |string|
131
- ::Cucumber::Term::ANSIColor.coloring? ? "\e[90m#{string}\e[0m" : string
115
+ define_method("#{method_name}_param") do |text = nil, &proc|
116
+ apply_styles(ALIASES["#{method_name}_param"], text, &proc) + apply_styles(ALIASES[method_name])
132
117
  end
133
118
  end
134
119
 
135
- define_grey
136
-
120
+ # :stopdoc:
137
121
  def cukes(n)
138
122
  ('(::) ' * n).strip
139
123
  end
@@ -149,6 +133,15 @@ module Cucumber
149
133
  def yellow_cukes(n)
150
134
  blink(yellow(cukes(n)))
151
135
  end
136
+ # :startdoc:
137
+
138
+ private
139
+
140
+ def apply_styles(styles, text = nil, &proc)
141
+ styles.split(',').reverse.reduce(text) do |result, method_name|
142
+ send(method_name, result, &proc)
143
+ end
144
+ end
152
145
  end
153
146
  end
154
147
  end
@@ -45,11 +45,11 @@ module Cucumber
45
45
  break
46
46
  end
47
47
  break if node.previous_node.nil?
48
+
48
49
  node = node.previous_node
49
50
  end
50
51
  keyword = dialect.given_keywords.reject { |kw| kw == '* ' }[0] if keyword.nil?
51
- keyword = Cucumber::Gherkin::I18n.code_keyword_for(keyword)
52
- keyword
52
+ Cucumber::Gherkin::I18n.code_keyword_for(keyword)
53
53
  end
54
54
 
55
55
  ScenarioSource = Struct.new(:type, :scenario)
@@ -33,7 +33,7 @@ module Cucumber
33
33
  def exception
34
34
  return @exception if ::Cucumber.use_full_backtrace
35
35
 
36
- pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m # rubocop:disable Style/RegexpLiteral
36
+ pwd_pattern = /#{::Regexp.escape(::Dir.pwd)}\//m
37
37
  backtrace = @exception.backtrace.map { |line| line.gsub(pwd_pattern, './') }
38
38
 
39
39
  filtered = (backtrace || []).reject do |line|
@@ -34,7 +34,7 @@ module Cucumber
34
34
 
35
35
  def format_step(keyword, step_match, status, source_indent)
36
36
  comment = if source_indent
37
- c = ('# ' + step_match.location.to_s).indent(source_indent)
37
+ c = indent("# #{step_match.location}", source_indent)
38
38
  format_string(c, :comment)
39
39
  else
40
40
  ''
@@ -99,17 +99,20 @@ module Cucumber
99
99
  @io.puts(format_string(string, status))
100
100
  end
101
101
 
102
- def exception_message_string(e, indent)
102
+ def exception_message_string(e, indent_amount)
103
103
  message = "#{e.message} (#{e.class})".dup.force_encoding('UTF-8')
104
104
  message = linebreaks(message, ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
105
105
 
106
- "#{message}\n#{e.backtrace.join("\n")}".indent(indent)
106
+ indent("#{message}\n#{e.backtrace.join("\n")}", indent_amount)
107
107
  end
108
108
 
109
109
  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/10655
110
110
  def linebreaks(msg, max)
111
111
  return msg unless max && max > 0
112
- msg.gsub(/.{1,#{max}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }.rstrip
112
+
113
+ msg.gsub(/.{1,#{max}}(?:\s|\Z)/) do
114
+ (Regexp.last_match(0) + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n")
115
+ end.rstrip
113
116
  end
114
117
 
115
118
  def collect_snippet_data(test_step, ast_lookup)
@@ -150,6 +153,7 @@ module Cucumber
150
153
 
151
154
  def print_passing_wip(config, passed_test_cases, ast_lookup)
152
155
  return unless config.wip?
156
+
153
157
  messages = passed_test_cases.map do |test_case|
154
158
  scenario_source = ast_lookup.scenario_source(test_case)
155
159
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
@@ -170,6 +174,7 @@ module Cucumber
170
174
  def attach(src, media_type)
171
175
  return unless media_type == 'text/x.cucumber.log+plain'
172
176
  return unless @io
177
+
173
178
  @io.puts
174
179
  @io.puts(format_string(src, :tag))
175
180
  @io.flush
@@ -177,6 +182,7 @@ module Cucumber
177
182
 
178
183
  def print_profile_information
179
184
  return if @options[:skip_profile_information] || @options[:profiles].nil? || @options[:profiles].empty?
185
+
180
186
  do_print_profile_information(@options[:profiles])
181
187
  end
182
188
 
@@ -208,6 +214,14 @@ module Cucumber
208
214
  ].join("\n")
209
215
  end
210
216
 
217
+ def indent(string, padding)
218
+ if padding >= 0
219
+ string.gsub(/^/, ' ' * padding)
220
+ else
221
+ string.gsub(/^ {0,#{-padding}}/, '')
222
+ end
223
+ end
224
+
211
225
  private
212
226
 
213
227
  FORMATS = Hash.new { |hash, format| hash[format] = method(format).to_proc }
@@ -216,6 +230,7 @@ module Cucumber
216
230
  key = keys.join('_').to_sym
217
231
  fmt = FORMATS[key]
218
232
  raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
233
+
219
234
  fmt
220
235
  end
221
236
 
@@ -238,6 +253,7 @@ module Cucumber
238
253
 
239
254
  class SnippetData
240
255
  attr_reader :actual_keyword, :step
256
+
241
257
  def initialize(actual_keyword, step)
242
258
  @actual_keyword = actual_keyword
243
259
  @step = step
@@ -23,6 +23,7 @@ module Cucumber
23
23
 
24
24
  def to_s
25
25
  return if @issues.empty?
26
+
26
27
  result = Core::Test::Result::TYPES.map { |type| scenario_listing(type, @issues[type]) }
27
28
  result.flatten.join("\n")
28
29
  end
@@ -35,6 +36,7 @@ module Cucumber
35
36
 
36
37
  def scenario_listing(type, test_cases)
37
38
  return [] if test_cases.empty?
39
+
38
40
  [format_string("#{type_heading(type)} Scenarios:", type)] + test_cases.map do |test_case|
39
41
  scenario_source = @ast_lookup.scenario_source(test_case)
40
42
  keyword = scenario_source.type == :Scenario ? scenario_source.scenario.keyword : scenario_source.scenario_outline.keyword
@@ -54,7 +56,10 @@ module Cucumber
54
56
 
55
57
  def profiles_string
56
58
  return if @config.custom_profiles.empty?
57
- @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ') + ' '
59
+
60
+ profiles = @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ')
61
+
62
+ "#{profiles} "
58
63
  end
59
64
  end
60
65
  end