rspec-core 2.5.1 → 2.6.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 (123) hide show
  1. data/.travis.yml +7 -0
  2. data/Gemfile +12 -14
  3. data/README.md +4 -1
  4. data/Rakefile +29 -12
  5. data/cucumber.yml +1 -1
  6. data/features/.nav +15 -9
  7. data/features/Autotest.md +31 -7
  8. data/features/Changelog.md +46 -3
  9. data/features/Upgrade.md +35 -2
  10. data/features/command_line/README.md +22 -0
  11. data/features/command_line/configure.feature +2 -2
  12. data/features/command_line/example_name_option.feature +10 -10
  13. data/features/command_line/exit_status.feature +4 -4
  14. data/features/command_line/format_option.feature +4 -4
  15. data/features/command_line/line_number_appended_to_path.feature +11 -11
  16. data/features/command_line/line_number_option.feature +2 -2
  17. data/features/command_line/rake_task.feature +3 -3
  18. data/features/command_line/tag.feature +30 -14
  19. data/features/configuration/alias_example_to.feature +48 -0
  20. data/features/configuration/custom_settings.feature +3 -3
  21. data/features/configuration/fail_fast.feature +3 -3
  22. data/features/configuration/read_options_from_file.feature +4 -4
  23. data/features/example_groups/basic_structure.feature +11 -15
  24. data/features/example_groups/shared_context.feature +74 -0
  25. data/features/example_groups/shared_example_group.feature +21 -17
  26. data/features/expectation_framework_integration/configure_expectation_framework.feature +15 -4
  27. data/features/filtering/exclusion_filters.feature +28 -4
  28. data/features/filtering/{implicit_filters.feature → if_and_unless.feature} +9 -7
  29. data/features/filtering/inclusion_filters.feature +26 -3
  30. data/features/filtering/run_all_when_everything_filtered.feature +2 -2
  31. data/features/formatters/custom_formatter.feature +1 -1
  32. data/features/formatters/text_formatter.feature +43 -0
  33. data/features/helper_methods/arbitrary_methods.feature +2 -2
  34. data/features/helper_methods/let.feature +2 -2
  35. data/features/helper_methods/modules.feature +149 -0
  36. data/features/hooks/around_hooks.feature +18 -11
  37. data/features/hooks/before_and_after_hooks.feature +15 -19
  38. data/features/hooks/filtering.feature +160 -124
  39. data/features/metadata/current_example.feature +17 -0
  40. data/features/metadata/described_class.feature +2 -2
  41. data/features/metadata/user_defined.feature +111 -0
  42. data/features/mock_framework_integration/use_any_framework.feature +1 -1
  43. data/features/mock_framework_integration/use_flexmock.feature +83 -10
  44. data/features/mock_framework_integration/use_mocha.feature +84 -10
  45. data/features/mock_framework_integration/use_rr.feature +85 -10
  46. data/features/mock_framework_integration/use_rspec.feature +84 -10
  47. data/features/pending/pending_examples.feature +8 -8
  48. data/features/spec_files/arbitrary_file_suffix.feature +1 -1
  49. data/features/step_definitions/additional_cli_steps.rb +11 -1
  50. data/features/subject/attribute_of_subject.feature +24 -4
  51. data/features/subject/explicit_subject.feature +5 -5
  52. data/features/subject/implicit_receiver.feature +2 -2
  53. data/features/subject/implicit_subject.feature +2 -2
  54. data/features/support/env.rb +6 -1
  55. data/lib/rspec/core/backward_compatibility.rb +12 -2
  56. data/lib/rspec/core/command_line.rb +2 -5
  57. data/lib/rspec/core/configuration.rb +70 -38
  58. data/lib/rspec/core/configuration_options.rb +6 -23
  59. data/lib/rspec/core/drb_command_line.rb +5 -11
  60. data/lib/rspec/core/example.rb +29 -21
  61. data/lib/rspec/core/example_group.rb +40 -8
  62. data/lib/rspec/core/extensions/object.rb +0 -1
  63. data/lib/rspec/core/formatters/base_formatter.rb +6 -0
  64. data/lib/rspec/core/formatters/base_text_formatter.rb +1 -1
  65. data/lib/rspec/core/formatters/helpers.rb +0 -4
  66. data/lib/rspec/core/hooks.rb +14 -4
  67. data/lib/rspec/core/metadata.rb +1 -1
  68. data/lib/rspec/core/metadata_hash_builder.rb +93 -0
  69. data/lib/rspec/core/mocking/with_flexmock.rb +2 -0
  70. data/lib/rspec/core/mocking/with_mocha.rb +2 -0
  71. data/lib/rspec/core/mocking/with_rr.rb +2 -0
  72. data/lib/rspec/core/mocking/with_rspec.rb +3 -1
  73. data/lib/rspec/core/option_parser.rb +9 -2
  74. data/lib/rspec/core/pending.rb +10 -3
  75. data/lib/rspec/core/reporter.rb +2 -2
  76. data/lib/rspec/core/runner.rb +38 -13
  77. data/lib/rspec/core/shared_example_group.rb +18 -4
  78. data/lib/rspec/core/subject.rb +4 -6
  79. data/lib/rspec/core/version.rb +1 -1
  80. data/lib/rspec/core/world.rb +70 -18
  81. data/lib/rspec/core.rb +29 -0
  82. data/lib/rspec/monkey/spork/test_framework/rspec.rb +1 -0
  83. data/rspec-core.gemspec +3 -5
  84. data/spec/autotest/failed_results_re_spec.rb +2 -2
  85. data/spec/rspec/core/command_line_spec.rb +36 -2
  86. data/spec/rspec/core/configuration_spec.rb +150 -70
  87. data/spec/rspec/core/deprecations_spec.rb +21 -0
  88. data/spec/rspec/core/drb_command_line_spec.rb +21 -56
  89. data/spec/rspec/core/example_group_spec.rb +213 -56
  90. data/spec/rspec/core/example_spec.rb +110 -0
  91. data/spec/rspec/core/formatters/base_formatter_spec.rb +23 -2
  92. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +9 -0
  93. data/spec/rspec/core/formatters/helpers_spec.rb +1 -1
  94. data/spec/rspec/core/formatters/html_formatted-1.8.6.html +5 -5
  95. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +8 -10
  96. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +5 -5
  97. data/spec/rspec/core/formatters/html_formatted-1.9.1.html +5 -5
  98. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +5 -5
  99. data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -1
  100. data/spec/rspec/core/formatters/text_mate_formatted-1.8.6.html +5 -5
  101. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +8 -10
  102. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +5 -5
  103. data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +5 -5
  104. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +5 -5
  105. data/spec/rspec/core/hooks_spec.rb +86 -0
  106. data/spec/rspec/core/metadata_spec.rb +7 -7
  107. data/spec/rspec/core/option_parser_spec.rb +26 -15
  108. data/spec/rspec/core/pending_example_spec.rb +12 -51
  109. data/spec/rspec/core/reporter_spec.rb +19 -3
  110. data/spec/rspec/core/resources/formatter_specs.rb +7 -1
  111. data/spec/rspec/core/rspec_matchers_spec.rb +45 -0
  112. data/spec/rspec/core/runner_spec.rb +42 -10
  113. data/spec/rspec/core/shared_example_group_spec.rb +57 -21
  114. data/spec/rspec/core/subject_spec.rb +32 -11
  115. data/spec/rspec/core/world_spec.rb +147 -15
  116. data/spec/rspec/core_spec.rb +28 -0
  117. data/spec/spec_helper.rb +22 -2
  118. data/spec/support/matchers.rb +44 -13
  119. data/spec/support/shared_example_groups.rb +41 -0
  120. data/spec/support/spec_files.rb +44 -0
  121. data/spec.txt +1126 -0
  122. metadata +35 -16
  123. data/spec/ruby_forker.rb +0 -13
@@ -1,4 +1,5 @@
1
1
  require "rbconfig"
2
+ require 'fileutils'
2
3
 
3
4
  module RSpec
4
5
  module Core
@@ -26,30 +27,41 @@ module RSpec
26
27
  add_setting :profile_examples
27
28
  add_setting :fail_fast
28
29
  add_setting :run_all_when_everything_filtered
29
- add_setting :filter
30
30
  add_setting :exclusion_filter
31
- add_setting :filename_pattern, :default => '**/*_spec.rb'
31
+ add_setting :inclusion_filter
32
+ add_setting :filter, :alias => :inclusion_filter
33
+ add_setting :pattern, :default => '**/*_spec.rb'
34
+ add_setting :filename_pattern, :alias => :pattern
32
35
  add_setting :files_to_run
33
36
  add_setting :include_or_extend_modules
34
37
  add_setting :backtrace_clean_patterns
35
38
  add_setting :tty
39
+ add_setting :treat_symbols_as_metadata_keys_with_true_values, :default => false
40
+ add_setting :expecting_with_rspec
41
+
42
+ CONDITIONAL_FILTERS = {
43
+ :if => lambda { |value, metadata| metadata.has_key?(:if) && !value },
44
+ :unless => lambda { |value| value }
45
+ }
46
+
47
+ DEFAULT_BACKTRACE_PATTERNS = [
48
+ /\/lib\d*\/ruby\//,
49
+ /bin\//,
50
+ /gems/,
51
+ /spec\/spec_helper\.rb/,
52
+ /lib\/rspec\/(core|expectations|matchers|mocks)/
53
+ ]
36
54
 
37
55
  def initialize
38
56
  @color_enabled = false
39
57
  self.include_or_extend_modules = []
40
58
  self.files_to_run = []
41
- self.backtrace_clean_patterns = [
42
- /\/lib\d*\/ruby\//,
43
- /bin\//,
44
- /gems/,
45
- /spec\/spec_helper\.rb/,
46
- /lib\/rspec\/(core|expectations|matchers|mocks)/
47
- ]
59
+ self.backtrace_clean_patterns = DEFAULT_BACKTRACE_PATTERNS.dup
60
+ self.exclusion_filter = CONDITIONAL_FILTERS.dup
61
+ end
48
62
 
49
- filter_run_excluding(
50
- :if => lambda { |value, metadata| metadata.has_key?(:if) && !value },
51
- :unless => lambda { |value| value }
52
- )
63
+ def reset
64
+ @reporter = nil
53
65
  end
54
66
 
55
67
  # :call-seq:
@@ -103,7 +115,7 @@ module RSpec
103
115
  end
104
116
 
105
117
  def clear_inclusion_filter # :nodoc:
106
- self.filter = nil
118
+ self.inclusion_filter = nil
107
119
  end
108
120
 
109
121
  def cleaned_from_backtrace?(line)
@@ -169,13 +181,11 @@ module RSpec
169
181
 
170
182
  # Returns the configured expectation framework adapter module(s)
171
183
  def expectation_frameworks
172
- settings[:expectation_frameworks] ||= begin
173
- require 'rspec/core/expecting/with_rspec'
174
- [RSpec::Core::ExpectationFrameworkAdapter]
175
- end
184
+ expect_with :rspec unless settings[:expectation_frameworks]
185
+ settings[:expectation_frameworks]
176
186
  end
177
187
 
178
- # Delegates to expect_with=([framework])
188
+ # Delegates to expect_with([framework])
179
189
  def expectation_framework=(framework)
180
190
  expect_with([framework])
181
191
  end
@@ -195,6 +205,7 @@ module RSpec
195
205
  case framework
196
206
  when :rspec
197
207
  require 'rspec/core/expecting/with_rspec'
208
+ self.expecting_with_rspec = true
198
209
  when :stdlib
199
210
  require 'rspec/core/expecting/with_stdlib'
200
211
  else
@@ -205,8 +216,8 @@ module RSpec
205
216
  end
206
217
  end
207
218
 
208
- def full_backtrace=(bool)
209
- settings[:backtrace_clean_patterns] = []
219
+ def full_backtrace=(true_or_false)
220
+ settings[:backtrace_clean_patterns] = true_or_false ? [] : DEFAULT_BACKTRACE_PATTERNS
210
221
  end
211
222
 
212
223
  def color_enabled
@@ -263,13 +274,13 @@ EOM
263
274
  filter_run({ :full_description => /#{description}/ }, true)
264
275
  end
265
276
 
266
- def add_formatter(formatter_to_use, output=nil)
277
+ def add_formatter(formatter_to_use, path=nil)
267
278
  formatter_class =
268
279
  built_in_formatter(formatter_to_use) ||
269
280
  custom_formatter(formatter_to_use) ||
270
281
  (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
271
282
 
272
- formatters << formatter_class.new(output ? File.new(output, 'w') : self.output)
283
+ formatters << formatter_class.new(path ? file_at(path) : output)
273
284
  end
274
285
 
275
286
  alias_method :formatter=, :add_formatter
@@ -288,7 +299,7 @@ EOM
288
299
  def files_or_directories_to_run=(*files)
289
300
  self.files_to_run = files.flatten.collect do |file|
290
301
  if File.directory?(file)
291
- filename_pattern.split(",").collect do |pattern|
302
+ pattern.split(",").collect do |pattern|
292
303
  Dir["#{file}/#{pattern.strip}"]
293
304
  end
294
305
  else
@@ -304,7 +315,8 @@ EOM
304
315
 
305
316
  # E.g. alias_example_to :crazy_slow, :speed => 'crazy_slow' defines
306
317
  # crazy_slow as an example variant that has the crazy_slow speed option
307
- def alias_example_to(new_name, extra_options={})
318
+ def alias_example_to(new_name, *args)
319
+ extra_options = build_metadata_hash_from(args)
308
320
  RSpec::Core::ExampleGroup.alias_example_to(new_name, extra_options)
309
321
  end
310
322
 
@@ -333,39 +345,53 @@ EOM
333
345
  RSpec::Core::ExampleGroup.alias_it_should_behave_like_to(new_name, report_label)
334
346
  end
335
347
 
336
- def filter_run_including(options={}, force_overwrite = false)
337
- if filter and filter[:line_number] || filter[:full_description]
348
+ def exclusion_filter=(filter)
349
+ settings[:exclusion_filter] = filter
350
+ end
351
+
352
+ def inclusion_filter=(filter)
353
+ settings[:inclusion_filter] = filter
354
+ end
355
+
356
+ def filter_run_including(*args)
357
+ force_overwrite = if args.last.is_a?(Hash) || args.last.is_a?(Symbol)
358
+ false
359
+ else
360
+ args.pop
361
+ end
362
+
363
+ options = build_metadata_hash_from(args)
364
+
365
+ if inclusion_filter and inclusion_filter[:line_number] || inclusion_filter[:full_description]
338
366
  warn "Filtering by #{options.inspect} is not possible since " \
339
- "you are already filtering by #{filter.inspect}"
367
+ "you are already filtering by #{inclusion_filter.inspect}"
340
368
  else
341
369
  if force_overwrite
342
- self.filter = options
370
+ self.inclusion_filter = options
343
371
  else
344
- self.filter = (filter || {}).merge(options)
372
+ self.inclusion_filter = (inclusion_filter || {}).merge(options)
345
373
  end
346
374
  end
347
375
  end
348
376
 
349
377
  alias_method :filter_run, :filter_run_including
350
378
 
351
- def filter_run_excluding(options={})
379
+ def filter_run_excluding(*args)
380
+ options = build_metadata_hash_from(args)
352
381
  self.exclusion_filter = (exclusion_filter || {}).merge(options)
353
382
  end
354
383
 
355
- def include(mod, filters={})
384
+ def include(mod, *args)
385
+ filters = build_metadata_hash_from(args)
356
386
  include_or_extend_modules << [:include, mod, filters]
357
387
  end
358
388
 
359
- def extend(mod, filters={})
389
+ def extend(mod, *args)
390
+ filters = build_metadata_hash_from(args)
360
391
  include_or_extend_modules << [:extend, mod, filters]
361
392
  end
362
393
 
363
394
  def configure_group(group)
364
- modules = {
365
- :include => group.included_modules.dup,
366
- :extend => group.ancestors.dup
367
- }
368
-
369
395
  include_or_extend_modules.each do |include_or_extend, mod, filters|
370
396
  next unless filters.empty? || group.apply?(:any?, filters)
371
397
  group.send(include_or_extend, mod)
@@ -465,6 +491,12 @@ MESSAGE
465
491
  word.downcase!
466
492
  word
467
493
  end
494
+
495
+ def file_at(path)
496
+ FileUtils.mkdir_p(File.dirname(path))
497
+ File.new(path, 'w')
498
+ end
499
+
468
500
  end
469
501
  end
470
502
  end
@@ -1,6 +1,3 @@
1
- # http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
2
- require 'optparse'
3
-
4
1
  module RSpec
5
2
  module Core
6
3
 
@@ -60,35 +57,21 @@ module RSpec
60
57
  end
61
58
 
62
59
  def parse_options
63
- @options = begin
64
- options_to_merge = []
65
- if custom_options_file
66
- options_to_merge << custom_options
67
- else
68
- options_to_merge << global_options
69
- options_to_merge << local_options
70
- end
71
- options_to_merge << command_line_options
72
- options_to_merge << env_options
73
-
74
- options_to_merge.inject do |merged, options|
75
- merged.merge(options)
76
- end
77
- end
60
+ @options ||= [file_options, command_line_options, env_options].inject {|merged, o| merged.merge o}
78
61
  end
79
62
 
80
63
  private
81
64
 
65
+ def file_options
66
+ custom_options_file ? custom_options : global_options.merge(local_options)
67
+ end
68
+
82
69
  def env_options
83
70
  ENV["SPEC_OPTS"] ? Parser.parse!(ENV["SPEC_OPTS"].split) : {}
84
71
  end
85
72
 
86
73
  def command_line_options
87
- @command_line_options ||= begin
88
- options = Parser.parse!(@args)
89
- options[:files_or_directories_to_run] = @args
90
- options
91
- end
74
+ @command_line_options ||= Parser.parse!(@args).merge :files_or_directories_to_run => @args
92
75
  end
93
76
 
94
77
  def custom_options
@@ -11,18 +11,12 @@ module RSpec
11
11
 
12
12
  def run(err, out)
13
13
  begin
14
- begin
15
- DRb.start_service("druby://localhost:0")
16
- rescue SocketError, Errno::EADDRNOTAVAIL
17
- DRb.start_service("druby://:0")
18
- end
19
- spec_server = DRbObject.new_with_uri("druby://127.0.0.1:#{drb_port}")
20
- spec_server.run(@options.drb_argv, err, out)
21
- true
22
- rescue DRb::DRbConnError
23
- err.puts "No DRb server is running. Running in local process instead ..."
24
- false
14
+ DRb.start_service("druby://localhost:0")
15
+ rescue SocketError, Errno::EADDRNOTAVAIL
16
+ DRb.start_service("druby://:0")
25
17
  end
18
+ spec_server = DRbObject.new_with_uri("druby://127.0.0.1:#{drb_port}")
19
+ spec_server.run(@options.drb_argv, err, out)
26
20
  end
27
21
  end
28
22
  end
@@ -42,24 +42,32 @@ module RSpec
42
42
 
43
43
  begin
44
44
  unless pending
45
- with_pending_capture do
46
- with_around_hooks do
47
- begin
48
- run_before_each
49
- @example_group_instance.instance_eval(&@example_block)
50
- rescue Exception => e
51
- set_exception(e)
52
- ensure
53
- run_after_each
54
- end
45
+ with_around_hooks do
46
+ begin
47
+ run_before_each
48
+ @example_group_instance.instance_eval(&@example_block)
49
+ rescue Pending::PendingDeclaredInExample => e
50
+ @pending_declared_in_example = e.message
51
+ rescue Exception => e
52
+ set_exception(e)
53
+ ensure
54
+ run_after_each
55
55
  end
56
56
  end
57
57
  end
58
58
  rescue Exception => e
59
59
  set_exception(e)
60
60
  ensure
61
- @example_group_instance.example = nil
62
- assign_auto_description
61
+ @example_group_instance.instance_variables.each do |ivar|
62
+ @example_group_instance.instance_variable_set(ivar, nil)
63
+ end
64
+ @example_group_instance = nil
65
+
66
+ begin
67
+ assign_auto_description
68
+ rescue Exception => e
69
+ set_exception(e)
70
+ end
63
71
  end
64
72
 
65
73
  finish(reporter)
@@ -94,13 +102,6 @@ module RSpec
94
102
 
95
103
  private
96
104
 
97
- def with_pending_capture
98
- @pending_declared_in_example = catch(:pending_declared_in_example) do
99
- yield
100
- throw :pending_declared_in_example, false
101
- end
102
- end
103
-
104
105
  def with_around_hooks(&block)
105
106
  if around_hooks.empty?
106
107
  yield
@@ -153,8 +154,15 @@ module RSpec
153
154
 
154
155
  def assign_auto_description
155
156
  if description.empty? and !pending?
156
- metadata[:description] = RSpec::Matchers.generated_description
157
- RSpec::Matchers.clear_generated_description
157
+ if RSpec.configuration.expecting_with_rspec?
158
+ metadata[:description] = RSpec::Matchers.generated_description
159
+ RSpec::Matchers.clear_generated_description
160
+ else
161
+ raise NotImplementedError.new(
162
+ "Generated descriptions are only supported when you use rspec-expectations. " +
163
+ "You must give every example an explicit description."
164
+ )
165
+ end
158
166
  end
159
167
  end
160
168
 
@@ -1,13 +1,15 @@
1
1
  module RSpec
2
2
  module Core
3
3
  class ExampleGroup
4
+ extend MetadataHashBuilder::WithDeprecationWarning
4
5
  extend Extensions::ModuleEvalWithArgs
5
- include Extensions::InstanceEvalWithArgs
6
- extend Hooks
7
6
  extend Subject::ClassMethods
7
+ extend Hooks
8
+
9
+ include Extensions::InstanceEvalWithArgs
8
10
  include Subject::InstanceMethods
9
- include Let
10
11
  include Pending
12
+ include Let
11
13
 
12
14
  attr_accessor :example
13
15
 
@@ -21,7 +23,6 @@ module RSpec
21
23
  end
22
24
 
23
25
  def self.register
24
- RSpec::Core::Runner.autorun
25
26
  world.register(self)
26
27
  end
27
28
 
@@ -41,7 +42,8 @@ module RSpec
41
42
 
42
43
  def self.define_example_method(name, extra_options={})
43
44
  module_eval(<<-END_RUBY, __FILE__, __LINE__)
44
- def self.#{name}(desc=nil, options={}, &block)
45
+ def self.#{name}(desc=nil, *args, &block)
46
+ options = build_metadata_hash_from(args)
45
47
  options.update(:pending => true) unless block
46
48
  options.update(#{extra_options.inspect})
47
49
  examples << RSpec::Core::Example.new(self, desc, options, block)
@@ -63,7 +65,7 @@ module RSpec
63
65
  alias_example_to :pending, :pending => true
64
66
  alias_example_to :xit, :pending => true
65
67
 
66
- def self.define_shared_group_method(new_name, report_label=nil)
68
+ def self.define_nested_shared_group_method(new_name, report_label=nil)
67
69
  module_eval(<<-END_RUBY, __FILE__, __LINE__)
68
70
  def self.#{new_name}(name, *args, &customization_block)
69
71
  shared_block = world.shared_example_groups[name]
@@ -79,14 +81,22 @@ module RSpec
79
81
  END_RUBY
80
82
  end
81
83
 
82
- define_shared_group_method :it_should_behave_like
84
+ define_nested_shared_group_method :it_should_behave_like
83
85
 
84
86
  class << self
85
- alias_method :alias_it_should_behave_like_to, :define_shared_group_method
87
+ alias_method :alias_it_should_behave_like_to, :define_nested_shared_group_method
86
88
  end
87
89
 
88
90
  alias_it_should_behave_like_to :it_behaves_like, "behaves like"
89
91
 
92
+ def self.include_context(name)
93
+ module_eval(&world.shared_example_groups[name])
94
+ end
95
+
96
+ class << self
97
+ alias_method :include_examples, :include_context
98
+ end
99
+
90
100
  def self.examples
91
101
  @examples ||= []
92
102
  end
@@ -149,7 +159,27 @@ module RSpec
149
159
  @top_level ||= superclass == ExampleGroup
150
160
  end
151
161
 
162
+ def self.ensure_example_groups_are_configured
163
+ unless defined?(@@example_groups_configured)
164
+ RSpec.configuration.configure_mock_framework
165
+ RSpec.configuration.configure_expectation_framework
166
+ @@example_groups_configured = true
167
+ end
168
+ end
169
+
152
170
  def self.set_it_up(*args)
171
+ # Ruby 1.9 has a bug that can lead to infinite recursion and a
172
+ # SystemStackError if you include a module in a superclass after
173
+ # including it in a subclass: https://gist.github.com/845896
174
+ # To prevent this, we must include any modules in RSpec::Core::ExampleGroup
175
+ # before users create example groups and have a chance to include
176
+ # the same module in a subclass of RSpec::Core::ExampleGroup.
177
+ # So we need to configure example groups here.
178
+ ensure_example_groups_are_configured
179
+
180
+ symbol_description = args.shift if args.first.is_a?(Symbol)
181
+ args << build_metadata_hash_from(args)
182
+ args.unshift(symbol_description) if symbol_description
153
183
  @metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
154
184
  world.configure_group(self)
155
185
  end
@@ -236,6 +266,7 @@ An error occurred in an after(:all) hook.
236
266
  fail_filtered_examples(ex, reporter)
237
267
  ensure
238
268
  eval_after_alls(new)
269
+ before_all_ivars.clear
239
270
  reporter.example_group_finished(self)
240
271
  end
241
272
  end
@@ -248,6 +279,7 @@ An error occurred in an after(:all) hook.
248
279
  child.fail_filtered_examples(exception, reporter)
249
280
  reporter.example_group_finished(child)
250
281
  end
282
+ false
251
283
  end
252
284
 
253
285
  def self.fail_fast?
@@ -2,7 +2,6 @@ module RSpec
2
2
  module Core
3
3
  module ObjectExtensions
4
4
  def describe(*args, &example_group_block)
5
- args << {} unless args.last.is_a?(Hash)
6
5
  RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
7
6
  end
8
7
  end
@@ -1,4 +1,5 @@
1
1
  require 'rspec/core/formatters/helpers'
2
+ require 'stringio'
2
3
 
3
4
  module RSpec
4
5
  module Core
@@ -95,6 +96,11 @@ module RSpec
95
96
  def format_backtrace(backtrace, example)
96
97
  return "" unless backtrace
97
98
  return backtrace if example.metadata[:full_backtrace] == true
99
+
100
+ if at_exit_index = backtrace.index(RSpec::Core::Runner::AT_EXIT_HOOK_BACKTRACE_LINE)
101
+ backtrace = backtrace[0, at_exit_index]
102
+ end
103
+
98
104
  cleansed = backtrace.map { |line| backtrace_line(line) }.compact
99
105
  cleansed.empty? ? backtrace : cleansed
100
106
  end
@@ -148,7 +148,7 @@ module RSpec
148
148
  output.puts "#{short_padding}#{index.next}) #{example.full_description}"
149
149
  output.puts "#{long_padding}#{red("Failure/Error:")} #{red(read_failed_line(exception, example).strip)}"
150
150
  output.puts "#{long_padding}#{red(exception.class.name << ":")}" unless exception.class.name =~ /RSpec/
151
- exception.message.split("\n").each { |line| output.puts "#{long_padding} #{red(line)}" }
151
+ exception.message.split("\n").each { |line| output.puts "#{long_padding} #{red(line)}" } if exception.message
152
152
 
153
153
  example.example_group.ancestors.push(example.example_group).each do |group|
154
154
  if group.metadata[:shared_group_name]
@@ -1,7 +1,5 @@
1
1
  module RSpec
2
-
3
2
  module Core
4
-
5
3
  module Formatters
6
4
 
7
5
  module Helpers
@@ -22,7 +20,5 @@ module RSpec
22
20
  end
23
21
 
24
22
  end
25
-
26
23
  end
27
-
28
24
  end
@@ -1,12 +1,14 @@
1
1
  module RSpec
2
2
  module Core
3
3
  module Hooks
4
+ include MetadataHashBuilder::WithConfigWarning
4
5
 
5
6
  class Hook
6
7
  attr_reader :options
7
8
 
8
9
  def initialize(options, &block)
9
10
  @options = options
11
+ raise "no block given for #{self.class::TYPE} hook" unless block
10
12
  @block = block
11
13
  end
12
14
 
@@ -24,6 +26,7 @@ module RSpec
24
26
  end
25
27
 
26
28
  class BeforeHook < Hook
29
+ TYPE = 'before'
27
30
  def run_in(example_group_instance)
28
31
  if example_group_instance
29
32
  example_group_instance.instance_eval(&self)
@@ -34,6 +37,7 @@ module RSpec
34
37
  end
35
38
 
36
39
  class AfterHook < Hook
40
+ TYPE = 'after'
37
41
  def run_in(example_group_instance)
38
42
  if example_group_instance
39
43
  example_group_instance.instance_eval_with_rescue(&self)
@@ -44,6 +48,7 @@ module RSpec
44
48
  end
45
49
 
46
50
  class AroundHook < Hook
51
+ TYPE = 'around'
47
52
  def call(wrapped_example)
48
53
  @block.call(wrapped_example)
49
54
  end
@@ -137,11 +142,16 @@ module RSpec
137
142
 
138
143
  private
139
144
 
140
- def scope_and_options_from(scope=:each, options={})
141
- if Hash === scope
142
- options = scope
143
- scope = :each
145
+ def scope_and_options_from(*args)
146
+ scope = if [:each, :all, :suite].include?(args.first)
147
+ args.shift
148
+ elsif args.any? { |a| a.is_a?(Symbol) }
149
+ raise ArgumentError.new("You must explicitly give a scope (:each, :all, or :suite) when using symbols as metadata for a hook.")
150
+ else
151
+ :each
144
152
  end
153
+
154
+ options = build_metadata_hash_from(args)
145
155
  return scope, options
146
156
  end
147
157
  end
@@ -142,7 +142,7 @@ EOM
142
142
  metadata[key] == value
143
143
  end
144
144
  else
145
- metadata[key] == value
145
+ metadata[key].to_s == value.to_s
146
146
  end
147
147
  end
148
148