rspec-mocks 3.0.0 → 3.1.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 (39) hide show
  1. checksums.yaml +6 -14
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +89 -1
  4. data/README.md +32 -18
  5. data/lib/rspec/mocks/any_instance/chain.rb +2 -2
  6. data/lib/rspec/mocks/any_instance/expectation_chain.rb +2 -3
  7. data/lib/rspec/mocks/any_instance/message_chains.rb +8 -7
  8. data/lib/rspec/mocks/any_instance/proxy.rb +7 -3
  9. data/lib/rspec/mocks/any_instance/recorder.rb +27 -25
  10. data/lib/rspec/mocks/any_instance/stub_chain.rb +3 -5
  11. data/lib/rspec/mocks/argument_list_matcher.rb +4 -4
  12. data/lib/rspec/mocks/argument_matchers.rb +39 -6
  13. data/lib/rspec/mocks/configuration.rb +4 -11
  14. data/lib/rspec/mocks/error_generator.rb +33 -27
  15. data/lib/rspec/mocks/example_methods.rb +75 -7
  16. data/lib/rspec/mocks/instance_method_stasher.rb +5 -5
  17. data/lib/rspec/mocks/matchers/have_received.rb +10 -8
  18. data/lib/rspec/mocks/matchers/receive.rb +8 -8
  19. data/lib/rspec/mocks/matchers/receive_message_chain.rb +5 -6
  20. data/lib/rspec/mocks/matchers/receive_messages.rb +6 -7
  21. data/lib/rspec/mocks/message_chain.rb +5 -5
  22. data/lib/rspec/mocks/message_expectation.rb +66 -27
  23. data/lib/rspec/mocks/method_double.rb +15 -12
  24. data/lib/rspec/mocks/method_reference.rb +8 -7
  25. data/lib/rspec/mocks/mutate_const.rb +26 -100
  26. data/lib/rspec/mocks/object_reference.rb +12 -13
  27. data/lib/rspec/mocks/order_group.rb +4 -5
  28. data/lib/rspec/mocks/proxy.rb +35 -24
  29. data/lib/rspec/mocks/space.rb +25 -25
  30. data/lib/rspec/mocks/syntax.rb +101 -99
  31. data/lib/rspec/mocks/targets.rb +6 -6
  32. data/lib/rspec/mocks/test_double.rb +13 -4
  33. data/lib/rspec/mocks/verifying_double.rb +16 -16
  34. data/lib/rspec/mocks/verifying_message_expecation.rb +15 -13
  35. data/lib/rspec/mocks/verifying_proxy.rb +12 -16
  36. data/lib/rspec/mocks/version.rb +1 -1
  37. data.tar.gz.sig +0 -0
  38. metadata +61 -54
  39. metadata.gz.sig +0 -0
@@ -40,29 +40,38 @@ module RSpec
40
40
  def raise_unexpected_message_args_error(expectation, *args)
41
41
  expected_args = format_args(*expectation.expected_args)
42
42
  actual_args = format_received_args(*args)
43
- __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
43
+ __raise "#{intro} received #{expectation.message.inspect} with " \
44
+ "unexpected arguments\n expected: #{expected_args}\n" \
45
+ " got: #{actual_args}"
44
46
  end
45
47
 
46
48
  # @private
47
49
  def raise_missing_default_stub_error(expectation, *args)
48
50
  expected_args = format_args(*expectation.expected_args)
49
51
  actual_args = format_received_args(*args)
50
- __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}\n Please stub a default value first if message might be received with other args as well. \n"
52
+ __raise "#{intro} received #{expectation.message.inspect} with " \
53
+ "unexpected arguments\n expected: #{expected_args}\n" \
54
+ " got: #{actual_args}\n Please stub a default value " \
55
+ "first if message might be received with other args as well. \n"
51
56
  end
52
57
 
53
58
  # @private
54
59
  def raise_similar_message_args_error(expectation, *args_for_multiple_calls)
55
60
  expected_args = format_args(*expectation.expected_args)
56
- actual_args = args_for_multiple_calls.collect {|a| format_received_args(*a)}.join(", ")
57
- __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
61
+ actual_args = args_for_multiple_calls.map { |a| format_received_args(*a) }.join(", ")
62
+ __raise "#{intro} received #{expectation.message.inspect} with " \
63
+ "unexpected arguments\n expected: #{expected_args}\n" \
64
+ " got: #{actual_args}"
58
65
  end
59
66
 
67
+ # rubocop:disable Style/ParameterLists
60
68
  # @private
61
69
  def raise_expectation_error(message, expected_received_count, argument_list_matcher, actual_received_count, expectation_count_type, *args)
62
70
  expected_part = expected_part_of_expectation_error(expected_received_count, expectation_count_type, argument_list_matcher)
63
71
  received_part = received_part_of_expectation_error(actual_received_count, *args)
64
72
  __raise "(#{intro}).#{message}#{format_args(*args)}\n #{expected_part}\n #{received_part}"
65
73
  end
74
+ # rubocop:enable Style/ParameterLists
66
75
 
67
76
  # @private
68
77
  def raise_unimplemented_error(doubled_module, method_name)
@@ -87,10 +96,10 @@ module RSpec
87
96
  # @private
88
97
  def raise_expired_test_double_error
89
98
  raise ExpiredTestDoubleError,
90
- "#{intro} was originally created in one example but has leaked into " +
91
- "another example and can no longer be used. rspec-mocks' doubles are " +
92
- "designed to only last for one example, and you need to create a new " +
93
- "one in each example you wish to use it for."
99
+ "#{intro} was originally created in one example but has leaked into " \
100
+ "another example and can no longer be used. rspec-mocks' doubles are " \
101
+ "designed to only last for one example, and you need to create a new " \
102
+ "one in each example you wish to use it for."
94
103
  end
95
104
 
96
105
  # @private
@@ -128,15 +137,13 @@ module RSpec
128
137
  # @private
129
138
  def method_call_args_description(args)
130
139
  case args.first
131
- when ArgumentMatchers::AnyArgsMatcher
132
- return " with any arguments"
133
- when ArgumentMatchers::NoArgsMatcher
134
- return " with no arguments"
140
+ when ArgumentMatchers::AnyArgsMatcher then " with any arguments"
141
+ when ArgumentMatchers::NoArgsMatcher then " with no arguments"
135
142
  end
136
143
  end
137
144
 
138
145
  # @private
139
- def describe_expectation(message, expected_received_count, actual_received_count, *args)
146
+ def describe_expectation(message, expected_received_count, _actual_received_count, *args)
140
147
  "have received #{message}#{format_args(*args)} #{count_message(expected_received_count)}"
141
148
  end
142
149
 
@@ -162,30 +169,30 @@ module RSpec
162
169
 
163
170
  # @private
164
171
  def raise_only_valid_on_a_partial_double(method)
165
- __raise "#{intro} is a pure test double. `#{method}` is only " +
172
+ __raise "#{intro} is a pure test double. `#{method}` is only " \
166
173
  "available on a partial double."
167
174
  end
168
175
 
169
176
  # @private
170
177
  def raise_expectation_on_unstubbed_method(method)
171
- __raise "#{intro} expected to have received #{method}, but that " +
172
- "method has not been stubbed."
178
+ __raise "#{intro} expected to have received #{method}, but that " \
179
+ "object is not a spy or method has not been stubbed."
173
180
  end
174
181
 
175
182
  # @private
176
183
  def raise_expectation_on_mocked_method(method)
177
- __raise "#{intro} expected to have received #{method}, but that " +
178
- "method has been mocked instead of stubbed."
184
+ __raise "#{intro} expected to have received #{method}, but that " \
185
+ "method has been mocked instead of stubbed or spied."
179
186
  end
180
187
 
181
188
  def self.raise_double_negation_error(wrapped_expression)
182
- raise "Isn't life confusing enough? You've already set a " +
183
- "negative message expectation and now you are trying to " +
184
- "negate it again with `never`. What does an expression like " +
189
+ raise "Isn't life confusing enough? You've already set a " \
190
+ "negative message expectation and now you are trying to " \
191
+ "negate it again with `never`. What does an expression like " \
185
192
  "`#{wrapped_expression}.not_to receive(:msg).never` even mean?"
186
193
  end
187
194
 
188
- private
195
+ private
189
196
 
190
197
  def intro
191
198
  if @name
@@ -203,7 +210,7 @@ module RSpec
203
210
 
204
211
  def __raise(message)
205
212
  message = opts[:message] unless opts[:message].nil?
206
- Kernel::raise(RSpec::Mocks::MockExpectationError, message)
213
+ Kernel.raise(RSpec::Mocks::MockExpectationError, message)
207
214
  end
208
215
 
209
216
  def arg_message(*args)
@@ -215,7 +222,7 @@ module RSpec
215
222
  end
216
223
 
217
224
  def arg_list(*args)
218
- args.collect {|arg| arg_has_valid_description(arg) ? arg.description : arg.inspect }.join(", ")
225
+ args.map { |arg| arg_has_valid_description(arg) ? arg.description : arg.inspect }.join(", ")
219
226
  end
220
227
 
221
228
  def arg_has_valid_description(arg)
@@ -229,19 +236,18 @@ module RSpec
229
236
  end
230
237
 
231
238
  def received_arg_list(*args)
232
- args.collect(&:inspect).join(", ")
239
+ args.map(&:inspect).join(", ")
233
240
  end
234
241
 
235
242
  def count_message(count, expectation_count_type=nil)
236
243
  return "at least #{times(count.abs)}" if count < 0 || expectation_count_type == :at_least
237
244
  return "at most #{times(count)}" if expectation_count_type == :at_most
238
- return times(count)
245
+ times(count)
239
246
  end
240
247
 
241
248
  def times(count)
242
249
  "#{count} time#{count == 1 ? '' : 's'}"
243
250
  end
244
-
245
251
  end
246
252
  end
247
253
  end
@@ -84,6 +84,73 @@ module RSpec
84
84
  ExampleMethods.declare_verifying_double(ObjectVerifyingDouble, ref, *args)
85
85
  end
86
86
 
87
+ # @overload spy()
88
+ # @overload spy(name)
89
+ # @param name [String/Symbol] used to clarify intent
90
+ # @overload spy(stubs)
91
+ # @param stubs (Hash) hash of message/return-value pairs
92
+ # @overload spy(name, stubs)
93
+ # @param name [String/Symbol] used to clarify intent
94
+ # @param stubs (Hash) hash of message/return-value pairs
95
+ # @return (Double)
96
+ #
97
+ # Constructs a test double that is optimized for use with
98
+ # `have_received`. With a normal double one has to stub methods in order
99
+ # to be able to spy them. A spy automatically spies on all methods.
100
+ def spy(*args)
101
+ double(*args).as_null_object
102
+ end
103
+
104
+ # @overload instance_spy(doubled_class)
105
+ # @param doubled_class [String, Class]
106
+ # @overload instance_spy(doubled_class, stubs)
107
+ # @param doubled_class [String, Class]
108
+ # @param stubs [Hash] hash of message/return-value pairs
109
+ # @return InstanceVerifyingDouble
110
+ #
111
+ # Constructs a test double that is optimized for use with `have_received`
112
+ # against a specific class. If the given class name has been loaded, only
113
+ # instance methods defined on the class are allowed to be stubbed. With
114
+ # a normal double one has to stub methods in order to be able to spy
115
+ # them. An instance_spy automatically spies on all instance methods to
116
+ # which the class responds.
117
+ def instance_spy(*args)
118
+ instance_double(*args).as_null_object
119
+ end
120
+
121
+ # @overload object_spy(object_or_name)
122
+ # @param object_or_name [String, Object]
123
+ # @overload object_spy(object_or_name, stubs)
124
+ # @param object_or_name [String, Object]
125
+ # @param stubs [Hash] hash of message/return-value pairs
126
+ # @return ObjectVerifyingDouble
127
+ #
128
+ # Constructs a test double that is optimized for use with `have_received`
129
+ # against a specific object. Only instance methods defined on the object
130
+ # are allowed to be stubbed. With a normal double one has to stub
131
+ # methods in order to be able to spy them. An object_spy automatically
132
+ # spies on all methods to which the object responds.
133
+ def object_spy(*args)
134
+ object_double(*args).as_null_object
135
+ end
136
+
137
+ # @overload class_spy(doubled_class)
138
+ # @param doubled_class [String, Module]
139
+ # @overload class_spy(doubled_class, stubs)
140
+ # @param doubled_class [String, Module]
141
+ # @param stubs [Hash] hash of message/return-value pairs
142
+ # @return ClassVerifyingDouble
143
+ #
144
+ # Constructs a test double that is optimized for use with `have_received`
145
+ # against a specific class. If the given class name has been loaded,
146
+ # only class methods defined on the class are allowed to be stubbed.
147
+ # With a normal double one has to stub methods in order to be able to spy
148
+ # them. An class_spy automatically spies on all class methods to which the
149
+ # class responds.
150
+ def class_spy(*args)
151
+ class_double(*args).as_null_object
152
+ end
153
+
87
154
  # Disables warning messages about expectations being set on nil.
88
155
  #
89
156
  # By default warning messages are issued when expectations are set on
@@ -130,7 +197,7 @@ module RSpec
130
197
  # stub_const("CardDeck", Class.new, :transfer_nested_constants => [:SUITS])
131
198
  # CardDeck::SUITS # => our suits array
132
199
  # CardDeck::NUM_CARDS # => uninitialized constant error
133
- def stub_const(constant_name, value, options = {})
200
+ def stub_const(constant_name, value, options={})
134
201
  ConstantMutator.stub(constant_name, value, options)
135
202
  end
136
203
 
@@ -151,8 +218,9 @@ module RSpec
151
218
  end
152
219
 
153
220
  # Verifies that the given object received the expected message during the
154
- # course of the test. The method must have previously been stubbed in
155
- # order for messages to be verified.
221
+ # course of the test. On a spy objects or as null object doubles this
222
+ # works for any method, on other objects the method must have
223
+ # been stubbed beforehand in order for messages to be verified.
156
224
  #
157
225
  # Stubbing and verifying messages received in this way implements the
158
226
  # Test Spy pattern.
@@ -256,7 +324,7 @@ module RSpec
256
324
  # use of `receive_message_chain` a code smell. Even though not all code smells
257
325
  # indicate real problems (think fluent interfaces), `receive_message_chain` still
258
326
  # results in brittle examples. For example, if you write
259
- # `foo.receive_message_chain(:bar, :baz => 37)` in a spec and then the
327
+ # `allow(foo).to receive_message_chain(:bar, :baz => 37)` in a spec and then the
260
328
  # implementation calls `foo.baz.bar`, the stub will not work.
261
329
  #
262
330
  # @example
@@ -288,9 +356,9 @@ module RSpec
288
356
  !ref.defined?
289
357
 
290
358
  raise VerifyingDoubleNotDefinedError,
291
- "#{ref.description} is not a defined constant. " +
292
- "Perhaps you misspelt it? " +
293
- "Disable check with verify_doubled_constant_names configuration option."
359
+ "#{ref.description} is not a defined constant. " \
360
+ "Perhaps you misspelt it? " \
361
+ "Disable check with verify_doubled_constant_names configuration option."
294
362
  end
295
363
 
296
364
  declare_double(type, ref, *args)
@@ -53,7 +53,7 @@ module RSpec
53
53
 
54
54
  # @private
55
55
  def stash
56
- return if !method_defined_directly_on_klass?
56
+ return unless method_defined_directly_on_klass?
57
57
  @original_method ||= ::RSpec::Support.method_handle_for(@object, @method)
58
58
  end
59
59
 
@@ -80,9 +80,9 @@ module RSpec
80
80
  yield
81
81
  rescue TypeError
82
82
  RSpec.warn_with(
83
- "RSpec failed to properly restore a partial double (#{@object.inspect}) " +
84
- "to its original state due to a known bug in MRI 2.0.0-p195 & p247 " +
85
- "(https://bugs.ruby-lang.org/issues/8686). This object may remain " +
83
+ "RSpec failed to properly restore a partial double (#{@object.inspect}) " \
84
+ "to its original state due to a known bug in MRI 2.0.0-p195 & p247 " \
85
+ "(https://bugs.ruby-lang.org/issues/8686). This object may remain " \
86
86
  "screwed up for the rest of this process. Please upgrade to 2.0.0-p353 or above.",
87
87
  :call_site => nil, :use_spec_location_as_call_site => true
88
88
  )
@@ -102,7 +102,7 @@ module RSpec
102
102
  end
103
103
 
104
104
  # @private
105
- def method_defined_on_klass?(klass = @klass)
105
+ def method_defined_on_klass?(klass=@klass)
106
106
  MethodReference.method_defined_at_any_visibility?(klass, @method)
107
107
  end
108
108
 
@@ -3,9 +3,9 @@ module RSpec
3
3
  module Matchers
4
4
  # @private
5
5
  class HaveReceived
6
- COUNT_CONSTRAINTS = %w(exactly at_least at_most times once twice)
7
- ARGS_CONSTRAINTS = %w(with)
8
- CONSTRAINTS = COUNT_CONSTRAINTS + ARGS_CONSTRAINTS + %w(ordered)
6
+ COUNT_CONSTRAINTS = %w[exactly at_least at_most times once twice thrice]
7
+ ARGS_CONSTRAINTS = %w[with]
8
+ CONSTRAINTS = COUNT_CONSTRAINTS + ARGS_CONSTRAINTS + %w[ordered]
9
9
 
10
10
  def initialize(method_name, &block)
11
11
  @method_name = method_name
@@ -22,6 +22,8 @@ module RSpec
22
22
  @block ||= block
23
23
  @subject = subject
24
24
  @expectation = expect
25
+ mock_proxy.ensure_implemented(@method_name)
26
+
25
27
  expected_messages_received_in_order?
26
28
  end
27
29
 
@@ -29,6 +31,7 @@ module RSpec
29
31
  @subject = subject
30
32
  ensure_count_unconstrained
31
33
  @expectation = expect.never
34
+ mock_proxy.ensure_implemented(@method_name)
32
35
  expected_messages_received_in_order?
33
36
  end
34
37
 
@@ -68,14 +71,13 @@ module RSpec
68
71
  end
69
72
 
70
73
  def ensure_count_unconstrained
71
- if count_constraint
72
- raise RSpec::Mocks::MockExpectationError,
73
- "can't use #{count_constraint} when negative"
74
- end
74
+ return unless count_constraint
75
+ raise RSpec::Mocks::MockExpectationError,
76
+ "can't use #{count_constraint} when negative"
75
77
  end
76
78
 
77
79
  def count_constraint
78
- @constraints.map(&:first).detect do |constraint|
80
+ @constraints.map(&:first).find do |constraint|
79
81
  COUNT_CONSTRAINTS.include?(constraint)
80
82
  end
81
83
  end
@@ -61,14 +61,14 @@ module RSpec
61
61
  private
62
62
 
63
63
  def warn_if_any_instance(expression, subject)
64
- if AnyInstance::Proxy === subject
65
- RSpec.warning(
66
- "`#{expression}(#{subject.klass}.any_instance).to` " <<
67
- "is probably not what you meant, it does not operate on " <<
68
- "any instance of `#{subject.klass}`. " <<
69
- "Use `#{expression}_any_instance_of(#{subject.klass}).to` instead."
70
- )
71
- end
64
+ return unless AnyInstance::Proxy === subject
65
+
66
+ RSpec.warning(
67
+ "`#{expression}(#{subject.klass}.any_instance).to` " \
68
+ "is probably not what you meant, it does not operate on " \
69
+ "any instance of `#{subject.klass}`. " \
70
+ "Use `#{expression}_any_instance_of(#{subject.klass}).to` instead."
71
+ )
72
72
  end
73
73
 
74
74
  def setup_mock_proxy_method_substitute(subject, method, block)
@@ -11,7 +11,7 @@ module RSpec
11
11
  @recorded_customizations = []
12
12
  end
13
13
 
14
- [:and_return, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
14
+ [:with, :and_return, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
15
15
  define_method(msg) do |*args, &block|
16
16
  @recorded_customizations << ExpectationCustomization.new(msg, args, block)
17
17
  self
@@ -44,11 +44,10 @@ module RSpec
44
44
  replay_customizations(chain)
45
45
  end
46
46
 
47
- def setup_negative_expectation(*args)
48
- raise NegationUnsupportedError.new(
49
- "`expect(...).not_to receive_message_chain` is not supported " +
50
- "since it doesn't really make sense. What would it even mean?"
51
- )
47
+ def setup_negative_expectation(*_args)
48
+ raise NegationUnsupportedError,
49
+ "`expect(...).not_to receive_message_chain` is not supported " \
50
+ "since it doesn't really make sense. What would it even mean?"
52
51
  end
53
52
 
54
53
  alias matches? setup_expectation
@@ -3,7 +3,6 @@ module RSpec
3
3
  module Matchers
4
4
  # @private
5
5
  class ReceiveMessages
6
-
7
6
  def initialize(message_return_value_hash)
8
7
  @message_return_value_hash = message_return_value_hash
9
8
  @backtrace_line = CallerFilter.first_non_rspec_line
@@ -15,29 +14,29 @@ module RSpec
15
14
 
16
15
  def setup_expectation(subject)
17
16
  warn_about_block if block_given?
18
- each_message_on( proxy_on(subject) ) do |host, message, return_value|
17
+ each_message_on(proxy_on(subject)) do |host, message, return_value|
19
18
  host.add_simple_expectation(message, return_value, @backtrace_line)
20
19
  end
21
20
  end
22
21
  alias matches? setup_expectation
23
22
 
24
- def setup_negative_expectation(subject)
23
+ def setup_negative_expectation(_subject)
25
24
  raise NegationUnsupportedError,
26
- "`expect(...).to_not receive_messages` is not supported since it " +
27
- "doesn't really make sense. What would it even mean?"
25
+ "`expect(...).to_not receive_messages` is not supported since it " \
26
+ "doesn't really make sense. What would it even mean?"
28
27
  end
29
28
  alias does_not_match? setup_negative_expectation
30
29
 
31
30
  def setup_allowance(subject)
32
31
  warn_about_block if block_given?
33
- each_message_on( proxy_on(subject) ) do |host, message, return_value|
32
+ each_message_on(proxy_on(subject)) do |host, message, return_value|
34
33
  host.add_simple_stub(message, return_value)
35
34
  end
36
35
  end
37
36
 
38
37
  def setup_any_instance_expectation(subject)
39
38
  warn_about_block if block_given?
40
- each_message_on( any_instance_of(subject) ) do |host, message, return_value|
39
+ each_message_on(any_instance_of(subject)) do |host, message, return_value|
41
40
  host.should_receive(message).and_return(return_value)
42
41
  end
43
42
  end
@@ -12,10 +12,10 @@ module RSpec
12
12
  # @api private
13
13
  def setup_chain
14
14
  if chain.length > 1
15
- if matching_stub = find_matching_stub
15
+ if (matching_stub = find_matching_stub)
16
16
  chain.shift
17
17
  chain_on(matching_stub.invoke(nil), *chain, &@block)
18
- elsif matching_expectation = find_matching_expectation
18
+ elsif (matching_expectation = find_matching_expectation)
19
19
  chain.shift
20
20
  chain_on(matching_expectation.invoke_without_incrementing_received_count(nil), *chain, &@block)
21
21
  else
@@ -30,8 +30,8 @@ module RSpec
30
30
 
31
31
  private
32
32
 
33
- def expectation(object, message, &return_block)
34
- raise NotImplementedError.new
33
+ def expectation(_object, _message, &_return_block)
34
+ raise NotImplementedError
35
35
  end
36
36
 
37
37
  def chain_on(object, *chain, &block)
@@ -42,7 +42,7 @@ module RSpec
42
42
  def format_chain(*chain, &blk)
43
43
  if Hash === chain.last
44
44
  hash = chain.pop
45
- hash.each do |k,v|
45
+ hash.each do |k, v|
46
46
  chain << k
47
47
  blk = Proc.new { v }
48
48
  end