cucumber 2.0.0.beta.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/History.md +131 -32
  4. data/Rakefile +0 -2
  5. data/cucumber.gemspec +4 -3
  6. data/examples/i18n/ht/Rakefile +6 -0
  7. data/examples/i18n/ht/features/adisyon.feature +17 -0
  8. data/examples/i18n/ht/features/divizyon.feature +10 -0
  9. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
  10. data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
  11. data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
  12. data/features/docs/cli/dry_run.feature +48 -0
  13. data/features/docs/cli/exclude_files.feature +1 -2
  14. data/features/docs/cli/run_specific_scenarios.feature +28 -66
  15. data/features/docs/cli/strict_mode.feature +24 -1
  16. data/features/docs/defining_steps/nested_steps.feature +49 -0
  17. data/features/docs/defining_steps/skip_scenario.feature +31 -2
  18. data/features/docs/defining_steps/snippets.feature +15 -0
  19. data/features/docs/exception_in_after_step_hook.feature +1 -1
  20. data/features/docs/exception_in_around_hook.feature +80 -0
  21. data/features/docs/extending_cucumber/custom_filter.feature +29 -0
  22. data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
  23. data/features/docs/formatters/debug_formatter.feature +24 -17
  24. data/features/docs/formatters/json_formatter.feature +65 -1
  25. data/features/docs/formatters/junit_formatter.feature +40 -0
  26. data/features/docs/formatters/pretty_formatter.feature +42 -0
  27. data/features/docs/formatters/rerun_formatter.feature +3 -2
  28. data/features/docs/getting_started.feature +1 -1
  29. data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
  30. data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
  31. data/features/docs/wire_protocol/invoke_message.feature +216 -0
  32. data/features/docs/wire_protocol/readme.md +26 -0
  33. data/features/docs/wire_protocol/snippets_message.feature +51 -0
  34. data/features/docs/wire_protocol/step_matches_message.feature +81 -0
  35. data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
  36. data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
  37. data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
  38. data/features/docs/work_in_progress.feature +1 -1
  39. data/features/docs/writing_support_code/after_hooks.feature +24 -0
  40. data/features/docs/writing_support_code/around_hooks.feature +31 -0
  41. data/features/docs/writing_support_code/before_hook.feature +7 -3
  42. data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
  43. data/features/lib/step_definitions/wire_steps.rb +18 -1
  44. data/features/lib/support/fake_wire_server.rb +10 -7
  45. data/lib/cucumber/cli/configuration.rb +6 -11
  46. data/lib/cucumber/cli/main.rb +2 -2
  47. data/lib/cucumber/cli/options.rb +8 -1
  48. data/lib/cucumber/cli/profile_loader.rb +1 -1
  49. data/lib/cucumber/core_ext/instance_exec.rb +1 -1
  50. data/lib/cucumber/encoding.rb +5 -0
  51. data/lib/cucumber/errors.rb +8 -0
  52. data/lib/cucumber/file_specs.rb +3 -1
  53. data/lib/cucumber/filters/activate_steps.rb +33 -0
  54. data/lib/cucumber/filters/apply_after_hooks.rb +9 -0
  55. data/lib/cucumber/filters/apply_after_step_hooks.rb +12 -0
  56. data/lib/cucumber/filters/apply_around_hooks.rb +12 -0
  57. data/lib/cucumber/filters/apply_before_hooks.rb +9 -0
  58. data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
  59. data/lib/cucumber/filters/prepare_world.rb +45 -0
  60. data/lib/cucumber/filters/quit.rb +28 -0
  61. data/lib/cucumber/filters/randomizer.rb +40 -0
  62. data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
  63. data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
  64. data/lib/cucumber/filters/tag_limits.rb +45 -0
  65. data/lib/cucumber/filters.rb +9 -0
  66. data/lib/cucumber/formatter/ansicolor.rb +0 -8
  67. data/lib/cucumber/formatter/console.rb +37 -20
  68. data/lib/cucumber/formatter/debug.rb +1 -8
  69. data/lib/cucumber/formatter/fanout.rb +27 -0
  70. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +10 -9
  71. data/lib/cucumber/formatter/html.rb +31 -6
  72. data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
  73. data/lib/cucumber/formatter/junit.rb +97 -2
  74. data/lib/cucumber/formatter/legacy_api/adapter.rb +1060 -0
  75. data/lib/cucumber/formatter/legacy_api/ast.rb +376 -0
  76. data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
  77. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
  78. data/lib/cucumber/formatter/pretty.rb +14 -0
  79. data/lib/cucumber/formatter/progress.rb +10 -0
  80. data/lib/cucumber/formatter/rerun.rb +14 -88
  81. data/lib/cucumber/hooks.rb +97 -0
  82. data/lib/cucumber/language_support/language_methods.rb +0 -54
  83. data/lib/cucumber/multiline_argument/data_table.rb +41 -29
  84. data/lib/cucumber/platform.rb +3 -3
  85. data/lib/cucumber/project_initializer.rb +43 -0
  86. data/lib/cucumber/rb_support/rb_hook.rb +2 -2
  87. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
  88. data/lib/cucumber/rb_support/rb_transform.rb +3 -1
  89. data/lib/cucumber/rb_support/rb_world.rb +2 -2
  90. data/lib/cucumber/rb_support/snippet.rb +1 -1
  91. data/lib/cucumber/rspec/doubles.rb +1 -1
  92. data/lib/cucumber/running_test_case.rb +115 -0
  93. data/lib/cucumber/runtime/after_hooks.rb +24 -0
  94. data/lib/cucumber/runtime/before_hooks.rb +23 -0
  95. data/lib/cucumber/runtime/for_programming_languages.rb +4 -8
  96. data/lib/cucumber/runtime/step_hooks.rb +22 -0
  97. data/lib/cucumber/runtime/support_code.rb +70 -5
  98. data/lib/cucumber/runtime.rb +56 -112
  99. data/lib/cucumber/step_match.rb +26 -2
  100. data/lib/cucumber.rb +7 -3
  101. data/spec/cucumber/cli/configuration_spec.rb +16 -1
  102. data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
  103. data/spec/cucumber/core_ext/instance_exec_spec.rb +4 -0
  104. data/spec/cucumber/file_specs_spec.rb +21 -2
  105. data/spec/cucumber/filters/activate_steps_spec.rb +57 -0
  106. data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
  107. data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
  108. data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
  109. data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
  110. data/spec/cucumber/formatter/debug_spec.rb +25 -530
  111. data/spec/cucumber/formatter/html_spec.rb +140 -0
  112. data/spec/cucumber/formatter/junit_spec.rb +212 -156
  113. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +2090 -0
  114. data/spec/cucumber/formatter/pretty_spec.rb +248 -2
  115. data/spec/cucumber/formatter/rerun_spec.rb +107 -0
  116. data/spec/cucumber/formatter/spec_helper.rb +17 -8
  117. data/spec/cucumber/hooks_spec.rb +30 -0
  118. data/spec/cucumber/multiline_argument/data_table_spec.rb +53 -47
  119. data/spec/cucumber/project_initializer_spec.rb +87 -0
  120. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  121. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +32 -7
  122. data/spec/cucumber/rb_support/rb_transform_spec.rb +20 -0
  123. data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
  124. data/spec/cucumber/running_test_case_spec.rb +83 -0
  125. data/spec/cucumber/runtime_spec.rb +1 -5
  126. data/spec/spec_helper.rb +3 -4
  127. metadata +149 -107
  128. data/bin/cuke +0 -60
  129. data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
  130. data/features/docs/output_from_hooks.feature +0 -128
  131. data/features/docs/report_called_undefined_steps.feature +0 -57
  132. data/features/docs/wire_protocol.feature +0 -337
  133. data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  134. data/gem_tasks/yard/default/layout/html/footer.erb +0 -5
  135. data/gem_tasks/yard/default/layout/html/index.erb +0 -1
  136. data/gem_tasks/yard/default/layout/html/layout.erb +0 -25
  137. data/gem_tasks/yard/default/layout/html/logo.erb +0 -1
  138. data/gem_tasks/yard/default/layout/html/setup.rb +0 -4
  139. data/gem_tasks/yard.rake +0 -43
  140. data/lib/cucumber/mappings.rb +0 -238
  141. data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
  142. data/lib/cucumber/runtime/results.rb +0 -64
  143. data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
  144. data/lib/cucumber/runtime/tag_limits.rb +0 -15
  145. data/spec/cucumber/mappings_spec.rb +0 -180
  146. data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
  147. data/spec/cucumber/runtime/results_spec.rb +0 -88
@@ -66,10 +66,6 @@ module Cucumber
66
66
  @options[:snippet_type] || :regexp
67
67
  end
68
68
 
69
- def build_tree_walker(runtime)
70
- Ast::TreeWalker.new(runtime, formatters(runtime), self)
71
- end
72
-
73
69
  def formatter_class(format)
74
70
  if(builtin = Options::BUILTIN_FORMATS[format])
75
71
  constantize(builtin[0])
@@ -111,7 +107,7 @@ module Cucumber
111
107
  Dir["#{path}/**/*.feature"].sort
112
108
  elsif path[0..0] == '@' and # @listfile.txt
113
109
  File.file?(path[1..-1]) # listfile.txt is a file
114
- IO.read(path[1..-1]).split
110
+ IO.read(path[1..-1]).split(/(.*?\.feature.*?) /).collect(&:strip).reject(&:empty?)
115
111
  else
116
112
  path
117
113
  end
@@ -151,7 +147,6 @@ module Cucumber
151
147
  @options[:name_regexps]
152
148
  end
153
149
 
154
- # todo: remove as unused
155
150
  def filters
156
151
  @options.filters
157
152
  end
@@ -169,13 +164,13 @@ module Cucumber
169
164
  @options[:paths]
170
165
  end
171
166
 
172
- def formatters(runtime)
167
+ def formatter_factories
173
168
  @options[:formats].map do |format_and_out|
174
169
  format = format_and_out[0]
175
170
  path_or_io = format_and_out[1]
176
171
  begin
177
- formatter_class = formatter_class(format)
178
- formatter_class.new(runtime, path_or_io, @options)
172
+ factory = formatter_class(format)
173
+ yield factory, path_or_io, @options
179
174
  rescue Exception => e
180
175
  e.message << "\nError creating formatter: #{format}"
181
176
  raise e
@@ -183,7 +178,8 @@ module Cucumber
183
178
  end
184
179
  end
185
180
 
186
- private
181
+ private
182
+
187
183
  def with_default_features_path(paths)
188
184
  return ['features'] if paths.empty?
189
185
  paths
@@ -195,7 +191,6 @@ module Cucumber
195
191
  end
196
192
  end
197
193
 
198
-
199
194
  def set_environment_variables
200
195
  @options[:env_vars].each do |var, value|
201
196
  ENV[var] = value
@@ -36,14 +36,14 @@ module Cucumber
36
36
  end
37
37
 
38
38
  runtime.run!
39
- failure = runtime.results.failure? || Cucumber.wants_to_quit
39
+ failure = runtime.failure? || Cucumber.wants_to_quit
40
40
  @kernel.exit(failure ? 1 : 0)
41
41
  rescue FileNotFoundException => e
42
42
  @err.puts(e.message)
43
43
  @err.puts("Couldn't open #{e.path}")
44
44
  @kernel.exit(1)
45
45
  rescue FeatureFolderNotFoundException => e
46
- @err.puts(e.message + ". Please create a #{e.path} directory to get started.")
46
+ @err.puts(e.message + ". You can use `cucumber --init` to get started.")
47
47
  @kernel.exit(1)
48
48
  rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
49
49
  @err.puts(e.message)
@@ -1,6 +1,7 @@
1
1
  require 'cucumber/cli/profile_loader'
2
2
  require 'cucumber/formatter/ansicolor'
3
3
  require 'cucumber/rb_support/rb_language'
4
+ require 'cucumber/project_initializer'
4
5
 
5
6
  module Cucumber
6
7
  module Cli
@@ -126,6 +127,12 @@ module Cucumber
126
127
  *FORMAT_HELP) do |v|
127
128
  @options[:formats] << [v, @out_stream]
128
129
  end
130
+ opts.on('--init',
131
+ 'Initializes folder structure and generates conventional files for',
132
+ 'a Cucumber project.') do |v|
133
+ ProjectInitializer.new.run
134
+ Kernel.exit(0)
135
+ end
129
136
  opts.on("-o", "--out [FILE|DIR]",
130
137
  "Write output to a file/directory instead of STDOUT. This option",
131
138
  "applies to the previously specified --format, or the",
@@ -266,7 +273,7 @@ TEXT
266
273
  end
267
274
 
268
275
  def filters
269
- @options.values_at(:name_regexps, :tag_expressions).select{|v| !v.empty?}.first || []
276
+ @options[:filters] ||= []
270
277
  end
271
278
 
272
279
  protected
@@ -60,7 +60,7 @@ Defined profiles in cucumber.yml:
60
60
  require 'erb'
61
61
  require 'yaml'
62
62
  begin
63
- @cucumber_erb = ERB.new(IO.read(cucumber_file)).result(binding)
63
+ @cucumber_erb = ERB.new(IO.read(cucumber_file), nil, '%').result(binding)
64
64
  rescue Exception => e
65
65
  raise(YmlLoadError,"cucumber.yml was found, but could not be parsed with ERB. Please refer to cucumber's documentation on correct profile usage.\n#{$!.inspect}")
66
66
  end
@@ -47,7 +47,7 @@ class Object #:nodoc:
47
47
  end
48
48
  end
49
49
 
50
- INSTANCE_EXEC_OFFSET = (Cucumber::RUBY_2_1 || Cucumber::RUBY_2_0 || Cucumber::RUBY_1_9 || Cucumber::JRUBY) ? -3 : -4
50
+ INSTANCE_EXEC_OFFSET = -3
51
51
 
52
52
  def replace_instance_exec_invocation_line!(backtrace, instance_exec_invocation_line, pseudo_method)
53
53
  return if Cucumber.use_full_backtrace
@@ -0,0 +1,5 @@
1
+ # See https://github.com/cucumber/cucumber/issues/693
2
+ if defined? Encoding
3
+ Encoding.default_external = 'utf-8'
4
+ Encoding.default_internal = 'utf-8'
5
+ end
@@ -20,6 +20,14 @@ module Cucumber
20
20
  end
21
21
  end
22
22
 
23
+ # Raised when there is no matching StepDefinition for a step called
24
+ # from within another step definition.
25
+ class UndefinedDynamicStep < StandardError
26
+ def initialize(step_name)
27
+ super %(Undefined dynamic step: "#{step_name}")
28
+ end
29
+ end
30
+
23
31
  # Raised when a StepDefinition's block invokes World#pending
24
32
  class Pending < Core::Test::Result::Pending
25
33
  end
@@ -1,4 +1,6 @@
1
+ require 'cucumber'
1
2
  require 'cucumber/core/ast/location'
3
+
2
4
  module Cucumber
3
5
  class FileSpecs
4
6
  FILE_COLON_LINE_PATTERN = /^([\w\W]*?)(?::([\d:]+))?$/ #:nodoc:
@@ -14,7 +16,7 @@ module Cucumber
14
16
  end
15
17
 
16
18
  def files
17
- @file_specs.map(&:file)
19
+ @file_specs.map(&:file).uniq
18
20
  end
19
21
 
20
22
  class FileSpec
@@ -0,0 +1,33 @@
1
+ require 'cucumber/core/filter'
2
+
3
+ module Cucumber
4
+ module Filters
5
+ class ActivateSteps < Core::Filter.new(:step_definitions)
6
+
7
+ def test_case(test_case)
8
+ CaseFilter.new(test_case, step_definitions).test_case.describe_to receiver
9
+ end
10
+
11
+ class CaseFilter
12
+ def initialize(test_case, step_definitions)
13
+ @original_test_case = test_case
14
+ @step_definitions = step_definitions
15
+ end
16
+
17
+ def test_case
18
+ @original_test_case.with_steps(new_test_steps)
19
+ end
20
+
21
+ private
22
+
23
+ def new_test_steps
24
+ @original_test_case.test_steps.map(&self.method(:attempt_to_activate))
25
+ end
26
+
27
+ def attempt_to_activate(test_step)
28
+ @step_definitions.find_match(test_step).activate(test_step)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module Cucumber
2
+ module Filters
3
+ class ApplyAfterHooks < Core::Filter.new(:hooks)
4
+ def test_case(test_case)
5
+ hooks.apply_after_hooks(test_case).describe_to(receiver)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'cucumber/core/filter'
2
+
3
+ module Cucumber
4
+ module Filters
5
+ class ApplyAfterStepHooks < Core::Filter.new(:hooks)
6
+ def test_case(test_case)
7
+ test_steps = hooks.find_after_step_hooks(test_case).apply(test_case.test_steps)
8
+ test_case.with_steps(test_steps).describe_to(receiver)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'cucumber/core/filter'
2
+
3
+ module Cucumber
4
+ module Filters
5
+ class ApplyAroundHooks < Core::Filter.new(:hooks)
6
+ def test_case(test_case)
7
+ around_hooks = hooks.find_around_hooks(test_case)
8
+ test_case.with_around_hooks(around_hooks).describe_to(receiver)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Cucumber
2
+ module Filters
3
+ class ApplyBeforeHooks < Core::Filter.new(:hooks)
4
+ def test_case(test_case)
5
+ hooks.apply_before_hooks(test_case).describe_to(receiver)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,6 @@
1
1
  module Cucumber
2
- class Runtime
2
+ module Filters
3
+
3
4
  class GatedReceiver
4
5
  def initialize(receiver)
5
6
  @receiver = receiver
@@ -8,6 +9,7 @@ module Cucumber
8
9
 
9
10
  def test_case(test_case)
10
11
  @test_cases << test_case
12
+ self
11
13
  end
12
14
 
13
15
  def done
@@ -15,7 +17,9 @@ module Cucumber
15
17
  test_case.describe_to(@receiver)
16
18
  end
17
19
  @receiver.done
20
+ self
18
21
  end
19
22
  end
23
+
20
24
  end
21
25
  end
@@ -0,0 +1,45 @@
1
+ require 'cucumber/core/filter'
2
+ require 'cucumber/running_test_case'
3
+ require 'cucumber/hooks'
4
+
5
+ module Cucumber
6
+ module Filters
7
+
8
+ class PrepareWorld < Core::Filter.new(:runtime)
9
+
10
+ def test_case(test_case)
11
+ CaseFilter.new(runtime, test_case).test_case.describe_to receiver
12
+ end
13
+
14
+ class CaseFilter
15
+ def initialize(runtime, original_test_case)
16
+ @runtime, @original_test_case = runtime, original_test_case
17
+ end
18
+
19
+ def test_case
20
+ init_scenario = Cucumber::Hooks.around_hook(@original_test_case.source) do |continue|
21
+ @runtime.begin_scenario(scenario)
22
+ continue.call
23
+ @runtime.end_scenario(scenario)
24
+ end
25
+ around_hooks = [init_scenario] + @original_test_case.around_hooks
26
+
27
+ default_hook = Cucumber::Hooks.before_hook(@original_test_case.source) do
28
+ #no op - legacy format adapter expects a before hooks
29
+ end
30
+ steps = [default_hook] + @original_test_case.test_steps
31
+
32
+ @original_test_case.with_around_hooks(around_hooks).with_steps(steps)
33
+ end
34
+
35
+ private
36
+
37
+ def scenario
38
+ @scenario ||= RunningTestCase.new(test_case)
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ module Cucumber
2
+ module Filters
3
+
4
+ class Quit
5
+ def initialize(receiver=nil)
6
+ @receiver = receiver
7
+ end
8
+
9
+ def test_case(test_case)
10
+ unless Cucumber.wants_to_quit
11
+ test_case.describe_to @receiver
12
+ end
13
+ self
14
+ end
15
+
16
+ def done
17
+ @receiver.done
18
+ self
19
+ end
20
+
21
+ def with_receiver(receiver)
22
+ self.class.new(receiver)
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+
@@ -0,0 +1,40 @@
1
+ module Cucumber
2
+ module Filters
3
+
4
+ # Batches up all test cases, randomizes them, and then sends them on
5
+ class Randomizer
6
+ def initialize(seed, receiver=nil)
7
+ @receiver = receiver
8
+ @test_cases = []
9
+ @seed = seed
10
+ end
11
+
12
+ def test_case(test_case)
13
+ @test_cases << test_case
14
+ self
15
+ end
16
+
17
+ def done
18
+ shuffled_test_cases.each do |test_case|
19
+ test_case.describe_to(@receiver)
20
+ end
21
+ @receiver.done
22
+ self
23
+ end
24
+
25
+ def with_receiver(receiver)
26
+ self.class.new(@seed, receiver)
27
+ end
28
+
29
+ private
30
+
31
+ def shuffled_test_cases
32
+ @test_cases.shuffle(random: Random.new(seed))
33
+ end
34
+
35
+ attr_reader :seed
36
+ private :seed
37
+ end
38
+
39
+ end
40
+ end
@@ -1,6 +1,7 @@
1
1
  module Cucumber
2
- class Runtime
3
- module TagLimits
2
+ module Filters
3
+ class TagLimits
4
+
4
5
  class TestCaseIndex
5
6
  def initialize
6
7
  @index = Hash.new { |hash, key| hash[key] = [] }
@@ -24,6 +25,7 @@ module Cucumber
24
25
 
25
26
  attr_accessor :index
26
27
  end
28
+
27
29
  end
28
30
  end
29
31
  end
@@ -1,6 +1,7 @@
1
1
  module Cucumber
2
- class Runtime
3
- module TagLimits
2
+ module Filters
3
+ class TagLimits
4
+
4
5
  class Verifier
5
6
  def initialize(tag_limits)
6
7
  @tag_limits = tag_limits
@@ -51,6 +52,7 @@ module Cucumber
51
52
  attr_reader :limit
52
53
  attr_reader :locations
53
54
  end
55
+
54
56
  end
55
57
  end
56
58
  end
@@ -0,0 +1,45 @@
1
+ require "cucumber/filters/gated_receiver"
2
+ require "cucumber/filters/tag_limits/test_case_index"
3
+ require "cucumber/filters/tag_limits/verifier"
4
+
5
+ module Cucumber
6
+ module Filters
7
+ class TagLimitExceededError < StandardError
8
+ def initialize(*limit_breaches)
9
+ super(limit_breaches.map(&:to_s).join("\n"))
10
+ end
11
+ end
12
+
13
+ class TagLimits
14
+ def initialize(tag_limits, receiver=nil)
15
+ @tag_limits = tag_limits
16
+ @gated_receiver = GatedReceiver.new(receiver)
17
+ @test_case_index = TestCaseIndex.new
18
+ @verifier = Verifier.new(@tag_limits)
19
+ end
20
+
21
+ def test_case(test_case)
22
+ gated_receiver.test_case(test_case)
23
+ test_case_index.add(test_case)
24
+ self
25
+ end
26
+
27
+ def done
28
+ verifier.verify!(test_case_index)
29
+ gated_receiver.done
30
+ self
31
+ end
32
+
33
+ def with_receiver(receiver)
34
+ self.class.new(@tag_limits, receiver)
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :gated_receiver
40
+ attr_reader :test_case_index
41
+ attr_reader :verifier
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ require 'cucumber/filters/activate_steps'
2
+ require 'cucumber/filters/apply_after_step_hooks'
3
+ require 'cucumber/filters/apply_before_hooks'
4
+ require 'cucumber/filters/apply_after_hooks'
5
+ require 'cucumber/filters/apply_around_hooks'
6
+ require 'cucumber/filters/prepare_world'
7
+ require 'cucumber/filters/quit'
8
+ require 'cucumber/filters/randomizer'
9
+ require 'cucumber/filters/tag_limits'
@@ -1,14 +1,6 @@
1
1
  require 'cucumber/platform'
2
2
  require 'cucumber/term/ansicolor'
3
3
 
4
- if Cucumber::IRONRUBY
5
- begin
6
- require 'iron-term-ansicolor'
7
- rescue LoadError
8
- STDERR.puts %{*** WARNING: You must "igem install iron-term-ansicolor" to get coloured ouput in on IronRuby}
9
- end
10
- end
11
-
12
4
  if Cucumber::WINDOWS_MRI
13
5
  unless ENV['ANSICON']
14
6
  STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows}
@@ -97,8 +97,8 @@ module Cucumber
97
97
 
98
98
  def collect_failing_scenarios(runtime)
99
99
  # TODO: brittle - stop coupling to types
100
- scenario_class = Cucumber::Reports::Legacy::Ast::Scenario
101
- example_table_class = Cucumber::Core::Ast::ExamplesTable
100
+ scenario_class = LegacyApi::Ast::Scenario
101
+ example_table_class = Core::Ast::ExamplesTable
102
102
 
103
103
  runtime.scenarios(:failed).select do |s|
104
104
  [scenario_class, example_table_class].include?(s.class)
@@ -118,7 +118,7 @@ module Cucumber
118
118
  end
119
119
 
120
120
  def print_exception(e, status, indent)
121
- message = "#{e.message} (#{e.class})"
121
+ message = "#{e.message} (#{e.class})".force_encoding("UTF-8")
122
122
  if ENV['CUCUMBER_TRUNCATE_OUTPUT']
123
123
  message = linebreaks(message, ENV['CUCUMBER_TRUNCATE_OUTPUT'].to_i)
124
124
  end
@@ -132,18 +132,24 @@ module Cucumber
132
132
  s.gsub(/.{1,#{max}}(?:\s|\Z)/){($& + 5.chr).gsub(/\n\005/,"\n").gsub(/\005/,"\n")}.rstrip
133
133
  end
134
134
 
135
+ def collect_snippet_data(test_step, result)
136
+ # collect snippet data for undefined steps
137
+ unless hook?(test_step)
138
+ keyword = test_step.source.last.actual_keyword(@previous_step_keyword)
139
+ @previous_step_keyword = keyword
140
+ if result.undefined?
141
+ @snippets_input << Console::SnippetData.new(keyword, test_step.source.last)
142
+ end
143
+ end
144
+ end
145
+
135
146
  def print_snippets(options)
136
147
  return unless options[:snippets]
137
- undefined = runtime.steps(:undefined)
138
- return if undefined.empty?
148
+ return if runtime.steps(:undefined).empty?
139
149
 
140
- unknown_programming_language = runtime.unknown_programming_language?
141
- snippets = undefined.map do |step|
142
- # step_name = Undefined === step.exception ? step.exception.step_name : step.name
143
- # TODO: This probably won't work for nested steps :( See above for old code.
144
- step_name = step.name
145
- @runtime.snippet_text(step.actual_keyword, step_name, step.multiline_arg)
146
- end.compact.uniq
150
+ snippets = @snippets_input.map do |data|
151
+ @runtime.snippet_text(data.actual_keyword, data.step.name, data.step.multiline_arg)
152
+ end.uniq
147
153
 
148
154
  text = "\nYou can implement step definitions for undefined steps with these snippets:\n\n"
149
155
  text += snippets.join("\n\n")
@@ -215,16 +221,27 @@ module Cucumber
215
221
  @io.puts "Using the #{profiles_sentence} profile#{'s' if profiles.size> 1}..."
216
222
  end
217
223
 
218
- private
224
+ private
219
225
 
220
- FORMATS = Hash.new{ |hash, format| hash[format] = method(format).to_proc }
226
+ FORMATS = Hash.new{ |hash, format| hash[format] = method(format).to_proc }
221
227
 
222
- def format_for(*keys)
223
- key = keys.join('_').to_sym
224
- fmt = FORMATS[key]
225
- raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
226
- fmt
227
- end
228
+ def format_for(*keys)
229
+ key = keys.join('_').to_sym
230
+ fmt = FORMATS[key]
231
+ raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
232
+ fmt
233
+ end
234
+
235
+ def hook?(test_step)
236
+ not test_step.source.last.respond_to?(:actual_keyword)
237
+ end
238
+
239
+ class SnippetData
240
+ attr_reader :actual_keyword, :step
241
+ def initialize(actual_keyword, step)
242
+ @actual_keyword, @step = actual_keyword, step
243
+ end
244
+ end
228
245
 
229
246
  end
230
247
  end
@@ -6,7 +6,6 @@ module Cucumber
6
6
  class Debug
7
7
  def initialize(runtime, io, options)
8
8
  @io = io
9
- @indent = 0
10
9
  end
11
10
 
12
11
  def log(message)
@@ -19,9 +18,7 @@ module Cucumber
19
18
  end
20
19
 
21
20
  def method_missing(name, *args)
22
- @indent -= 2 if name.to_s =~ /^after/
23
21
  print(name)
24
- @indent += 2 if name.to_s =~ /^before/
25
22
  end
26
23
 
27
24
  def puts(*args)
@@ -31,11 +28,7 @@ module Cucumber
31
28
  private
32
29
 
33
30
  def print(text)
34
- @io.puts "#{indent}#{text}"
35
- end
36
-
37
- def indent
38
- (' ' * @indent)
31
+ @io.puts text
39
32
  end
40
33
  end
41
34
  end
@@ -0,0 +1,27 @@
1
+ module Cucumber
2
+ module Formatter
3
+
4
+ # Forwards any messages sent to this object to all recipients
5
+ # that respond to that message.
6
+ class Fanout < BasicObject
7
+ attr_reader :recipients
8
+ private :recipients
9
+
10
+ def initialize(recipients)
11
+ @recipients = recipients
12
+ end
13
+
14
+ def method_missing(message, *args)
15
+ recipients.each do |recipient|
16
+ recipient.send(message, *args) if recipient.respond_to?(message)
17
+ end
18
+ end
19
+
20
+ def respond_to_missing?(name, include_private = false)
21
+ recipients.any? { |recipient| recipient.respond_to?(name, include_private) }
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end