rspec-mocks 3.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +26 -0
  5. data/README.md +29 -15
  6. data/lib/rspec/mocks/any_instance/chain.rb +2 -2
  7. data/lib/rspec/mocks/any_instance/expectation_chain.rb +2 -3
  8. data/lib/rspec/mocks/any_instance/message_chains.rb +8 -7
  9. data/lib/rspec/mocks/any_instance/proxy.rb +2 -2
  10. data/lib/rspec/mocks/any_instance/recorder.rb +27 -25
  11. data/lib/rspec/mocks/any_instance/stub_chain.rb +3 -5
  12. data/lib/rspec/mocks/argument_list_matcher.rb +4 -4
  13. data/lib/rspec/mocks/argument_matchers.rb +23 -5
  14. data/lib/rspec/mocks/configuration.rb +3 -10
  15. data/lib/rspec/mocks/error_generator.rb +33 -27
  16. data/lib/rspec/mocks/example_methods.rb +74 -6
  17. data/lib/rspec/mocks/instance_method_stasher.rb +5 -5
  18. data/lib/rspec/mocks/matchers/have_received.rb +7 -8
  19. data/lib/rspec/mocks/matchers/receive.rb +8 -8
  20. data/lib/rspec/mocks/matchers/receive_message_chain.rb +4 -5
  21. data/lib/rspec/mocks/matchers/receive_messages.rb +6 -7
  22. data/lib/rspec/mocks/message_chain.rb +5 -5
  23. data/lib/rspec/mocks/message_expectation.rb +56 -28
  24. data/lib/rspec/mocks/method_double.rb +15 -12
  25. data/lib/rspec/mocks/method_reference.rb +8 -7
  26. data/lib/rspec/mocks/mutate_const.rb +26 -100
  27. data/lib/rspec/mocks/object_reference.rb +12 -13
  28. data/lib/rspec/mocks/order_group.rb +4 -5
  29. data/lib/rspec/mocks/proxy.rb +31 -25
  30. data/lib/rspec/mocks/space.rb +24 -24
  31. data/lib/rspec/mocks/syntax.rb +8 -8
  32. data/lib/rspec/mocks/targets.rb +6 -6
  33. data/lib/rspec/mocks/test_double.rb +3 -3
  34. data/lib/rspec/mocks/verifying_double.rb +10 -12
  35. data/lib/rspec/mocks/verifying_message_expecation.rb +15 -13
  36. data/lib/rspec/mocks/verifying_proxy.rb +11 -15
  37. data/lib/rspec/mocks/version.rb +1 -1
  38. metadata +5 -5
  39. metadata.gz.sig +0 -0
@@ -59,7 +59,7 @@ module RSpec
59
59
  define_method(method_name) do |*args, &block|
60
60
  method_double.proxy_method_invoked(self, *args, &block)
61
61
  end
62
- self.__send__ visibility, method_name
62
+ __send__(visibility, method_name)
63
63
  end
64
64
 
65
65
  @method_is_proxied = true
@@ -69,7 +69,7 @@ module RSpec
69
69
  # method to perform additional operations.
70
70
  #
71
71
  # @private
72
- def proxy_method_invoked(obj, *args, &block)
72
+ def proxy_method_invoked(_obj, *args, &block)
73
73
  @proxy.message_received method_name, *args, &block
74
74
  end
75
75
 
@@ -80,9 +80,7 @@ module RSpec
80
80
 
81
81
  definition_target.__send__(:remove_method, @method_name)
82
82
 
83
- if @method_stasher.method_is_stashed?
84
- @method_stasher.restore
85
- end
83
+ @method_stasher.restore if @method_stasher.method_is_stashed?
86
84
  restore_original_visibility
87
85
 
88
86
  @method_is_proxied = false
@@ -91,7 +89,9 @@ module RSpec
91
89
  # @private
92
90
  def show_frozen_warning
93
91
  RSpec.warn_with(
94
- "WARNING: rspec-mocks was unable to restore the original `#{@method_name}` method on #{@object.inspect} because it has been frozen. If you reuse this object, `#{@method_name}` will continue to respond with its stub implementation.",
92
+ "WARNING: rspec-mocks was unable to restore the original `#{@method_name}` " \
93
+ "method on #{@object.inspect} because it has been frozen. If you reuse this " \
94
+ "object, `#{@method_name}` will continue to respond with its stub implementation.",
95
95
  :call_site => nil,
96
96
  :use_spec_location_as_call_site => true
97
97
  )
@@ -107,7 +107,7 @@ module RSpec
107
107
 
108
108
  # @private
109
109
  def verify
110
- expectations.each {|e| e.verify_messages_received}
110
+ expectations.each { |e| e.verify_messages_received }
111
111
  end
112
112
 
113
113
  # @private
@@ -134,7 +134,7 @@ module RSpec
134
134
  def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
135
135
  configure_method
136
136
  expectation = message_expectation_class.new(error_generator, expectation_ordering,
137
- expected_from, self, :expectation, opts, &implementation)
137
+ expected_from, self, :expectation, opts, &implementation)
138
138
  expectations << expectation
139
139
  expectation
140
140
  end
@@ -149,7 +149,7 @@ module RSpec
149
149
  def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
150
150
  configure_method
151
151
  stub = message_expectation_class.new(error_generator, expectation_ordering, expected_from,
152
- self, :stub, opts, &implementation)
152
+ self, :stub, opts, &implementation)
153
153
  stubs.unshift stub
154
154
  stub
155
155
  end
@@ -172,7 +172,7 @@ module RSpec
172
172
  end
173
173
 
174
174
  # @private
175
- def setup_simple_method_double(method_name, response, collection, error_generator = nil, backtrace_line = nil)
175
+ def setup_simple_method_double(method_name, response, collection, error_generator=nil, backtrace_line=nil)
176
176
  define_proxy_method
177
177
 
178
178
  me = SimpleMessageExpectation.new(method_name, response, error_generator, backtrace_line)
@@ -202,8 +202,6 @@ module RSpec
202
202
  raise MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
203
203
  end
204
204
 
205
- private
206
-
207
205
  # In Ruby 2.0.0 and above prepend will alter the method lookup chain.
208
206
  # We use an object's singleton class to define method doubles upon,
209
207
  # however if the object has had it's singleton class (as opposed to
@@ -216,6 +214,9 @@ module RSpec
216
214
  # of our own.
217
215
  #
218
216
  if Support::RubyFeatures.module_prepends_supported?
217
+
218
+ private
219
+
219
220
  # We subclass `Module` in order to be able to easily detect our prepended module.
220
221
  RSpecPrependedModule = Class.new(Module)
221
222
 
@@ -247,6 +248,8 @@ module RSpec
247
248
 
248
249
  else
249
250
 
251
+ private
252
+
250
253
  def definition_target
251
254
  object_singleton_class
252
255
  end
@@ -27,7 +27,7 @@ module RSpec
27
27
  # cases when we don't know if a method is implemented and
28
28
  # both `implemented?` and `unimplemented?` will return false.
29
29
  def unimplemented?
30
- @object_reference.when_loaded do |m|
30
+ @object_reference.when_loaded do |_m|
31
31
  return !implemented?
32
32
  end
33
33
 
@@ -44,9 +44,8 @@ module RSpec
44
44
  end
45
45
 
46
46
  def with_signature
47
- if original = original_method
48
- yield Support::MethodSignature.new(original)
49
- end
47
+ return unless (original = original_method)
48
+ yield Support::MethodSignature.new(original)
50
49
  end
51
50
 
52
51
  def visibility
@@ -59,7 +58,7 @@ module RSpec
59
58
  :public
60
59
  end
61
60
 
62
- private
61
+ private
63
62
 
64
63
  def original_method
65
64
  @object_reference.when_loaded do |m|
@@ -98,7 +97,8 @@ module RSpec
98
97
 
99
98
  # @private
100
99
  class InstanceMethodReference < MethodReference
101
- private
100
+ private
101
+
102
102
  def method_implemented?(mod)
103
103
  MethodReference.method_defined_at_any_visibility?(mod, @method_name)
104
104
  end
@@ -133,7 +133,8 @@ module RSpec
133
133
 
134
134
  # @private
135
135
  class ObjectMethodReference < MethodReference
136
- private
136
+ private
137
+
137
138
  def method_implemented?(object)
138
139
  object.respond_to?(@method_name, true)
139
140
  end
@@ -1,85 +1,11 @@
1
+ RSpec::Support.require_rspec_support 'recursive_const_methods'
2
+
1
3
  module RSpec
2
4
  module Mocks
3
- # Provides recursive constant lookup methods useful for
4
- # constant stubbing.
5
- #
6
- # @private
7
- module RecursiveConstMethods
8
- # We only want to consider constants that are defined directly on a
9
- # particular module, and not include top-level/inherited constants.
10
- # Unfortunately, the constant API changed between 1.8 and 1.9, so
11
- # we need to conditionally define methods to ignore the top-level/inherited
12
- # constants.
13
- #
14
- # Given:
15
- # class A; B = 1; end
16
- # class C < A; end
17
- #
18
- # On 1.8:
19
- # - C.const_get("Hash") # => ::Hash
20
- # - C.const_defined?("Hash") # => false
21
- # - C.constants # => ["B"]
22
- # - None of these methods accept the extra `inherit` argument
23
- # On 1.9:
24
- # - C.const_get("Hash") # => ::Hash
25
- # - C.const_defined?("Hash") # => true
26
- # - C.const_get("Hash", false) # => raises NameError
27
- # - C.const_defined?("Hash", false) # => false
28
- # - C.constants # => [:B]
29
- # - C.constants(false) #=> []
30
- if Module.method(:const_defined?).arity == 1
31
- def const_defined_on?(mod, const_name)
32
- mod.const_defined?(const_name)
33
- end
34
-
35
- def get_const_defined_on(mod, const_name)
36
- if const_defined_on?(mod, const_name)
37
- return mod.const_get(const_name)
38
- end
39
-
40
- raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
41
- end
42
-
43
- def constants_defined_on(mod)
44
- mod.constants.select { |c| const_defined_on?(mod, c) }
45
- end
46
- else
47
- def const_defined_on?(mod, const_name)
48
- mod.const_defined?(const_name, false)
49
- end
50
-
51
- def get_const_defined_on(mod, const_name)
52
- mod.const_get(const_name, false)
53
- end
54
-
55
- def constants_defined_on(mod)
56
- mod.constants(false)
57
- end
58
- end
59
-
60
- def recursive_const_get(const_name)
61
- normalize_const_name(const_name).split('::').inject(Object) do |mod, name|
62
- get_const_defined_on(mod, name)
63
- end
64
- end
65
-
66
- def recursive_const_defined?(const_name)
67
- normalize_const_name(const_name).split('::').inject([Object, '']) do |(mod, full_name), name|
68
- yield(full_name, name) if block_given? && !(Module === mod)
69
- return false unless const_defined_on?(mod, name)
70
- [get_const_defined_on(mod, name), [mod, name].join('::')]
71
- end
72
- end
73
-
74
- def normalize_const_name(const_name)
75
- const_name.sub(/\A::/, '')
76
- end
77
- end
78
-
79
5
  # Provides information about constants that may (or may not)
80
6
  # have been mutated by rspec-mocks.
81
7
  class Constant
82
- extend RecursiveConstMethods
8
+ extend Support::RecursiveConstMethods
83
9
 
84
10
  # @api private
85
11
  def initialize(name)
@@ -154,7 +80,7 @@ module RSpec
154
80
 
155
81
  # Provides a means to stub constants.
156
82
  class ConstantMutator
157
- extend RecursiveConstMethods
83
+ extend Support::RecursiveConstMethods
158
84
 
159
85
  # Stubs a constant.
160
86
  #
@@ -167,12 +93,12 @@ module RSpec
167
93
  # examples. This is an alternate public API that is provided
168
94
  # so you can stub constants in other contexts (e.g. helper
169
95
  # classes).
170
- def self.stub(constant_name, value, options = {})
96
+ def self.stub(constant_name, value, options={})
171
97
  mutator = if recursive_const_defined?(constant_name, &raise_on_invalid_const)
172
- DefinedConstantReplacer
173
- else
174
- UndefinedConstantSetter
175
- end
98
+ DefinedConstantReplacer
99
+ else
100
+ UndefinedConstantSetter
101
+ end
176
102
 
177
103
  mutate(mutator.new(constant_name, value, options[:transfer_nested_constants]))
178
104
  value
@@ -188,7 +114,7 @@ module RSpec
188
114
  # so you can hide constants in other contexts (e.g. helper
189
115
  # classes).
190
116
  def self.hide(constant_name)
191
- mutate(ConstantHider.new(constant_name, nil, { }))
117
+ mutate(ConstantHider.new(constant_name, nil, {}))
192
118
  nil
193
119
  end
194
120
 
@@ -196,7 +122,7 @@ module RSpec
196
122
  #
197
123
  # @private
198
124
  class BaseMutator
199
- include RecursiveConstMethods
125
+ include Support::RecursiveConstMethods
200
126
 
201
127
  attr_reader :original_value, :full_constant_name
202
128
 
@@ -227,7 +153,7 @@ module RSpec
227
153
  # @private
228
154
  class ConstantHider < BaseMutator
229
155
  def mutate
230
- return unless @defined = recursive_const_defined?(full_constant_name)
156
+ return unless (@defined = recursive_const_defined?(full_constant_name))
231
157
  @context = recursive_const_get(@context_parts.join('::'))
232
158
  @original_value = get_const_defined_on(@context, @const_name)
233
159
 
@@ -298,12 +224,12 @@ module RSpec
298
224
  return [] unless should_transfer_nested_constants?
299
225
 
300
226
  { @original_value => "the original value", @mutated_value => "the stubbed value" }.each do |value, description|
301
- unless value.respond_to?(:constants)
302
- raise ArgumentError,
303
- "Cannot transfer nested constants for #{@full_constant_name} " +
304
- "since #{description} is not a class or module and only classes " +
305
- "and modules support nested constants."
306
- end
227
+ next if value.respond_to?(:constants)
228
+
229
+ raise ArgumentError,
230
+ "Cannot transfer nested constants for #{@full_constant_name} " \
231
+ "since #{description} is not a class or module and only classes " \
232
+ "and modules support nested constants."
307
233
  end
308
234
 
309
235
  if Array === @transfer_nested_constants
@@ -313,9 +239,9 @@ module RSpec
313
239
  if undefined_constants.any?
314
240
  available_constants = constants_defined_on(@original_value) - @transfer_nested_constants
315
241
  raise ArgumentError,
316
- "Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " +
317
- "for #{@full_constant_name} since they are not defined. Did you mean " +
318
- "#{available_constants.join(' or ')}?"
242
+ "Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " \
243
+ "for #{@full_constant_name} since they are not defined. Did you mean " \
244
+ "#{available_constants.join(' or ')}?"
319
245
  end
320
246
 
321
247
  @transfer_nested_constants
@@ -363,10 +289,10 @@ module RSpec
363
289
 
364
290
  def name_for(parent, name)
365
291
  root = if parent == Object
366
- ''
367
- else
368
- parent.name
369
- end
292
+ ''
293
+ else
294
+ parent.name
295
+ end
370
296
  root + '::' + name
371
297
  end
372
298
  end
@@ -389,7 +315,7 @@ module RSpec
389
315
  # @api private
390
316
  def self.raise_on_invalid_const
391
317
  lambda do |const_name, failed_name|
392
- raise "Cannot stub constant #{failed_name} on #{const_name} " +
318
+ raise "Cannot stub constant #{failed_name} on #{const_name} " \
393
319
  "since #{const_name} is not a module."
394
320
  end
395
321
  end
@@ -1,21 +1,20 @@
1
1
  module RSpec
2
2
  module Mocks
3
-
4
3
  # @private
5
4
  class ObjectReference
6
5
  # Returns an appropriate Object or Module reference based
7
6
  # on the given argument.
8
- def self.for(object_module_or_name, allow_direct_object_refs = false)
7
+ def self.for(object_module_or_name, allow_direct_object_refs=false)
9
8
  case object_module_or_name
10
- when Module then DirectModuleReference.new(object_module_or_name)
11
- when String then NamedObjectReference.new(object_module_or_name)
9
+ when Module then DirectModuleReference.new(object_module_or_name)
10
+ when String then NamedObjectReference.new(object_module_or_name)
11
+ else
12
+ if allow_direct_object_refs
13
+ DirectObjectReference.new(object_module_or_name)
12
14
  else
13
- if allow_direct_object_refs
14
- DirectObjectReference.new(object_module_or_name)
15
- else
16
- raise ArgumentError,
17
- "Module or String expected, got #{object_module_or_name.inspect}"
18
- end
15
+ raise ArgumentError,
16
+ "Module or String expected, got #{object_module_or_name.inspect}"
17
+ end
19
18
  end
20
19
  end
21
20
  end
@@ -35,7 +34,7 @@ module RSpec
35
34
 
36
35
  def const_to_replace
37
36
  raise ArgumentError,
38
- "Can not perform constant replacement with an object."
37
+ "Can not perform constant replacement with an object."
39
38
  end
40
39
 
41
40
  def defined?
@@ -78,11 +77,11 @@ module RSpec
78
77
  end
79
78
  alias description const_to_replace
80
79
 
81
- def when_loaded(&block)
80
+ def when_loaded(&_block)
82
81
  yield object if object
83
82
  end
84
83
 
85
- private
84
+ private
86
85
 
87
86
  def object
88
87
  @object ||= Constant.original(@const_name).original_value
@@ -25,10 +25,10 @@ module RSpec
25
25
  # @private
26
26
  def consume
27
27
  remaining_expectations.each_with_index do |expectation, index|
28
- if expectation.ordered?
29
- @index += index + 1
30
- return expectation
31
- end
28
+ next unless expectation.ordered?
29
+
30
+ @index += index + 1
31
+ return expectation
32
32
  end
33
33
  nil
34
34
  end
@@ -76,7 +76,6 @@ module RSpec
76
76
  def expectation_for(message)
77
77
  @expectations.find { |e| message == e }
78
78
  end
79
-
80
79
  end
81
80
  end
82
81
  end
@@ -9,7 +9,7 @@ module RSpec
9
9
  end
10
10
 
11
11
  # @private
12
- def ensure_implemented(*args)
12
+ def ensure_implemented(*_args)
13
13
  # noop for basic proxies, see VerifyingProxy for behaviour.
14
14
  end
15
15
 
@@ -42,7 +42,7 @@ module RSpec
42
42
  end
43
43
 
44
44
  # @private
45
- def original_method_handle_for(message)
45
+ def original_method_handle_for(_message)
46
46
  nil
47
47
  end
48
48
 
@@ -89,20 +89,19 @@ module RSpec
89
89
  end
90
90
 
91
91
  @messages_received.each do |(actual_method_name, args, _)|
92
- if expectation.matches?(actual_method_name, *args)
93
- expectation.invoke(nil)
94
- block.call(*args) if block
95
- end
96
- end
92
+ next unless expectation.matches?(actual_method_name, *args)
97
93
 
94
+ expectation.invoke(nil)
95
+ block.call(*args) if block
96
+ end
98
97
  end
99
98
 
100
99
  # @private
101
100
  def check_for_unexpected_arguments(expectation)
102
101
  @messages_received.each do |(method_name, args, _)|
103
- if expectation.matches_name_but_not_args(method_name, *args)
104
- raise_unexpected_message_args_error(expectation, *args)
105
- end
102
+ next unless expectation.matches_name_but_not_args(method_name, *args)
103
+
104
+ raise_unexpected_message_args_error(expectation, *args)
106
105
  end
107
106
  end
108
107
 
@@ -129,7 +128,7 @@ module RSpec
129
128
 
130
129
  # @private
131
130
  def verify
132
- @method_doubles.each_value {|d| d.verify}
131
+ @method_doubles.each_value { |d| d.verify }
133
132
  end
134
133
 
135
134
  # @private
@@ -139,12 +138,12 @@ module RSpec
139
138
 
140
139
  # @private
141
140
  def received_message?(method_name, *args, &block)
142
- @messages_received.any? {|array| array == [method_name, args, block]}
141
+ @messages_received.any? { |array| array == [method_name, args, block] }
143
142
  end
144
143
 
145
144
  # @private
146
145
  def has_negative_expectation?(message)
147
- method_double_for(message).expectations.detect {|expectation| expectation.negative_expectation_for?(message)}
146
+ method_double_for(message).expectations.find { |expectation| expectation.negative_expectation_for?(message) }
148
147
  end
149
148
 
150
149
  # @private
@@ -162,16 +161,19 @@ module RSpec
162
161
 
163
162
  if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
164
163
  expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
165
- if expectation = find_almost_matching_expectation(message, *args)
164
+ if (expectation = find_almost_matching_expectation(message, *args))
166
165
  expectation.advise(*args) unless expectation.expected_messages_received?
167
166
  end
168
167
  stub.invoke(nil, *args, &block)
169
168
  elsif expectation
170
169
  expectation.invoke(stub, *args, &block)
171
- elsif expectation = find_almost_matching_expectation(message, *args)
170
+ elsif (expectation = find_almost_matching_expectation(message, *args))
172
171
  expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
173
- raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(message) or null_object?)
174
- elsif stub = find_almost_matching_stub(message, *args)
172
+
173
+ if null_object? || !has_negative_expectation?(message)
174
+ raise_unexpected_message_args_error(expectation, *args)
175
+ end
176
+ elsif (stub = find_almost_matching_stub(message, *args))
175
177
  stub.advise(*args)
176
178
  raise_missing_default_stub_error(stub, *args)
177
179
  elsif Class === @object
@@ -197,7 +199,7 @@ module RSpec
197
199
  end
198
200
 
199
201
  # @private
200
- def visibility_for(method_name)
202
+ def visibility_for(_method_name)
201
203
  # This is the default (for test doubles). Subclasses override this.
202
204
  :public
203
205
  end
@@ -206,9 +208,13 @@ module RSpec
206
208
  def prepended_modules_of_singleton_class
207
209
  @prepended_modules_of_singleton_class ||= begin
208
210
  singleton_class = @object.singleton_class
209
- singleton_class.ancestors.take_while do |mod|
210
- !(Class === mod || @object.equal?(mod))
211
- end
211
+ ancestors = singleton_class.ancestors
212
+
213
+ # `|| 0` is necessary for Ruby 2.0, where the singleton class
214
+ # is only in the ancestor list when there are prepended modules.
215
+ singleton_index = ancestors.index(singleton_class) || 0
216
+
217
+ ancestors[0, singleton_index]
212
218
  end
213
219
  end
214
220
  end
@@ -244,11 +250,11 @@ module RSpec
244
250
  end
245
251
 
246
252
  def find_matching_method_stub(method_name, *args)
247
- method_double_for(method_name).stubs.find {|stub| stub.matches?(method_name, *args)}
253
+ method_double_for(method_name).stubs.find { |stub| stub.matches?(method_name, *args) }
248
254
  end
249
255
 
250
256
  def find_almost_matching_stub(method_name, *args)
251
- method_double_for(method_name).stubs.find {|stub| stub.matches_name_but_not_args(method_name, *args)}
257
+ method_double_for(method_name).stubs.find { |stub| stub.matches_name_but_not_args(method_name, *args) }
252
258
  end
253
259
  end
254
260
 
@@ -295,7 +301,7 @@ module RSpec
295
301
  end
296
302
 
297
303
  def reset
298
- @method_doubles.each_value {|d| d.reset}
304
+ @method_doubles.each_value { |d| d.reset }
299
305
  super
300
306
  end
301
307
 
@@ -415,7 +421,7 @@ module RSpec
415
421
 
416
422
  private
417
423
 
418
- def warn method_name
424
+ def warn(method_name)
419
425
  source = CallerFilter.first_non_rspec_line
420
426
  Kernel.warn("An expectation of :#{method_name} was set on nil. Called from #{source}. Use allow_message_expectations_on_nil to disable warnings.")
421
427
  end