rspec-mocks 3.2.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +47 -0
- data/README.md +2 -2
- data/lib/rspec/mocks/any_instance.rb +1 -0
- data/lib/rspec/mocks/any_instance/chain.rb +1 -1
- data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +1 -3
- data/lib/rspec/mocks/any_instance/recorder.rb +7 -10
- data/lib/rspec/mocks/argument_list_matcher.rb +3 -3
- data/lib/rspec/mocks/configuration.rb +6 -5
- data/lib/rspec/mocks/error_generator.rb +163 -111
- data/lib/rspec/mocks/example_methods.rb +2 -5
- data/lib/rspec/mocks/matchers/have_received.rb +6 -9
- data/lib/rspec/mocks/message_chain.rb +0 -4
- data/lib/rspec/mocks/message_expectation.rb +56 -53
- data/lib/rspec/mocks/method_double.rb +13 -9
- data/lib/rspec/mocks/method_reference.rb +37 -0
- data/lib/rspec/mocks/proxy.rb +26 -18
- data/lib/rspec/mocks/test_double.rb +40 -5
- data/lib/rspec/mocks/verifying_double.rb +11 -16
- data/lib/rspec/mocks/verifying_proxy.rb +31 -7
- data/lib/rspec/mocks/version.rb +1 -1
- metadata +8 -7
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bb4586d03e4b2bf84d904af032165dfae270599
|
4
|
+
data.tar.gz: 6889f7727cf4545a05618a19c0f7ff35174718ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bb9e03448dfde3e78aec7388dd7b49bccb8005ec49a7ab525b41818a6678e41568fa7946a4d443a8103058d77c4ae2760ac07eb69b0ef37dd39f197e580aa48
|
7
|
+
data.tar.gz: 00a6e20fb91ccb3dd7212ac5877e9b348609aede07ed8158aee6032f1e30d7d89a833a7d1107343e780da15daa0800d94985cdd151796434f5413c8663935fa0
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Changelog.md
CHANGED
@@ -1,3 +1,50 @@
|
|
1
|
+
### 3.3.0 / 2015-06-12
|
2
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.2.1...v3.3.0)
|
3
|
+
|
4
|
+
Enhancements:
|
5
|
+
|
6
|
+
* When stubbing `new` on `MyClass` or `class_double(MyClass)`, use the
|
7
|
+
method signature from `MyClass#initialize` to verify arguments.
|
8
|
+
(Myron Marston, #886)
|
9
|
+
* Use matcher descriptions when generating description of received arguments
|
10
|
+
for mock expectation failures. (Tim Wade, #891)
|
11
|
+
* Avoid loading `stringio` unnecessarily. (Myron Marston, #894)
|
12
|
+
* Verifying doubles failure messages now distinguish between class and instance
|
13
|
+
level methods. (Tim Wade, #896, #908)
|
14
|
+
* Improve mock expectation failure messages so that it combines both
|
15
|
+
number of times and the received arguments in the output. (John Ceh, #918)
|
16
|
+
* Improve how test doubles are represented in failure messages.
|
17
|
+
(Siva Gollapalli, Myron Marston, #932)
|
18
|
+
* Rename `RSpec::Mocks::Configuration#when_declaring_verifying_double` to
|
19
|
+
`RSpec::Mocks::Configuration#before_verifying_doubles` and utilise when
|
20
|
+
verifying partial doubles. (Jon Rowe, #940)
|
21
|
+
* Use rspec-support's `ObjectFormatter` for improved formatting of
|
22
|
+
arguments in failure messages so that, for example, full time
|
23
|
+
precisions is displayed for time objects. (Gavin Miller, Myron Marston, #955)
|
24
|
+
|
25
|
+
Bug Fixes:
|
26
|
+
|
27
|
+
* Ensure expectations that raise eagerly also raise during RSpec verification.
|
28
|
+
This means that if exceptions are caught inside test execution the test will
|
29
|
+
still fail. (Sam Phippen, #884)
|
30
|
+
* Fix `have_received(msg).with(args).exactly(n).times` and
|
31
|
+
`receive(msg).with(args).exactly(n).times` failure messages
|
32
|
+
for when the message was received the wrong number of times with
|
33
|
+
the specified args, and also received additional times with other
|
34
|
+
arguments. Previously it confusingly listed the arguments as being
|
35
|
+
mis-matched (even when the double was allowed to receive with any
|
36
|
+
args) rather than listing the count. (John Ceh, #918)
|
37
|
+
* Fix `any_args`/`anything` support so that we avoid calling `obj == anything`
|
38
|
+
on user objects that may have improperly implemented `==` in a way that
|
39
|
+
raises errors. (Myron Marston, #924)
|
40
|
+
* Fix edge case involving stubbing the same method on a class and a subclass
|
41
|
+
which previously hit a `NoMethodError` internally in RSpec. (Myron Marston #954)
|
42
|
+
* Fix edge case where the message received count would be incremented multiple
|
43
|
+
times for one failure. (Myron Marston, #957)
|
44
|
+
* Fix failure messages for when spies received the expected message with
|
45
|
+
different arguments and also received another message. (Maurício Linhares, #960)
|
46
|
+
* Silence whitespace-only diffs. (Myron Marston, #969)
|
47
|
+
|
1
48
|
### 3.2.1 / 2015-02-23
|
2
49
|
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.2.0...v3.2.1)
|
3
50
|
|
data/README.md
CHANGED
@@ -417,8 +417,8 @@ There are many different viewpoints about the meaning of mocks and stubs. If
|
|
417
417
|
you are interested in learning more, here is some recommended reading:
|
418
418
|
|
419
419
|
* Mock Objects: http://www.mockobjects.com/
|
420
|
-
* Endo-Testing: http://
|
421
|
-
* Mock Roles, Not Objects: http://jmock.org/oopsla2004.pdf
|
420
|
+
* Endo-Testing: http://www.ccs.neu.edu/research/demeter/related-work/extreme-programming/MockObjectsFinal.PDF
|
421
|
+
* Mock Roles, Not Objects: http://www.jmock.org/oopsla2004.pdf
|
422
422
|
* Test Double: http://www.martinfowler.com/bliki/TestDouble.html
|
423
423
|
* Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
|
424
424
|
* Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
module AnyInstance
|
4
|
+
# @private
|
5
|
+
class ErrorGenerator < ::RSpec::Mocks::ErrorGenerator
|
6
|
+
def raise_second_instance_received_message_error(unfulfilled_expectations)
|
7
|
+
__raise "Exactly one instance should have received the following " \
|
8
|
+
"message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def raise_does_not_implement_error(klass, method_name)
|
12
|
+
__raise "#{klass} does not implement ##{method_name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def raise_message_already_received_by_other_instance_error(method_name, object_inspect, invoked_instance)
|
16
|
+
__raise "The message '#{method_name}' was received by #{object_inspect} " \
|
17
|
+
"but has already been received by #{invoked_instance}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def raise_not_supported_with_prepend_error(method_name, problem_mod)
|
21
|
+
__raise "Using `any_instance` to stub a method (#{method_name}) that has been " \
|
22
|
+
"defined on a prepended module (#{problem_mod}) is not supported."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.error_generator
|
27
|
+
@error_generator ||= ErrorGenerator.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -75,9 +75,7 @@ module RSpec
|
|
75
75
|
return unless ExpectationChain === instance
|
76
76
|
return if @instance_with_expectation.equal?(instance)
|
77
77
|
|
78
|
-
|
79
|
-
"Exactly one instance should have received the following " \
|
80
|
-
"message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
|
78
|
+
AnyInstance.error_generator.raise_second_instance_received_message_error(unfulfilled_expectations)
|
81
79
|
end
|
82
80
|
end
|
83
81
|
end
|
@@ -76,7 +76,7 @@ module RSpec
|
|
76
76
|
# @see Methods#unstub
|
77
77
|
def unstub(method_name)
|
78
78
|
unless @observed_methods.include?(method_name.to_sym)
|
79
|
-
|
79
|
+
AnyInstance.error_generator.raise_method_not_stubbed_error(method_name)
|
80
80
|
end
|
81
81
|
message_chains.remove_stub_chains_for!(method_name)
|
82
82
|
stubs[method_name].clear
|
@@ -91,9 +91,7 @@ module RSpec
|
|
91
91
|
return unless @expectation_set
|
92
92
|
return if message_chains.all_expectations_fulfilled?
|
93
93
|
|
94
|
-
|
95
|
-
"Exactly one instance should have received the following " \
|
96
|
-
"message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}"
|
94
|
+
AnyInstance.error_generator.raise_second_instance_received_message_error(message_chains.unfulfilled_expectations)
|
97
95
|
end
|
98
96
|
|
99
97
|
# @private
|
@@ -221,8 +219,7 @@ module RSpec
|
|
221
219
|
|
222
220
|
if RSpec::Mocks.configuration.verify_partial_doubles?
|
223
221
|
unless public_protected_or_private_method_defined?(method_name)
|
224
|
-
|
225
|
-
"#{@klass} does not implement ##{method_name}"
|
222
|
+
AnyInstance.error_generator.raise_does_not_implement_error(@klass, method_name)
|
226
223
|
end
|
227
224
|
end
|
228
225
|
|
@@ -242,7 +239,9 @@ module RSpec
|
|
242
239
|
@klass.__send__(:define_method, method_name) do |*_args, &_blk|
|
243
240
|
invoked_instance = recorder.instance_that_received(method_name)
|
244
241
|
inspect = "#<#{self.class}:#{object_id} #{instance_variables.map { |name| "#{name}=#{instance_variable_get name}" }.join(', ')}>"
|
245
|
-
|
242
|
+
AnyInstance.error_generator.raise_message_already_received_by_other_instance_error(
|
243
|
+
method_name, inspect, invoked_instance
|
244
|
+
)
|
246
245
|
end
|
247
246
|
end
|
248
247
|
|
@@ -252,9 +251,7 @@ module RSpec
|
|
252
251
|
problem_mod = prepended_modules.find { |mod| mod.method_defined?(method_name) }
|
253
252
|
return unless problem_mod
|
254
253
|
|
255
|
-
|
256
|
-
"Using `any_instance` to stub a method (#{method_name}) that has been " \
|
257
|
-
"defined on a prepended module (#{problem_mod}) is not supported."
|
254
|
+
AnyInstance.error_generator.raise_not_supported_with_prepend_error(method_name, problem_mod)
|
258
255
|
end
|
259
256
|
else
|
260
257
|
def allow_no_prepended_module_definition_of(_method_name)
|
@@ -64,7 +64,7 @@ module RSpec
|
|
64
64
|
def resolve_expected_args_based_on(actual_args)
|
65
65
|
return [] if [ArgumentMatchers::NoArgsMatcher::INSTANCE] == expected_args
|
66
66
|
|
67
|
-
any_args_index = expected_args.index
|
67
|
+
any_args_index = expected_args.index { |a| ArgumentMatchers::AnyArgsMatcher::INSTANCE == a }
|
68
68
|
return expected_args unless any_args_index
|
69
69
|
|
70
70
|
replace_any_args_with_splat_of_anything(any_args_index, actual_args.count)
|
@@ -81,10 +81,10 @@ module RSpec
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def ensure_expected_args_valid!
|
84
|
-
if expected_args.count
|
84
|
+
if expected_args.count { |a| ArgumentMatchers::AnyArgsMatcher::INSTANCE == a } > 1
|
85
85
|
raise ArgumentError, "`any_args` can only be passed to " \
|
86
86
|
"`with` once but you have passed it multiple times."
|
87
|
-
elsif expected_args.count > 1 && expected_args.
|
87
|
+
elsif expected_args.count > 1 && expected_args.any? { |a| ArgumentMatchers::NoArgsMatcher::INSTANCE == a }
|
88
88
|
raise ArgumentError, "`no_args` can only be passed as a " \
|
89
89
|
"singleton argument to `with` (i.e. `with(no_args)`), " \
|
90
90
|
"but you have passed additional arguments."
|
@@ -103,17 +103,18 @@ module RSpec
|
|
103
103
|
# Provides a way to perform customisations when verifying doubles.
|
104
104
|
#
|
105
105
|
# @example
|
106
|
-
# RSpec::Mocks.configuration.
|
106
|
+
# RSpec::Mocks.configuration.before_verifying_doubles do |ref|
|
107
107
|
# ref.some_method!
|
108
108
|
# end
|
109
|
-
def
|
110
|
-
|
109
|
+
def before_verifying_doubles(&block)
|
110
|
+
verifying_double_callbacks << block
|
111
111
|
end
|
112
|
+
alias :when_declaring_verifying_double :before_verifying_doubles
|
112
113
|
|
113
114
|
# @api private
|
114
115
|
# Returns an array of blocks to call when verifying doubles
|
115
|
-
def
|
116
|
-
@
|
116
|
+
def verifying_double_callbacks
|
117
|
+
@verifying_double_callbacks ||= []
|
117
118
|
end
|
118
119
|
|
119
120
|
def transfer_nested_constants?
|
@@ -1,4 +1,4 @@
|
|
1
|
-
RSpec::Support.require_rspec_support
|
1
|
+
RSpec::Support.require_rspec_support "object_formatter"
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module Mocks
|
@@ -36,9 +36,8 @@ module RSpec
|
|
36
36
|
class ErrorGenerator
|
37
37
|
attr_writer :opts
|
38
38
|
|
39
|
-
def initialize(target
|
39
|
+
def initialize(target=nil)
|
40
40
|
@target = target
|
41
|
-
@name = name
|
42
41
|
end
|
43
42
|
|
44
43
|
# @private
|
@@ -47,41 +46,26 @@ module RSpec
|
|
47
46
|
end
|
48
47
|
|
49
48
|
# @private
|
50
|
-
def raise_unexpected_message_error(message,
|
51
|
-
__raise "#{intro} received unexpected message :#{message}#{
|
49
|
+
def raise_unexpected_message_error(message, args)
|
50
|
+
__raise "#{intro} received unexpected message :#{message} with #{format_args(args)}"
|
52
51
|
end
|
53
52
|
|
54
53
|
# @private
|
55
|
-
def raise_unexpected_message_args_error(expectation,
|
56
|
-
|
57
|
-
actual_args = format_received_args(*args)
|
58
|
-
diff = diff_message(expectation.expected_args, args)
|
59
|
-
|
60
|
-
message = default_error_message(expectation, expected_args, actual_args)
|
61
|
-
message << "\nDiff:#{diff}" unless diff.empty?
|
62
|
-
|
63
|
-
__raise message
|
54
|
+
def raise_unexpected_message_args_error(expectation, args_for_multiple_calls, source_id=nil)
|
55
|
+
__raise error_message(expectation, args_for_multiple_calls), nil, source_id
|
64
56
|
end
|
65
57
|
|
66
58
|
# @private
|
67
|
-
def raise_missing_default_stub_error(expectation,
|
68
|
-
|
69
|
-
actual_args = format_received_args(*args)
|
70
|
-
diff = diff_message(expectation.expected_args, args)
|
71
|
-
|
72
|
-
message = default_error_message(expectation, expected_args, actual_args)
|
73
|
-
message << "\nDiff:\n #{diff}" unless diff.empty?
|
59
|
+
def raise_missing_default_stub_error(expectation, args_for_multiple_calls)
|
60
|
+
message = error_message(expectation, args_for_multiple_calls)
|
74
61
|
message << "\n Please stub a default value first if message might be received with other args as well. \n"
|
75
62
|
|
76
63
|
__raise message
|
77
64
|
end
|
78
65
|
|
79
66
|
# @private
|
80
|
-
def raise_similar_message_args_error(expectation,
|
81
|
-
|
82
|
-
actual_args = args_for_multiple_calls.map { |a| format_received_args(*a) }.join(", ")
|
83
|
-
|
84
|
-
__raise(default_error_message(expectation, expected_args, actual_args))
|
67
|
+
def raise_similar_message_args_error(expectation, args_for_multiple_calls, backtrace_line=nil)
|
68
|
+
__raise error_message(expectation, args_for_multiple_calls), backtrace_line
|
85
69
|
end
|
86
70
|
|
87
71
|
def default_error_message(expectation, expected_args, actual_args)
|
@@ -95,19 +79,37 @@ module RSpec
|
|
95
79
|
|
96
80
|
# rubocop:disable Style/ParameterLists
|
97
81
|
# @private
|
98
|
-
def raise_expectation_error(message, expected_received_count, argument_list_matcher,
|
82
|
+
def raise_expectation_error(message, expected_received_count, argument_list_matcher,
|
83
|
+
actual_received_count, expectation_count_type, args,
|
84
|
+
backtrace_line=nil, source_id=nil)
|
99
85
|
expected_part = expected_part_of_expectation_error(expected_received_count, expectation_count_type, argument_list_matcher)
|
100
|
-
received_part = received_part_of_expectation_error(actual_received_count,
|
101
|
-
__raise "(#{intro}).#{message}#{format_args(
|
86
|
+
received_part = received_part_of_expectation_error(actual_received_count, args)
|
87
|
+
__raise "(#{intro(:unwrapped)}).#{message}#{format_args(args)}\n #{expected_part}\n #{received_part}", backtrace_line, source_id
|
102
88
|
end
|
103
89
|
# rubocop:enable Style/ParameterLists
|
104
90
|
|
105
91
|
# @private
|
106
|
-
def raise_unimplemented_error(doubled_module, method_name)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
92
|
+
def raise_unimplemented_error(doubled_module, method_name, object)
|
93
|
+
message = case object
|
94
|
+
when InstanceVerifyingDouble
|
95
|
+
"the %s class does not implement the instance method: %s" <<
|
96
|
+
if ObjectMethodReference.for(doubled_module, method_name).implemented?
|
97
|
+
". Perhaps you meant to use `class_double` instead?"
|
98
|
+
else
|
99
|
+
""
|
100
|
+
end
|
101
|
+
when ClassVerifyingDouble
|
102
|
+
"the %s class does not implement the class method: %s" <<
|
103
|
+
if InstanceMethodReference.for(doubled_module, method_name).implemented?
|
104
|
+
". Perhaps you meant to use `instance_double` instead?"
|
105
|
+
else
|
106
|
+
""
|
107
|
+
end
|
108
|
+
else
|
109
|
+
"%s does not implement: %s"
|
110
|
+
end
|
111
|
+
|
112
|
+
__raise message % [doubled_module.description, method_name]
|
111
113
|
end
|
112
114
|
|
113
115
|
# @private
|
@@ -132,101 +134,131 @@ module RSpec
|
|
132
134
|
end
|
133
135
|
|
134
136
|
# @private
|
135
|
-
def
|
136
|
-
"
|
137
|
-
actual_method_call_args_description(actual_received_count, args)
|
137
|
+
def describe_expectation(verb, message, expected_received_count, _actual_received_count, args)
|
138
|
+
"#{verb} #{message}#{format_args(args)} #{count_message(expected_received_count)}"
|
138
139
|
end
|
139
140
|
|
140
141
|
# @private
|
141
|
-
def
|
142
|
-
"
|
143
|
-
expected_method_call_args_description(argument_list_matcher.expected_args)
|
142
|
+
def raise_out_of_order_error(message)
|
143
|
+
__raise "#{intro} received :#{message} out of order"
|
144
144
|
end
|
145
145
|
|
146
146
|
# @private
|
147
|
-
def
|
148
|
-
|
149
|
-
if count > 0 && args.length > 0
|
150
|
-
" with arguments: #{args.inspect.gsub(/\A\[(.+)\]\z/, '(\1)')}"
|
151
|
-
else
|
152
|
-
""
|
153
|
-
end
|
147
|
+
def raise_missing_block_error(args_to_yield)
|
148
|
+
__raise "#{intro} asked to yield |#{arg_list(args_to_yield)}| but no block was passed"
|
154
149
|
end
|
155
150
|
|
156
151
|
# @private
|
157
|
-
def
|
158
|
-
|
159
|
-
if args.length > 0
|
160
|
-
" with arguments: #{format_args(*args)}"
|
161
|
-
else
|
162
|
-
""
|
163
|
-
end
|
152
|
+
def raise_wrong_arity_error(args_to_yield, signature)
|
153
|
+
__raise "#{intro} yielded |#{arg_list(args_to_yield)}| to block with #{signature.description}"
|
164
154
|
end
|
165
155
|
|
166
156
|
# @private
|
167
|
-
def
|
168
|
-
|
169
|
-
|
170
|
-
when ArgumentMatchers::NoArgsMatcher then " with no arguments"
|
171
|
-
end
|
157
|
+
def raise_only_valid_on_a_partial_double(method)
|
158
|
+
__raise "#{intro} is a pure test double. `#{method}` is only " \
|
159
|
+
"available on a partial double."
|
172
160
|
end
|
173
161
|
|
174
162
|
# @private
|
175
|
-
def
|
176
|
-
"#{
|
163
|
+
def raise_expectation_on_unstubbed_method(method)
|
164
|
+
__raise "#{intro} expected to have received #{method}, but that " \
|
165
|
+
"object is not a spy or method has not been stubbed."
|
177
166
|
end
|
178
167
|
|
179
168
|
# @private
|
180
|
-
def
|
181
|
-
__raise "#{intro} received
|
169
|
+
def raise_expectation_on_mocked_method(method)
|
170
|
+
__raise "#{intro} expected to have received #{method}, but that " \
|
171
|
+
"method has been mocked instead of stubbed or spied."
|
182
172
|
end
|
183
173
|
|
184
174
|
# @private
|
185
|
-
def
|
186
|
-
__raise "
|
175
|
+
def raise_double_negation_error(wrapped_expression)
|
176
|
+
__raise "Isn't life confusing enough? You've already set a " \
|
177
|
+
"negative message expectation and now you are trying to " \
|
178
|
+
"negate it again with `never`. What does an expression like " \
|
179
|
+
"`#{wrapped_expression}.not_to receive(:msg).never` even mean?"
|
187
180
|
end
|
188
181
|
|
189
182
|
# @private
|
190
|
-
def
|
191
|
-
|
183
|
+
def raise_verifying_double_not_defined_error(ref)
|
184
|
+
notify(VerifyingDoubleNotDefinedError.new(
|
185
|
+
"#{ref.description.inspect} is not a defined constant. " \
|
186
|
+
"Perhaps you misspelt it? " \
|
187
|
+
"Disable check with `verify_doubled_constant_names` configuration option."
|
188
|
+
))
|
192
189
|
end
|
193
190
|
|
194
191
|
# @private
|
195
|
-
def
|
196
|
-
__raise "#{
|
192
|
+
def raise_have_received_disallowed(type, reason)
|
193
|
+
__raise "Using #{type}(...) with the `have_received` " \
|
194
|
+
"matcher is not supported#{reason}."
|
197
195
|
end
|
198
196
|
|
199
197
|
# @private
|
200
|
-
def
|
201
|
-
__raise "
|
202
|
-
"available on a partial double."
|
198
|
+
def raise_cant_constrain_count_for_negated_have_received_error(count_constraint)
|
199
|
+
__raise "can't use #{count_constraint} when negative"
|
203
200
|
end
|
204
201
|
|
205
202
|
# @private
|
206
|
-
def
|
207
|
-
__raise "
|
208
|
-
"object is not a spy or method has not been stubbed."
|
203
|
+
def raise_method_not_stubbed_error(method_name)
|
204
|
+
__raise "The method `#{method_name}` was not stubbed or was already unstubbed"
|
209
205
|
end
|
210
206
|
|
211
207
|
# @private
|
212
|
-
def
|
213
|
-
|
214
|
-
|
215
|
-
|
208
|
+
def raise_already_invoked_error(message, calling_customization)
|
209
|
+
error_message = "The message expectation for #{intro}.#{message} has already been invoked " \
|
210
|
+
"and cannot be modified further (e.g. using `#{calling_customization}`). All message expectation " \
|
211
|
+
"customizations must be applied before it is used for the first time."
|
216
212
|
|
217
|
-
|
218
|
-
raise "Isn't life confusing enough? You've already set a " \
|
219
|
-
"negative message expectation and now you are trying to " \
|
220
|
-
"negate it again with `never`. What does an expression like " \
|
221
|
-
"`#{wrapped_expression}.not_to receive(:msg).never` even mean?"
|
213
|
+
notify MockExpectationAlreadyInvokedError.new(error_message)
|
222
214
|
end
|
223
215
|
|
224
216
|
private
|
225
217
|
|
218
|
+
def received_part_of_expectation_error(actual_received_count, args)
|
219
|
+
"received: #{count_message(actual_received_count)}" +
|
220
|
+
method_call_args_description(args) do
|
221
|
+
actual_received_count > 0 && args.length > 0
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def expected_part_of_expectation_error(expected_received_count, expectation_count_type, argument_list_matcher)
|
226
|
+
"expected: #{count_message(expected_received_count, expectation_count_type)}" +
|
227
|
+
method_call_args_description(argument_list_matcher.expected_args) do
|
228
|
+
argument_list_matcher.expected_args.length > 0
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def method_call_args_description(args)
|
233
|
+
case args.first
|
234
|
+
when ArgumentMatchers::AnyArgsMatcher then " with any arguments"
|
235
|
+
when ArgumentMatchers::NoArgsMatcher then " with no arguments"
|
236
|
+
else
|
237
|
+
if yield
|
238
|
+
" with arguments: #{format_args(args)}"
|
239
|
+
else
|
240
|
+
""
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
226
245
|
def unexpected_arguments_message(expected_args_string, actual_args_string)
|
227
246
|
"with unexpected arguments\n expected: #{expected_args_string}\n got: #{actual_args_string}"
|
228
247
|
end
|
229
248
|
|
249
|
+
def error_message(expectation, args_for_multiple_calls)
|
250
|
+
expected_args = format_args(expectation.expected_args)
|
251
|
+
actual_args = format_received_args(args_for_multiple_calls)
|
252
|
+
message = default_error_message(expectation, expected_args, actual_args)
|
253
|
+
|
254
|
+
if args_for_multiple_calls.one?
|
255
|
+
diff = diff_message(expectation.expected_args, args_for_multiple_calls.first)
|
256
|
+
message << "\nDiff:#{diff}" unless diff.strip.empty?
|
257
|
+
end
|
258
|
+
|
259
|
+
message
|
260
|
+
end
|
261
|
+
|
230
262
|
def diff_message(expected_args, actual_args)
|
231
263
|
formatted_expected_args = expected_args.map do |x|
|
232
264
|
RSpec::Support.rspec_description_for_object(x)
|
@@ -253,47 +285,54 @@ module RSpec
|
|
253
285
|
RSpec::Support::Differ.new(:color => RSpec::Mocks.configuration.color?)
|
254
286
|
end
|
255
287
|
|
256
|
-
def intro
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
"
|
261
|
-
|
262
|
-
"
|
263
|
-
|
264
|
-
|
265
|
-
else
|
266
|
-
"nil"
|
288
|
+
def intro(unwrapped=false)
|
289
|
+
case @target
|
290
|
+
when TestDouble then TestDoubleFormatter.format(@target, unwrapped)
|
291
|
+
when Class then
|
292
|
+
formatted = "#{@target.inspect} (class)"
|
293
|
+
return formatted if unwrapped
|
294
|
+
"#<#{formatted}>"
|
295
|
+
when NilClass then "nil"
|
296
|
+
else @target
|
267
297
|
end
|
268
298
|
end
|
269
299
|
|
270
|
-
def __raise(message)
|
300
|
+
def __raise(message, backtrace_line=nil, source_id=nil)
|
271
301
|
message = opts[:message] unless opts[:message].nil?
|
272
|
-
|
302
|
+
exception = RSpec::Mocks::MockExpectationError.new(message)
|
303
|
+
prepend_to_backtrace(exception, backtrace_line) if backtrace_line
|
304
|
+
notify exception, :source_id => source_id
|
273
305
|
end
|
274
306
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
307
|
+
if RSpec::Support::Ruby.jruby?
|
308
|
+
def prepend_to_backtrace(exception, line)
|
309
|
+
raise exception
|
310
|
+
rescue RSpec::Mocks::MockExpectationError => with_backtrace
|
311
|
+
with_backtrace.backtrace.unshift(line)
|
312
|
+
end
|
313
|
+
else
|
314
|
+
def prepend_to_backtrace(exception, line)
|
315
|
+
exception.set_backtrace(caller.unshift line)
|
316
|
+
end
|
281
317
|
end
|
282
318
|
|
283
|
-
def
|
284
|
-
|
319
|
+
def notify(*args)
|
320
|
+
RSpec::Support.notify_failure(*args)
|
285
321
|
end
|
286
322
|
|
287
|
-
def
|
288
|
-
|
323
|
+
def format_args(args)
|
324
|
+
return "(no args)" if args.empty?
|
325
|
+
"(#{arg_list(args)})"
|
289
326
|
end
|
290
327
|
|
291
|
-
def
|
292
|
-
args.
|
328
|
+
def arg_list(args)
|
329
|
+
args.map { |arg| RSpec::Support::ObjectFormatter.format(arg) }.join(", ")
|
293
330
|
end
|
294
331
|
|
295
|
-
def
|
296
|
-
|
332
|
+
def format_received_args(args_for_multiple_calls)
|
333
|
+
grouped_args(args_for_multiple_calls).map do |args_for_one_call, index|
|
334
|
+
"#{format_args(args_for_one_call)}#{group_count(index, args_for_multiple_calls)}"
|
335
|
+
end.join("\n ")
|
297
336
|
end
|
298
337
|
|
299
338
|
def count_message(count, expectation_count_type=nil)
|
@@ -305,6 +344,19 @@ module RSpec
|
|
305
344
|
def times(count)
|
306
345
|
"#{count} time#{count == 1 ? '' : 's'}"
|
307
346
|
end
|
347
|
+
|
348
|
+
def grouped_args(args)
|
349
|
+
Hash[args.group_by { |x| x }.map { |k, v| [k, v.count] }]
|
350
|
+
end
|
351
|
+
|
352
|
+
def group_count(index, args)
|
353
|
+
" (#{times(index)})" if args.size > 1 || index > 1
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# @private
|
358
|
+
def self.error_generator
|
359
|
+
@error_generator ||= ErrorGenerator.new
|
308
360
|
end
|
309
361
|
end
|
310
362
|
end
|