rspec-mocks 2.99.4 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +1 -0
  4. data/Changelog.md +89 -105
  5. data/License.txt +1 -0
  6. data/README.md +77 -57
  7. data/features/argument_matchers/explicit.feature +5 -5
  8. data/features/argument_matchers/general_matchers.feature +10 -10
  9. data/features/argument_matchers/type_matchers.feature +3 -3
  10. data/features/message_expectations/allow_any_instance_of.feature +1 -1
  11. data/features/message_expectations/any_instance.feature +27 -5
  12. data/features/message_expectations/call_original.feature +2 -2
  13. data/features/message_expectations/expect_message_using_expect.feature +2 -2
  14. data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
  15. data/features/message_expectations/receive_counts.feature +7 -7
  16. data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
  17. data/features/method_stubs/README.md +3 -0
  18. data/features/method_stubs/any_instance.feature +11 -11
  19. data/features/method_stubs/as_null_object.feature +4 -4
  20. data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
  21. data/features/method_stubs/stub_chain.feature +3 -3
  22. data/features/method_stubs/stub_implementation.feature +2 -2
  23. data/features/method_stubs/to_ary.feature +2 -2
  24. data/features/mutating_constants/hiding_defined_constant.feature +2 -2
  25. data/features/mutating_constants/stub_defined_constant.feature +5 -5
  26. data/features/mutating_constants/stub_undefined_constant.feature +6 -6
  27. data/features/outside_rspec/configuration.feature +0 -2
  28. data/features/outside_rspec/standalone.feature +1 -1
  29. data/features/spies/spy_partial_mock_method.feature +2 -2
  30. data/features/spies/spy_pure_mock_method.feature +5 -5
  31. data/features/spies/spy_unstubbed_method.feature +1 -1
  32. data/features/support/env.rb +10 -1
  33. data/features/test_frameworks/test_unit.feature +1 -1
  34. data/features/verifying_doubles/class_doubles.feature +88 -0
  35. data/features/verifying_doubles/dynamic_classes.feature +72 -0
  36. data/features/verifying_doubles/introduction.feature +85 -0
  37. data/features/verifying_doubles/object_doubles.feature +65 -0
  38. data/features/verifying_doubles/partial_doubles.feature +34 -0
  39. data/lib/rspec/mocks.rb +8 -34
  40. data/lib/rspec/mocks/any_instance/chain.rb +4 -34
  41. data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
  42. data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
  43. data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
  44. data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
  45. data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
  46. data/lib/rspec/mocks/argument_matchers.rb +26 -12
  47. data/lib/rspec/mocks/arity_calculator.rb +66 -0
  48. data/lib/rspec/mocks/configuration.rb +42 -14
  49. data/lib/rspec/mocks/error_generator.rb +34 -10
  50. data/lib/rspec/mocks/example_methods.rb +64 -19
  51. data/lib/rspec/mocks/extensions/marshal.rb +0 -15
  52. data/lib/rspec/mocks/framework.rb +4 -4
  53. data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
  54. data/lib/rspec/mocks/matchers/have_received.rb +18 -14
  55. data/lib/rspec/mocks/matchers/receive.rb +29 -7
  56. data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  57. data/lib/rspec/mocks/message_expectation.rb +95 -148
  58. data/lib/rspec/mocks/method_double.rb +77 -139
  59. data/lib/rspec/mocks/method_reference.rb +95 -0
  60. data/lib/rspec/mocks/mock.rb +1 -1
  61. data/lib/rspec/mocks/mutate_const.rb +12 -9
  62. data/lib/rspec/mocks/object_reference.rb +90 -0
  63. data/lib/rspec/mocks/order_group.rb +49 -7
  64. data/lib/rspec/mocks/proxy.rb +72 -33
  65. data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
  66. data/lib/rspec/mocks/space.rb +13 -18
  67. data/lib/rspec/mocks/stub_chain.rb +2 -2
  68. data/lib/rspec/mocks/syntax.rb +61 -36
  69. data/lib/rspec/mocks/targets.rb +40 -19
  70. data/lib/rspec/mocks/test_double.rb +12 -56
  71. data/lib/rspec/mocks/verifying_double.rb +77 -0
  72. data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  73. data/lib/rspec/mocks/verifying_proxy.rb +151 -0
  74. data/lib/rspec/mocks/version.rb +1 -1
  75. data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
  76. data/spec/rspec/mocks/and_yield_spec.rb +2 -2
  77. data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
  78. data/spec/rspec/mocks/any_instance_spec.rb +53 -260
  79. data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
  80. data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
  81. data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
  82. data/spec/rspec/mocks/at_least_spec.rb +4 -32
  83. data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
  84. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
  85. data/spec/rspec/mocks/configuration_spec.rb +79 -0
  86. data/spec/rspec/mocks/double_spec.rb +10 -78
  87. data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
  88. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
  89. data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
  90. data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
  91. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
  92. data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
  93. data/spec/rspec/mocks/methods_spec.rb +1 -1
  94. data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
  95. data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
  96. data/spec/rspec/mocks/mock_space_spec.rb +10 -1
  97. data/spec/rspec/mocks/mock_spec.rb +26 -82
  98. data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
  99. data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
  100. data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
  101. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  102. data/spec/rspec/mocks/order_group_spec.rb +27 -0
  103. data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
  104. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
  105. data/spec/rspec/mocks/record_messages_spec.rb +4 -4
  106. data/spec/rspec/mocks/serialization_spec.rb +4 -6
  107. data/spec/rspec/mocks/space_spec.rb +3 -3
  108. data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
  109. data/spec/rspec/mocks/stub_spec.rb +23 -44
  110. data/spec/rspec/mocks/test_double_spec.rb +3 -22
  111. data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
  112. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
  113. data/spec/rspec/mocks_spec.rb +16 -39
  114. data/spec/spec_helper.rb +29 -18
  115. metadata +131 -86
  116. metadata.gz.sig +1 -0
  117. data/features/message_expectations/expect_any_instance_of.feature +0 -27
  118. data/lib/rspec/mocks/caller_filter.rb +0 -60
  119. data/lib/rspec/mocks/deprecation.rb +0 -26
  120. data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
  121. data/lib/rspec/mocks/extensions/proc.rb +0 -63
  122. data/lib/spec/mocks.rb +0 -4
  123. data/spec/rspec/mocks/and_return_spec.rb +0 -17
  124. data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
  125. data/spec/rspec/mocks/before_all_spec.rb +0 -74
  126. data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
  127. data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
  128. data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
  129. data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
  130. data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
  131. data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
  132. data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
  133. data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -12,11 +12,16 @@ module RSpec
12
12
  private
13
13
 
14
14
  def create_message_expectation_on(instance)
15
- super do |proxy, expected_from|
16
- stub = proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)
17
- @recorder.stubs[stub.message] << stub
18
- stub
15
+ proxy = ::RSpec::Mocks.proxy_for(instance)
16
+ expected_from = IGNORED_BACKTRACE_LINE
17
+ stub = proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)
18
+ @recorder.stubs[stub.message] << stub
19
+
20
+ if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
21
+ stub.and_yield_receiver_to_implementation
19
22
  end
23
+
24
+ stub
20
25
  end
21
26
 
22
27
  def invocation_order
@@ -23,6 +23,8 @@ module RSpec
23
23
  # arg_list_matcher = RSpec::Mocks::ArgumentListMatcher.new(123, hash_including(:a => 'b'))
24
24
  # arg_list_matcher.args_match?(123, :a => 'b')
25
25
  #
26
+ # This class is immutable.
27
+ #
26
28
  # @see ArgumentMatchers
27
29
  class ArgumentListMatcher
28
30
  # @private
@@ -69,7 +71,7 @@ module RSpec
69
71
 
70
72
  def matcher_for(arg)
71
73
  return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
72
- return ArgumentMatchers::RegexpMatcher.new(arg) if arg.is_a?(Regexp)
74
+ return ArgumentMatchers::RegexpMatcher.new(arg) if Regexp === arg
73
75
  return ArgumentMatchers::EqualityProxy.new(arg)
74
76
  end
75
77
 
@@ -92,6 +94,11 @@ module RSpec
92
94
  def match_any_args?
93
95
  @match_any_args
94
96
  end
97
+
98
+ # Value that will match all argument lists.
99
+ #
100
+ # @private
101
+ MATCH_ALL = new(ArgumentMatchers::AnyArgsMatcher.new)
95
102
  end
96
103
  end
97
104
  end
@@ -83,6 +83,20 @@ module RSpec
83
83
  end
84
84
  end
85
85
 
86
+ class ArrayIncludingMatcher
87
+ def initialize(expected)
88
+ @expected = expected
89
+ end
90
+
91
+ def ==(actual)
92
+ Set.new(actual).superset?(Set.new(@expected))
93
+ end
94
+
95
+ def description
96
+ "array_including(#{@expected.join(",")})"
97
+ end
98
+ end
99
+
86
100
  class DuckTypeMatcher
87
101
  def initialize(*methods_to_respond_to)
88
102
  @methods_to_respond_to = methods_to_respond_to
@@ -109,18 +123,6 @@ module RSpec
109
123
  end
110
124
 
111
125
  def ==(expected)
112
- if defined?(DateTime) && DateTime === expected
113
- RSpec.warn_deprecation <<-WARN.gsub(/^\s*\|/,'')
114
- |In RSpec 3.0.0 matchers use `#===` (the match operator) to perform
115
- |comparision between expected and actual arguments. Due to strange
116
- |behaviour with `DateTime#===` (which ignores the time of the object
117
- |when performing a comparison) this may result in undesired
118
- |behaviour. We recommend you switch to a `Date` or `Time` object
119
- |instead.
120
- |
121
- |Called from: #{RSpec::CallerFilter.first_non_rspec_line}
122
- WARN
123
- end
124
126
  @given == expected
125
127
  end
126
128
  end
@@ -204,6 +206,18 @@ module RSpec
204
206
  HashIncludingMatcher.new(anythingize_lonely_keys(*args))
205
207
  end
206
208
 
209
+ # Matches an array that includes the specified items at least once.
210
+ # Ignores duplicates and additional values
211
+ #
212
+ # @example
213
+ #
214
+ # object.should_receive(:message).with(array_including(1,2,3))
215
+ # object.should_receive(:message).with(array_including([1,2,3]))
216
+ def array_including(*args)
217
+ actually_an_array = Array === args.first && args.count == 1 ? args.first : args
218
+ ArrayIncludingMatcher.new(actually_an_array)
219
+ end
220
+
207
221
  # Matches a hash that doesn't include the specified key(s) or key/value.
208
222
  #
209
223
  # @example
@@ -0,0 +1,66 @@
1
+ module RSpec
2
+ module Mocks
3
+
4
+ # Figures out the valid arity range for a method. Surprisingly non-trivial.
5
+ class ArityCalculator
6
+
7
+ def initialize(method)
8
+ @method = method
9
+ end
10
+
11
+ # @api private
12
+ def within_range?(actual)
13
+ min_arity <= actual && actual <= max_arity
14
+ end
15
+
16
+ # @api private
17
+ def range_description
18
+ return min_arity.to_s if min_arity == max_arity
19
+ return "#{min_arity} or more" if max_arity == INFINITY
20
+ "#{min_arity} to #{max_arity}"
21
+ end
22
+
23
+ private
24
+
25
+ def method
26
+ @method
27
+ end
28
+
29
+ # @api private
30
+ def self.supports_optional_and_splat_args?
31
+ Method.method_defined?(:parameters)
32
+ end
33
+
34
+ def min_arity
35
+ return method.arity if method.arity >= 0
36
+ # `~` inverts the one's complement and gives us the number of
37
+ # required arguments.
38
+ ~method.arity
39
+ end
40
+
41
+ if supports_optional_and_splat_args?
42
+ def max_arity
43
+ params = method.parameters
44
+ if params.any? {|(type, _)| type == :rest }
45
+ # Method takes a splat argument
46
+ return INFINITY
47
+ else
48
+ params.count {|(type, _)| type != :block }
49
+ end
50
+ end
51
+ else
52
+ def max_arity
53
+ # On 1.8, Method#parameters does not exist. There is no way to
54
+ # distinguish between default and splat args, so there is no way to
55
+ # have it work correctly for both default and splat args, as far as I
56
+ # can tell. The best we can do is consider it INFINITY (to be
57
+ # tolerant of splat args).
58
+ method.arity < 0 ? INFINITY : method.arity
59
+ end
60
+ end
61
+
62
+ INFINITY = 1/0.0
63
+ end
64
+ end
65
+ end
66
+
@@ -4,9 +4,10 @@ module RSpec
4
4
  class Configuration
5
5
 
6
6
  def initialize
7
- @yield_receiver_to_any_instance_implementation_blocks = false
8
- @should_warn_about_any_instance_blocks = true
9
- @marshal_patched = false
7
+ @yield_receiver_to_any_instance_implementation_blocks = true
8
+ @verify_doubled_constant_names = false
9
+ @transfer_nested_constants = false
10
+ @verify_partial_doubles = false
10
11
  end
11
12
 
12
13
  def yield_receiver_to_any_instance_implementation_blocks?
@@ -14,14 +15,9 @@ module RSpec
14
15
  end
15
16
 
16
17
  def yield_receiver_to_any_instance_implementation_blocks=(arg)
17
- @should_warn_about_any_instance_blocks = false
18
18
  @yield_receiver_to_any_instance_implementation_blocks = arg
19
19
  end
20
20
 
21
- def should_warn_about_any_instance_blocks?
22
- @should_warn_about_any_instance_blocks
23
- end
24
-
25
21
  # Adds `stub` and `should_receive` to the given
26
22
  # modules or classes. This is usually only necessary
27
23
  # if you application uses some proxy classes that
@@ -64,12 +60,45 @@ module RSpec
64
60
  syntaxes
65
61
  end
66
62
 
67
- def patch_marshal_to_support_partial_doubles=(val)
68
- @marshal_patched = val
63
+ def verify_doubled_constant_names?
64
+ !!@verify_doubled_constant_names
65
+ end
66
+
67
+ # When this is set to true, an error will be raised when
68
+ # `instance_double` or `class_double` is given the name of an undefined
69
+ # constant. You probably only want to set this when running your entire
70
+ # test suite, with all production code loaded. Setting this for an
71
+ # isolated unit test will prevent you from being able to isolate it!
72
+ def verify_doubled_constant_names=(val)
73
+ @verify_doubled_constant_names = val
69
74
  end
70
75
 
71
- def marshal_patched?
72
- @marshal_patched
76
+ def transfer_nested_constants?
77
+ !!@transfer_nested_constants
78
+ end
79
+
80
+ # Sets the default for the `transfer_nested_constants` option when
81
+ # stubbing constants.
82
+ def transfer_nested_constants=(val)
83
+ @transfer_nested_constants = val
84
+ end
85
+
86
+ # When set to true, partial mocks will be verified the same as object
87
+ # doubles. Any stubs will have their arity checked against the original
88
+ # method, and methods that do not exist cannot be stubbed.
89
+ def verify_partial_doubles=(val)
90
+ @verify_partial_doubles = !!val
91
+ end
92
+
93
+ def verify_partial_doubles?
94
+ @verify_partial_doubles
95
+ end
96
+
97
+ # @api private
98
+ # Resets the configured syntax to the default.
99
+ def reset_syntaxes_to_default
100
+ self.syntax = [:should, :expect]
101
+ RSpec::Mocks::Syntax.warn_about_should!
73
102
  end
74
103
  end
75
104
 
@@ -77,7 +106,6 @@ module RSpec
77
106
  @configuration ||= Configuration.new
78
107
  end
79
108
 
80
- configuration.syntax = [:should, :expect]
109
+ configuration.reset_syntaxes_to_default
81
110
  end
82
111
  end
83
-
@@ -4,8 +4,7 @@ module RSpec
4
4
  class ErrorGenerator
5
5
  attr_writer :opts
6
6
 
7
- def initialize(target, name, options={})
8
- @declared_as = options[:__declared_as] || 'Mock'
7
+ def initialize(target, name)
9
8
  @target = target
10
9
  @name = name
11
10
  end
@@ -48,6 +47,22 @@ module RSpec
48
47
  __raise "(#{intro}).#{message}#{format_args(*args)}\n #{expected_part}\n #{received_part}"
49
48
  end
50
49
 
50
+ # @private
51
+ def raise_unimplemented_error(doubled_module, method_name)
52
+ __raise "%s does not implement:\n %s" % [
53
+ doubled_module.description,
54
+ method_name
55
+ ]
56
+ end
57
+
58
+ # @private
59
+ def raise_arity_error(calculator, actual)
60
+ __raise "Wrong number of arguments. Expected %s, got %s." % [
61
+ calculator.range_description,
62
+ actual
63
+ ]
64
+ end
65
+
51
66
  # @private
52
67
  def received_part_of_expectation_error(actual_received_count, *args)
53
68
  "received: #{count_message(actual_received_count)}" +
@@ -62,11 +77,14 @@ module RSpec
62
77
 
63
78
  # @private
64
79
  def method_call_args_description(args)
65
- if args.first.is_a?(ArgumentMatchers::AnyArgsMatcher)
66
- " with any arguments"
67
- elsif args.first.is_a?(ArgumentMatchers::NoArgsMatcher)
68
- " with no arguments"
69
- elsif args.length > 0
80
+ case args.first
81
+ when ArgumentMatchers::AnyArgsMatcher
82
+ return " with any arguments"
83
+ when ArgumentMatchers::NoArgsMatcher
84
+ return " with no arguments"
85
+ end
86
+
87
+ if args.length > 0
70
88
  " with arguments: #{args.inspect.gsub(/\A\[(.+)\]\z/, '(\1)')}"
71
89
  else
72
90
  ""
@@ -127,9 +145,9 @@ module RSpec
127
145
 
128
146
  def intro
129
147
  if @name
130
- "#{@declared_as} #{@name.inspect}"
148
+ "Double #{@name.inspect}"
131
149
  elsif TestDouble === @target
132
- @declared_as
150
+ "Double"
133
151
  elsif Class === @target
134
152
  "<#{@target.inspect} (class)>"
135
153
  elsif @target
@@ -153,7 +171,13 @@ module RSpec
153
171
  end
154
172
 
155
173
  def arg_list(*args)
156
- args.collect {|arg| arg.respond_to?(:description) ? arg.description : arg.inspect}.join(", ")
174
+ args.collect {|arg| arg_has_valid_description(arg) ? arg.description : arg.inspect }.join(", ")
175
+ end
176
+
177
+ def arg_has_valid_description(arg)
178
+ return false unless arg.respond_to?(:description)
179
+
180
+ !arg.description.nil? && !arg.description.empty?
157
181
  end
158
182
 
159
183
  def format_received_args(*args)
@@ -1,3 +1,5 @@
1
+ require 'rspec/mocks/object_reference'
2
+
1
3
  module RSpec
2
4
  module Mocks
3
5
  module ExampleMethods
@@ -9,12 +11,12 @@ module RSpec
9
11
  # @overload double(name, stubs)
10
12
  # @param name [String/Symbol] (optional) used in
11
13
  # clarify intent
12
- # @param stubs (Hash) (optional) hash of method/return-value pairs
14
+ # @param stubs (Hash) (optional) hash of message/return-value pairs
13
15
  # @return (Mock)
14
16
  #
15
17
  # Constructs an instance of [RSpec::Mocks::Mock](RSpec::Mocks::Mock) configured
16
18
  # with an optional name, used for reporting in failure messages, and an optional
17
- # hash of method/return-value pairs.
19
+ # hash of message/return-value pairs.
18
20
  #
19
21
  # @example
20
22
  #
@@ -25,22 +27,53 @@ module RSpec
25
27
  # card.suit #=> "Spades"
26
28
  # card.rank #=> "A"
27
29
  #
28
- # @see #mock
29
- # @see #stub
30
30
  def double(*args)
31
- declare_double('Double', *args)
31
+ declare_double(Mock, *args)
32
+ end
33
+
34
+ # @overload instance_double(doubled_class)
35
+ # @overload instance_double(doubled_class, stubs)
36
+ # @param doubled_class [String, Class]
37
+ # @param stubs [Hash] (optional) hash of message/return-value pairs
38
+ # @return InstanceVerifyingDouble
39
+ #
40
+ # Constructs a test double against a specific class. If the given class
41
+ # name has been loaded, only instance methods defined on the class are
42
+ # allowed to be stubbed. In all other ways it behaves like a
43
+ # [double](double).
44
+ def instance_double(doubled_class, *args)
45
+ ref = ObjectReference.for(doubled_class)
46
+ declare_verifying_double(InstanceVerifyingDouble, ref, *args)
32
47
  end
33
48
 
34
- # Deprecated: Use [double](#double-instance_method).
35
- def mock(*args)
36
- RSpec.deprecate "mock", :replacement => "double"
37
- declare_double('Mock', *args)
49
+ # @overload class_double(doubled_class)
50
+ # @overload class_double(doubled_class, stubs)
51
+ # @param doubled_class [String, Module]
52
+ # @param stubs [Hash] (optional) hash of message/return-value pairs
53
+ # @return ClassVerifyingDouble
54
+ #
55
+ # Constructs a test double against a specific class. If the given class
56
+ # name has been loaded, only class methods defined on the class are
57
+ # allowed to be stubbed. In all other ways it behaves like a
58
+ # [double](double).
59
+ def class_double(doubled_class, *args)
60
+ ref = ObjectReference.for(doubled_class)
61
+ declare_verifying_double(ClassVerifyingDouble, ref, *args)
38
62
  end
39
63
 
40
- # Deprecated: Use [double](#double-instance_method).
41
- def stub(*args)
42
- RSpec.deprecate "stub", :replacement => "double"
43
- declare_double('Stub', *args)
64
+ # @overload object_double(object_or_name)
65
+ # @overload object_double(object_or_name, stubs)
66
+ # @param object_or_name [String, Object]
67
+ # @param stubs [Hash] (optional) hash of message/return-value pairs
68
+ # @return ObjectVerifyingDouble
69
+ #
70
+ # Constructs a test double against a specific object. Only the methods
71
+ # the object responds to are allowed to be stubbed. If a String argument
72
+ # is provided, it is assumed to reference a constant object which is used
73
+ # for verification. In all other ways it behaves like a [double](double).
74
+ def object_double(object_or_name, *args)
75
+ ref = ObjectReference.for(object_or_name, :allow_direct_object_refs)
76
+ declare_verifying_double(ObjectVerifyingDouble, ref, *args)
44
77
  end
45
78
 
46
79
  # Disables warning messages about expectations being set on nil.
@@ -127,12 +160,12 @@ module RSpec
127
160
  #
128
161
  # # You can also use most message expectations:
129
162
  # expect(invitation).to have_received(:accept).with(mailer).once
130
- def have_received(method_name)
131
- Matchers::HaveReceived.new(method_name)
163
+ def have_received(method_name, &block)
164
+ Matchers::HaveReceived.new(method_name, &block)
132
165
  end
133
166
 
134
167
  def self.included(klass)
135
- klass.class_eval do
168
+ klass.class_exec do
136
169
  # This gets mixed in so that if `RSpec::Matchers` is included in
137
170
  # `klass` later, it's definition of `expect` will take precedence.
138
171
  include ExpectHost unless method_defined?(:expect)
@@ -141,10 +174,22 @@ module RSpec
141
174
 
142
175
  private
143
176
 
144
- def declare_double(declared_as, *args)
177
+ def declare_verifying_double(type, ref, *args)
178
+ if RSpec::Mocks.configuration.verify_doubled_constant_names? &&
179
+ !ref.defined?
180
+
181
+ raise NameError,
182
+ "#{ref.name} is not a defined constant. " +
183
+ "Perhaps you misspelt it? " +
184
+ "Disable check with verify_doubled_constant_names configuration option."
185
+ end
186
+
187
+ declare_double(type, ref, *args)
188
+ end
189
+
190
+ def declare_double(type, *args)
145
191
  args << {} unless Hash === args.last
146
- args.last[:__declared_as] = declared_as
147
- RSpec::Mocks::Double.new(*args)
192
+ type.new(*args)
148
193
  end
149
194
 
150
195
  # This module exists to host the `expect` method for cases where