cucumber 3.1.2 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1880 -1146
  3. data/CONTRIBUTING.md +220 -61
  4. data/README.md +143 -22
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber_mixin.rb +49 -53
  7. data/lib/autotest/discover.rb +3 -2
  8. data/lib/cucumber/cli/configuration.rb +32 -7
  9. data/lib/cucumber/cli/main.rb +16 -15
  10. data/lib/cucumber/cli/options.rb +111 -79
  11. data/lib/cucumber/cli/profile_loader.rb +45 -26
  12. data/lib/cucumber/cli/rerun_file.rb +1 -1
  13. data/lib/cucumber/configuration.rb +47 -31
  14. data/lib/cucumber/constantize.rb +3 -6
  15. data/lib/cucumber/deprecate.rb +32 -7
  16. data/lib/cucumber/errors.rb +5 -7
  17. data/lib/cucumber/events/envelope.rb +9 -0
  18. data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
  19. data/lib/cucumber/events/hook_test_step_created.rb +12 -0
  20. data/lib/cucumber/events/step_activated.rb +0 -5
  21. data/lib/cucumber/events/step_definition_registered.rb +0 -5
  22. data/lib/cucumber/events/test_case_created.rb +12 -0
  23. data/lib/cucumber/events/test_case_ready.rb +12 -0
  24. data/lib/cucumber/events/test_run_finished.rb +2 -1
  25. data/lib/cucumber/events/test_step_created.rb +12 -0
  26. data/lib/cucumber/events/undefined_parameter_type.rb +9 -0
  27. data/lib/cucumber/events.rb +15 -8
  28. data/lib/cucumber/file_specs.rb +8 -7
  29. data/lib/cucumber/filters/activate_steps.rb +6 -3
  30. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  31. data/lib/cucumber/filters/prepare_world.rb +5 -9
  32. data/lib/cucumber/filters/quit.rb +1 -3
  33. data/lib/cucumber/filters/tag_limits/verifier.rb +3 -7
  34. data/lib/cucumber/filters/tag_limits.rb +1 -3
  35. data/lib/cucumber/filters.rb +1 -0
  36. data/lib/cucumber/formatter/ansicolor.rb +74 -86
  37. data/lib/cucumber/formatter/ast_lookup.rb +163 -0
  38. data/lib/cucumber/formatter/backtrace_filter.rb +10 -7
  39. data/lib/cucumber/formatter/console.rb +76 -68
  40. data/lib/cucumber/formatter/console_counts.rb +4 -9
  41. data/lib/cucumber/formatter/console_issues.rb +12 -4
  42. data/lib/cucumber/formatter/duration.rb +1 -1
  43. data/lib/cucumber/formatter/duration_extractor.rb +4 -1
  44. data/lib/cucumber/formatter/errors.rb +7 -0
  45. data/lib/cucumber/formatter/fanout.rb +3 -1
  46. data/lib/cucumber/formatter/html.rb +11 -598
  47. data/lib/cucumber/formatter/http_io.rb +152 -0
  48. data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -2
  49. data/lib/cucumber/formatter/interceptor.rb +11 -30
  50. data/lib/cucumber/formatter/io.rb +57 -13
  51. data/lib/cucumber/formatter/json.rb +119 -124
  52. data/lib/cucumber/formatter/junit.rb +75 -55
  53. data/lib/cucumber/formatter/message.rb +23 -0
  54. data/lib/cucumber/formatter/message_builder.rb +256 -0
  55. data/lib/cucumber/formatter/pretty.rb +370 -153
  56. data/lib/cucumber/formatter/progress.rb +31 -32
  57. data/lib/cucumber/formatter/publish_banner_printer.rb +77 -0
  58. data/lib/cucumber/formatter/query/hook_by_test_step.rb +32 -0
  59. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  60. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  61. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  62. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +42 -0
  63. data/lib/cucumber/formatter/rerun.rb +24 -4
  64. data/lib/cucumber/formatter/stepdefs.rb +1 -2
  65. data/lib/cucumber/formatter/steps.rb +8 -6
  66. data/lib/cucumber/formatter/summary.rb +17 -8
  67. data/lib/cucumber/formatter/unicode.rb +18 -20
  68. data/lib/cucumber/formatter/url_reporter.rb +17 -0
  69. data/lib/cucumber/formatter/usage.rb +18 -15
  70. data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
  71. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +14 -18
  72. data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
  73. data/lib/cucumber/gherkin/steps_parser.rb +17 -8
  74. data/lib/cucumber/glue/dsl.rb +29 -15
  75. data/lib/cucumber/glue/hook.rb +37 -11
  76. data/lib/cucumber/glue/invoke_in_world.rb +17 -22
  77. data/lib/cucumber/glue/proto_world.rb +47 -53
  78. data/lib/cucumber/glue/registry_and_more.rb +62 -17
  79. data/lib/cucumber/glue/registry_wrapper.rb +31 -0
  80. data/lib/cucumber/glue/snippet.rb +23 -22
  81. data/lib/cucumber/glue/step_definition.rb +48 -23
  82. data/lib/cucumber/glue/world_factory.rb +1 -1
  83. data/lib/cucumber/hooks.rb +12 -11
  84. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +4 -3
  85. data/lib/cucumber/multiline_argument/data_table.rb +143 -123
  86. data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
  87. data/lib/cucumber/multiline_argument.rb +4 -6
  88. data/lib/cucumber/platform.rb +5 -5
  89. data/lib/cucumber/rake/task.rb +34 -25
  90. data/lib/cucumber/rspec/disable_option_parser.rb +15 -11
  91. data/lib/cucumber/rspec/doubles.rb +3 -5
  92. data/lib/cucumber/running_test_case.rb +3 -53
  93. data/lib/cucumber/runtime/after_hooks.rb +8 -4
  94. data/lib/cucumber/runtime/before_hooks.rb +8 -4
  95. data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
  96. data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
  97. data/lib/cucumber/runtime/step_hooks.rb +6 -2
  98. data/lib/cucumber/runtime/support_code.rb +16 -15
  99. data/lib/cucumber/runtime/user_interface.rb +10 -19
  100. data/lib/cucumber/runtime.rb +78 -76
  101. data/lib/cucumber/step_definition_light.rb +4 -3
  102. data/lib/cucumber/step_definitions.rb +2 -2
  103. data/lib/cucumber/step_match.rb +17 -20
  104. data/lib/cucumber/step_match_search.rb +5 -3
  105. data/lib/cucumber/term/ansicolor.rb +72 -48
  106. data/lib/cucumber/term/banner.rb +57 -0
  107. data/lib/cucumber/version +1 -1
  108. data/lib/cucumber.rb +3 -2
  109. data/lib/simplecov_setup.rb +1 -1
  110. metadata +279 -81
  111. data/lib/cucumber/core_ext/string.rb +0 -11
  112. data/lib/cucumber/events/gherkin_source_parsed.rb~ +0 -14
  113. data/lib/cucumber/formatter/ast_lookup.rb~ +0 -9
  114. data/lib/cucumber/formatter/cucumber.css +0 -286
  115. data/lib/cucumber/formatter/cucumber.sass +0 -247
  116. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
  117. data/lib/cucumber/formatter/html_builder.rb +0 -121
  118. data/lib/cucumber/formatter/inline-js.js +0 -30
  119. data/lib/cucumber/formatter/jquery-min.js +0 -154
  120. data/lib/cucumber/formatter/json_pretty.rb +0 -11
  121. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  122. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  123. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  124. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  125. data/lib/cucumber/step_argument.rb +0 -25
@@ -8,9 +8,7 @@ module Cucumber
8
8
  end
9
9
 
10
10
  def test_case(test_case)
11
- unless Cucumber.wants_to_quit
12
- test_case.describe_to @receiver
13
- end
11
+ test_case.describe_to @receiver unless Cucumber.wants_to_quit
14
12
  self
15
13
  end
16
14
 
@@ -17,10 +17,8 @@ module Cucumber
17
17
 
18
18
  def collect_breaches(test_case_index)
19
19
  tag_limits.reduce([]) do |breaches, (tag_name, limit)|
20
- breaches.tap do |breaches|
21
- if test_case_index.count_by_tag_name(tag_name) > limit
22
- breaches << Breach.new(tag_name, limit, test_case_index.locations_of_tag_name(tag_name))
23
- end
20
+ breaches.tap do |breach|
21
+ breach << Breach.new(tag_name, limit, test_case_index.locations_of_tag_name(tag_name)) if test_case_index.count_by_tag_name(tag_name) > limit
24
22
  end
25
23
  end
26
24
  end
@@ -49,9 +47,7 @@ module Cucumber
49
47
  locations.count
50
48
  end
51
49
 
52
- attr_reader :tag_name
53
- attr_reader :limit
54
- attr_reader :locations
50
+ attr_reader :tag_name, :limit, :locations
55
51
  end
56
52
  end
57
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
@@ -11,3 +11,4 @@ require 'cucumber/filters/quit'
11
11
  require 'cucumber/filters/randomizer'
12
12
  require 'cucumber/filters/retry'
13
13
  require 'cucumber/filters/tag_limits'
14
+ require 'cucumber/filters/broadcast_test_case_ready_event'
@@ -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,48 +56,45 @@ 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
- if k.to_s =~ /(.*)_param/
59
- h[$1] + ',bold'
60
- end
61
- end.merge({
62
- 'undefined' => 'yellow',
63
- 'pending' => 'yellow',
64
- 'flaky' => 'yellow',
65
- 'failed' => 'red',
66
- 'passed' => 'green',
67
- 'outline' => 'cyan',
68
- 'skipped' => 'cyan',
69
- 'comment' => 'grey',
70
- 'tag' => 'cyan'
71
- })
68
+ next unless k.to_s =~ /(.*)_param/
72
69
 
73
- if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
74
- ENV['CUCUMBER_COLORS'].split(':').each do |pair|
70
+ "#{h[Regexp.last_match(1)]},bold"
71
+ end.merge(
72
+ 'undefined' => 'yellow',
73
+ 'pending' => 'yellow',
74
+ 'flaky' => 'yellow',
75
+ 'failed' => 'red',
76
+ 'passed' => 'green',
77
+ 'outline' => 'cyan',
78
+ 'skipped' => 'cyan',
79
+ 'comment' => 'grey',
80
+ 'tag' => 'cyan'
81
+ )
82
+ # :startdoc:
83
+
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|
75
91
  a = pair.split('=')
76
92
  ALIASES[a[0]] = a[1]
77
93
  end
78
94
  end
95
+ apply_custom_colors(ENV['CUCUMBER_COLORS']) if ENV['CUCUMBER_COLORS']
79
96
 
80
- # Eval to define the color-named methods required by Term::ANSIColor.
97
+ # Define the color-named methods required by Term::ANSIColor.
81
98
  #
82
99
  # Examples:
83
100
  #
@@ -89,56 +106,18 @@ module Cucumber
89
106
  # red(bold(string, &proc)) + red
90
107
  # end
91
108
  ALIASES.each_key do |method_name|
92
- unless method_name =~ /.*_param/
93
- code = <<-EOF
94
- def #{method_name}(string=nil, &proc)
95
- #{ALIASES[method_name].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method_name].split(",").length}
96
- end
97
- # This resets the colour to the non-param colour
98
- def #{method_name}_param(string=nil, &proc)
99
- #{ALIASES[method_name + '_param'].split(",").join("(") + "(string, &proc" + ")" * ALIASES[method_name + '_param'].split(",").length} + #{ALIASES[method_name].split(",").join(' + ')}
100
- end
101
- EOF
102
- eval(code)
103
- end
104
- end
109
+ next if method_name.end_with?('_param')
105
110
 
106
- def self.define_grey #:nodoc:
107
- begin
108
- gem 'genki-ruby-terminfo'
109
- require 'terminfo'
110
- case TermInfo.default_object.tigetnum('colors')
111
- when 0
112
- raise "Your terminal doesn't support colours."
113
- when 1
114
- ::Cucumber::Term::ANSIColor.coloring = false
115
- alias grey white
116
- when 2..8
117
- alias grey white
118
- else
119
- define_real_grey
120
- end
121
- rescue Exception => e
122
- if e.class.name == 'TermInfo::TermInfoError'
123
- STDERR.puts '*** WARNING ***'
124
- STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
125
- STDERR.puts 'Try setting it to TERM=xterm-256color to get grey colour in output.'
126
- STDERR.puts "\n"
127
- alias grey white
128
- else
129
- define_real_grey
130
- end
111
+ define_method(method_name) do |text = nil, &proc|
112
+ apply_styles(ALIASES[method_name], text, &proc)
131
113
  end
132
- end
133
114
 
134
- def self.define_real_grey #:nodoc:
135
- define_method :grey do |string|
136
- ::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])
137
117
  end
138
118
  end
139
119
 
140
- define_grey
141
-
120
+ # :stopdoc:
142
121
  def cukes(n)
143
122
  ('(::) ' * n).strip
144
123
  end
@@ -154,6 +133,15 @@ module Cucumber
154
133
  def yellow_cukes(n)
155
134
  blink(yellow(cukes(n)))
156
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
157
145
  end
158
146
  end
159
147
  end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ class AstLookup
6
+ def initialize(config)
7
+ @gherkin_documents = {}
8
+ @test_case_lookups = {}
9
+ @test_step_lookups = {}
10
+ @step_keyword_lookups = {}
11
+ config.on_event :gherkin_source_parsed, &method(:on_gherkin_source_parsed)
12
+ end
13
+
14
+ def on_gherkin_source_parsed(event)
15
+ @gherkin_documents[event.gherkin_document.uri] = event.gherkin_document
16
+ end
17
+
18
+ def gherkin_document(uri)
19
+ @gherkin_documents[uri]
20
+ end
21
+
22
+ def scenario_source(test_case)
23
+ uri = test_case.location.file
24
+ @test_case_lookups[uri] ||= TestCaseLookupBuilder.new(gherkin_document(uri)).lookup_hash
25
+ @test_case_lookups[uri][test_case.location.lines.max]
26
+ end
27
+
28
+ def step_source(test_step)
29
+ uri = test_step.location.file
30
+ @test_step_lookups[uri] ||= TestStepLookupBuilder.new(gherkin_document(uri)).lookup_hash
31
+ @test_step_lookups[uri][test_step.location.lines.min]
32
+ end
33
+
34
+ def snippet_step_keyword(test_step)
35
+ uri = test_step.location.file
36
+ document = gherkin_document(uri)
37
+ dialect = ::Gherkin::Dialect.for(document.feature.language)
38
+ given_when_then_keywords = [dialect.given_keywords, dialect.when_keywords, dialect.then_keywords].flatten.uniq.reject { |kw| kw == '* ' }
39
+ keyword_lookup = step_keyword_lookup(uri)
40
+ keyword = nil
41
+ node = keyword_lookup[test_step.location.lines.min]
42
+ while keyword.nil?
43
+ if given_when_then_keywords.include?(node.keyword)
44
+ keyword = node.keyword
45
+ break
46
+ end
47
+ break if node.previous_node.nil?
48
+
49
+ node = node.previous_node
50
+ end
51
+ keyword = dialect.given_keywords.reject { |kw| kw == '* ' }[0] if keyword.nil?
52
+ Cucumber::Gherkin::I18n.code_keyword_for(keyword)
53
+ end
54
+
55
+ ScenarioSource = Struct.new(:type, :scenario)
56
+
57
+ ScenarioOutlineSource = Struct.new(:type, :scenario_outline, :examples, :row)
58
+
59
+ StepSource = Struct.new(:type, :step)
60
+
61
+ private
62
+
63
+ def step_keyword_lookup(uri)
64
+ @step_keyword_lookups[uri] ||= KeywordLookupBuilder.new(gherkin_document(uri)).lookup_hash
65
+ end
66
+
67
+ class TestCaseLookupBuilder
68
+ attr_reader :lookup_hash
69
+
70
+ def initialize(gherkin_document)
71
+ @lookup_hash = {}
72
+ process_scenario_container(gherkin_document.feature)
73
+ end
74
+
75
+ private
76
+
77
+ def process_scenario_container(container)
78
+ container.children.each do |child|
79
+ if child.respond_to?(:rule) && child.rule
80
+ process_scenario_container(child.rule)
81
+ elsif child.respond_to?(:scenario) && child.scenario
82
+ process_scenario(child)
83
+ end
84
+ end
85
+ end
86
+
87
+ def process_scenario(child)
88
+ if child.scenario.examples.empty?
89
+ @lookup_hash[child.scenario.location.line] = ScenarioSource.new(:Scenario, child.scenario)
90
+ else
91
+ child.scenario.examples.each do |examples|
92
+ examples.table_body.each do |row|
93
+ @lookup_hash[row.location.line] = ScenarioOutlineSource.new(:ScenarioOutline, child.scenario, examples, row)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ class TestStepLookupBuilder
101
+ attr_reader :lookup_hash
102
+
103
+ def initialize(gherkin_document)
104
+ @lookup_hash = {}
105
+ process_scenario_container(gherkin_document.feature)
106
+ end
107
+
108
+ private
109
+
110
+ def process_scenario_container(container)
111
+ container.children.each do |child|
112
+ if child.respond_to?(:rule) && child.rule
113
+ process_scenario_container(child.rule)
114
+ elsif child.respond_to?(:scenario) && child.scenario
115
+ child.scenario.steps.each do |step|
116
+ @lookup_hash[step.location.line] = StepSource.new(:Step, step)
117
+ end
118
+ elsif !child.background.nil?
119
+ child.background.steps.each do |step|
120
+ @lookup_hash[step.location.line] = StepSource.new(:Step, step)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ KeywordSearchNode = Struct.new(:keyword, :previous_node)
128
+
129
+ class KeywordLookupBuilder
130
+ attr_reader :lookup_hash
131
+
132
+ def initialize(gherkin_document)
133
+ @lookup_hash = {}
134
+ process_scenario_container(gherkin_document.feature, nil)
135
+ end
136
+
137
+ private
138
+
139
+ def process_scenario_container(container, original_previous_node)
140
+ container.children.each do |child|
141
+ previous_node = original_previous_node
142
+ if child.respond_to?(:rule) && child.rule
143
+ process_scenario_container(child.rule, original_previous_node)
144
+ elsif child.respond_to?(:scenario) && child.scenario
145
+ child.scenario.steps.each do |step|
146
+ node = KeywordSearchNode.new(step.keyword, previous_node)
147
+ @lookup_hash[step.location.line] = node
148
+ previous_node = node
149
+ end
150
+ elsif child.respond_to?(:background) && child.background
151
+ child.background.steps.each do |step|
152
+ node = KeywordSearchNode.new(step.keyword, previous_node)
153
+ @lookup_hash[step.location.line] = node
154
+ previous_node = node
155
+ original_previous_node = previous_node
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -4,22 +4,25 @@ require 'cucumber/platform'
4
4
 
5
5
  module Cucumber
6
6
  module Formatter
7
- @backtrace_filters = %w(
7
+ @backtrace_filters = %w[
8
8
  /vendor/rails
9
9
  lib/cucumber
10
10
  bin/cucumber:
11
11
  lib/rspec
12
12
  gems/
13
+ site_ruby/
13
14
  minitest
14
15
  test/unit
15
16
  .gem/ruby
16
- lib/ruby/
17
17
  bin/bundle
18
- )
18
+ rdebug-ide
19
+ ]
19
20
 
20
- if ::Cucumber::JRUBY
21
- @backtrace_filters << 'org/jruby/'
22
- end
21
+ @backtrace_filters << RbConfig::CONFIG['rubyarchdir'] if RbConfig::CONFIG['rubyarchdir']
22
+ @backtrace_filters << RbConfig::CONFIG['rubylibdir'] if RbConfig::CONFIG['rubylibdir']
23
+
24
+ @backtrace_filters << 'org/jruby/' if ::Cucumber::JRUBY
25
+ @backtrace_filters << '<internal:' if RUBY_ENGINE == 'truffleruby'
23
26
 
24
27
  BACKTRACE_FILTER_PATTERNS = Regexp.new(@backtrace_filters.join('|'))
25
28
 
@@ -41,7 +44,7 @@ module Cucumber
41
44
  if ::ENV['CUCUMBER_TRUNCATE_OUTPUT']
42
45
  # Strip off file locations
43
46
  filtered = filtered.map do |line|
44
- line =~ /(.*):in `/ ? $1 : line
47
+ line =~ /(.*):in `/ ? Regexp.last_match(1) : line
45
48
  end
46
49
  end
47
50