rspec-mocks-diag 3.8.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.yardopts +6 -0
- data/Changelog.md +1108 -0
- data/LICENSE.md +25 -0
- data/README.md +460 -0
- data/lib/rspec/mocks.rb +130 -0
- data/lib/rspec/mocks/any_instance.rb +11 -0
- data/lib/rspec/mocks/any_instance/chain.rb +110 -0
- data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
- data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +31 -0
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +50 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +83 -0
- data/lib/rspec/mocks/any_instance/proxy.rb +116 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +289 -0
- data/lib/rspec/mocks/any_instance/stub_chain.rb +51 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
- data/lib/rspec/mocks/argument_list_matcher.rb +100 -0
- data/lib/rspec/mocks/argument_matchers.rb +320 -0
- data/lib/rspec/mocks/configuration.rb +212 -0
- data/lib/rspec/mocks/error_generator.rb +378 -0
- data/lib/rspec/mocks/example_methods.rb +434 -0
- data/lib/rspec/mocks/instance_method_stasher.rb +146 -0
- data/lib/rspec/mocks/marshal_extension.rb +41 -0
- data/lib/rspec/mocks/matchers/expectation_customization.rb +20 -0
- data/lib/rspec/mocks/matchers/have_received.rb +134 -0
- data/lib/rspec/mocks/matchers/receive.rb +132 -0
- data/lib/rspec/mocks/matchers/receive_message_chain.rb +82 -0
- data/lib/rspec/mocks/matchers/receive_messages.rb +77 -0
- data/lib/rspec/mocks/message_chain.rb +87 -0
- data/lib/rspec/mocks/message_expectation.rb +748 -0
- data/lib/rspec/mocks/method_double.rb +287 -0
- data/lib/rspec/mocks/method_reference.rb +202 -0
- data/lib/rspec/mocks/minitest_integration.rb +68 -0
- data/lib/rspec/mocks/mutate_const.rb +339 -0
- data/lib/rspec/mocks/object_reference.rb +149 -0
- data/lib/rspec/mocks/order_group.rb +81 -0
- data/lib/rspec/mocks/proxy.rb +485 -0
- data/lib/rspec/mocks/space.rb +238 -0
- data/lib/rspec/mocks/standalone.rb +3 -0
- data/lib/rspec/mocks/syntax.rb +325 -0
- data/lib/rspec/mocks/targets.rb +124 -0
- data/lib/rspec/mocks/test_double.rb +171 -0
- data/lib/rspec/mocks/verifying_double.rb +129 -0
- data/lib/rspec/mocks/verifying_message_expectation.rb +54 -0
- data/lib/rspec/mocks/verifying_proxy.rb +220 -0
- data/lib/rspec/mocks/version.rb +9 -0
- metadata +186 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
# @private
|
4
|
+
module TargetDelegationClassMethods
|
5
|
+
def delegate_to(matcher_method)
|
6
|
+
define_method(:to) do |matcher, &block|
|
7
|
+
unless matcher_allowed?(matcher)
|
8
|
+
raise_unsupported_matcher(:to, matcher)
|
9
|
+
end
|
10
|
+
define_matcher(matcher, matcher_method, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def delegate_not_to(matcher_method, options={})
|
15
|
+
method_name = options.fetch(:from)
|
16
|
+
define_method(method_name) do |matcher, &block|
|
17
|
+
case matcher
|
18
|
+
when Matchers::Receive, Matchers::HaveReceived
|
19
|
+
define_matcher(matcher, matcher_method, &block)
|
20
|
+
when Matchers::ReceiveMessages, Matchers::ReceiveMessageChain
|
21
|
+
raise_negation_unsupported(method_name, matcher)
|
22
|
+
else
|
23
|
+
raise_unsupported_matcher(method_name, matcher)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def disallow_negation(method_name)
|
29
|
+
define_method(method_name) do |matcher, *_args|
|
30
|
+
raise_negation_unsupported(method_name, matcher)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @private
|
36
|
+
module TargetDelegationInstanceMethods
|
37
|
+
attr_reader :target
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def matcher_allowed?(matcher)
|
42
|
+
Matchers::Matcher === matcher
|
43
|
+
end
|
44
|
+
|
45
|
+
def define_matcher(matcher, name, &block)
|
46
|
+
matcher.__send__(name, target, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def raise_unsupported_matcher(method_name, matcher)
|
50
|
+
raise UnsupportedMatcherError,
|
51
|
+
"only the `receive`, `have_received` and `receive_messages` matchers are supported " \
|
52
|
+
"with `#{expression}(...).#{method_name}`, but you have provided: #{matcher}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def raise_negation_unsupported(method_name, matcher)
|
56
|
+
raise NegationUnsupportedError,
|
57
|
+
"`#{expression}(...).#{method_name} #{matcher.name}` is not supported since it " \
|
58
|
+
"doesn't really make sense. What would it even mean?"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @private
|
63
|
+
class TargetBase
|
64
|
+
def initialize(target)
|
65
|
+
@target = target
|
66
|
+
end
|
67
|
+
|
68
|
+
extend TargetDelegationClassMethods
|
69
|
+
include TargetDelegationInstanceMethods
|
70
|
+
end
|
71
|
+
|
72
|
+
# @private
|
73
|
+
module ExpectationTargetMethods
|
74
|
+
extend TargetDelegationClassMethods
|
75
|
+
include TargetDelegationInstanceMethods
|
76
|
+
|
77
|
+
delegate_to :setup_expectation
|
78
|
+
delegate_not_to :setup_negative_expectation, :from => :not_to
|
79
|
+
delegate_not_to :setup_negative_expectation, :from => :to_not
|
80
|
+
|
81
|
+
def expression
|
82
|
+
:expect
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @private
|
87
|
+
class ExpectationTarget < TargetBase
|
88
|
+
include ExpectationTargetMethods
|
89
|
+
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
class AllowanceTarget < TargetBase
|
93
|
+
def expression
|
94
|
+
:allow
|
95
|
+
end
|
96
|
+
|
97
|
+
delegate_to :setup_allowance
|
98
|
+
disallow_negation :not_to
|
99
|
+
disallow_negation :to_not
|
100
|
+
end
|
101
|
+
|
102
|
+
# @private
|
103
|
+
class AnyInstanceAllowanceTarget < TargetBase
|
104
|
+
def expression
|
105
|
+
:allow_any_instance_of
|
106
|
+
end
|
107
|
+
|
108
|
+
delegate_to :setup_any_instance_allowance
|
109
|
+
disallow_negation :not_to
|
110
|
+
disallow_negation :to_not
|
111
|
+
end
|
112
|
+
|
113
|
+
# @private
|
114
|
+
class AnyInstanceExpectationTarget < TargetBase
|
115
|
+
def expression
|
116
|
+
:expect_any_instance_of
|
117
|
+
end
|
118
|
+
|
119
|
+
delegate_to :setup_any_instance_expectation
|
120
|
+
delegate_not_to :setup_any_instance_negative_expectation, :from => :not_to
|
121
|
+
delegate_not_to :setup_any_instance_negative_expectation, :from => :to_not
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
# Implements the methods needed for a pure test double. RSpec::Mocks::Double
|
4
|
+
# includes this module, and it is provided for cases where you want a
|
5
|
+
# pure test double without subclassing RSpec::Mocks::Double.
|
6
|
+
module TestDouble
|
7
|
+
# Creates a new test double with a `name` (that will be used in error
|
8
|
+
# messages only)
|
9
|
+
def initialize(name=nil, stubs={})
|
10
|
+
@__expired = false
|
11
|
+
if Hash === name && stubs.empty?
|
12
|
+
stubs = name
|
13
|
+
@name = nil
|
14
|
+
else
|
15
|
+
@name = name
|
16
|
+
end
|
17
|
+
assign_stubs(stubs)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Tells the object to respond to all messages. If specific stub values
|
21
|
+
# are declared, they'll work as expected. If not, the receiver is
|
22
|
+
# returned.
|
23
|
+
def as_null_object
|
24
|
+
__mock_proxy.as_null_object
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns true if this object has received `as_null_object`
|
28
|
+
def null_object?
|
29
|
+
__mock_proxy.null_object?
|
30
|
+
end
|
31
|
+
|
32
|
+
# This allows for comparing the mock to other objects that proxy such as
|
33
|
+
# ActiveRecords belongs_to proxy objects. By making the other object run
|
34
|
+
# the comparison, we're sure the call gets delegated to the proxy
|
35
|
+
# target.
|
36
|
+
def ==(other)
|
37
|
+
other == __mock_proxy
|
38
|
+
end
|
39
|
+
|
40
|
+
# @private
|
41
|
+
def inspect
|
42
|
+
TestDoubleFormatter.format(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private
|
46
|
+
def to_s
|
47
|
+
inspect.tr('<', '[').tr('>', ']')
|
48
|
+
end
|
49
|
+
|
50
|
+
# @private
|
51
|
+
def respond_to?(message, incl_private=false)
|
52
|
+
__mock_proxy.null_object? ? true : super
|
53
|
+
end
|
54
|
+
|
55
|
+
# @private
|
56
|
+
def __build_mock_proxy_unless_expired(order_group)
|
57
|
+
__raise_expired_error || __build_mock_proxy(order_group)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @private
|
61
|
+
def __disallow_further_usage!
|
62
|
+
@__expired = true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Override for default freeze implementation to prevent freezing of test
|
66
|
+
# doubles.
|
67
|
+
def freeze
|
68
|
+
RSpec.warn_with("WARNING: you attempted to freeze a test double. This is explicitly a no-op as freezing doubles can lead to undesired behaviour when resetting tests.")
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def method_missing(message, *args, &block)
|
75
|
+
proxy = __mock_proxy
|
76
|
+
proxy.record_message_received(message, *args, &block)
|
77
|
+
|
78
|
+
if proxy.null_object?
|
79
|
+
case message
|
80
|
+
when :to_int then return 0
|
81
|
+
when :to_a, :to_ary then return nil
|
82
|
+
when :to_str then return to_s
|
83
|
+
else return self
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Defined private and protected methods will still trigger `method_missing`
|
88
|
+
# when called publicly. We want ruby's method visibility error to get raised,
|
89
|
+
# so we simply delegate to `super` in that case.
|
90
|
+
# ...well, we would delegate to `super`, but there's a JRuby
|
91
|
+
# bug, so we raise our own visibility error instead:
|
92
|
+
# https://github.com/jruby/jruby/issues/1398
|
93
|
+
visibility = proxy.visibility_for(message)
|
94
|
+
if visibility == :private || visibility == :protected
|
95
|
+
ErrorGenerator.new(self).raise_non_public_error(
|
96
|
+
message, visibility
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Required wrapping doubles in an Array on Ruby 1.9.2
|
101
|
+
raise NoMethodError if [:to_a, :to_ary].include? message
|
102
|
+
proxy.raise_unexpected_message_error(message, args)
|
103
|
+
end
|
104
|
+
|
105
|
+
def assign_stubs(stubs)
|
106
|
+
stubs.each_pair do |message, response|
|
107
|
+
__mock_proxy.add_simple_stub(message, response)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def __mock_proxy
|
112
|
+
::RSpec::Mocks.space.proxy_for(self)
|
113
|
+
end
|
114
|
+
|
115
|
+
def __build_mock_proxy(order_group)
|
116
|
+
TestDoubleProxy.new(self, order_group)
|
117
|
+
end
|
118
|
+
|
119
|
+
def __raise_expired_error
|
120
|
+
return false unless @__expired
|
121
|
+
ErrorGenerator.new(self).raise_expired_test_double_error
|
122
|
+
end
|
123
|
+
|
124
|
+
def initialize_copy(other)
|
125
|
+
as_null_object if other.null_object?
|
126
|
+
super
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# A generic test double object. `double`, `instance_double` and friends
|
131
|
+
# return an instance of this.
|
132
|
+
class Double
|
133
|
+
include TestDouble
|
134
|
+
end
|
135
|
+
|
136
|
+
# @private
|
137
|
+
module TestDoubleFormatter
|
138
|
+
def self.format(dbl, unwrap=false)
|
139
|
+
format = "#{type_desc(dbl)}#{verified_module_desc(dbl)} #{name_desc(dbl)}"
|
140
|
+
return format if unwrap
|
141
|
+
"#<#{format}>"
|
142
|
+
end
|
143
|
+
|
144
|
+
class << self
|
145
|
+
private
|
146
|
+
|
147
|
+
def type_desc(dbl)
|
148
|
+
case dbl
|
149
|
+
when InstanceVerifyingDouble then "InstanceDouble"
|
150
|
+
when ClassVerifyingDouble then "ClassDouble"
|
151
|
+
when ObjectVerifyingDouble then "ObjectDouble"
|
152
|
+
else "Double"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# @private
|
157
|
+
IVAR_GET = Object.instance_method(:instance_variable_get)
|
158
|
+
|
159
|
+
def verified_module_desc(dbl)
|
160
|
+
return nil unless VerifyingDouble === dbl
|
161
|
+
"(#{IVAR_GET.bind(dbl).call(:@doubled_module).description})"
|
162
|
+
end
|
163
|
+
|
164
|
+
def name_desc(dbl)
|
165
|
+
return "(anonymous)" unless (name = IVAR_GET.bind(dbl).call(:@name))
|
166
|
+
name.inspect
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
RSpec::Support.require_rspec_mocks 'verifying_proxy'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
# @private
|
6
|
+
module VerifyingDouble
|
7
|
+
def respond_to?(message, include_private=false)
|
8
|
+
return super unless null_object?
|
9
|
+
|
10
|
+
method_ref = __mock_proxy.method_reference[message]
|
11
|
+
|
12
|
+
case method_ref.visibility
|
13
|
+
when :public then true
|
14
|
+
when :private then include_private
|
15
|
+
when :protected then include_private || RUBY_VERSION.to_f < 2.0
|
16
|
+
else !method_ref.unimplemented?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(message, *args, &block)
|
21
|
+
# Null object conditional is an optimization. If not a null object,
|
22
|
+
# validity of method expectations will have been checked at definition
|
23
|
+
# time.
|
24
|
+
if null_object?
|
25
|
+
if @__sending_message == message
|
26
|
+
__mock_proxy.ensure_implemented(message)
|
27
|
+
else
|
28
|
+
__mock_proxy.ensure_publicly_implemented(message, self)
|
29
|
+
end
|
30
|
+
|
31
|
+
__mock_proxy.validate_arguments!(message, args)
|
32
|
+
end
|
33
|
+
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
# @private
|
38
|
+
module SilentIO
|
39
|
+
def self.method_missing(*); end
|
40
|
+
def self.respond_to?(*)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Redefining `__send__` causes ruby to issue a warning.
|
46
|
+
old, $stderr = $stderr, SilentIO
|
47
|
+
def __send__(name, *args, &block)
|
48
|
+
@__sending_message = name
|
49
|
+
super
|
50
|
+
ensure
|
51
|
+
@__sending_message = nil
|
52
|
+
end
|
53
|
+
$stderr = old
|
54
|
+
|
55
|
+
def send(name, *args, &block)
|
56
|
+
__send__(name, *args, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(doubled_module, *args)
|
60
|
+
@doubled_module = doubled_module
|
61
|
+
|
62
|
+
possible_name = args.first
|
63
|
+
name = if String === possible_name || Symbol === possible_name
|
64
|
+
args.shift
|
65
|
+
end
|
66
|
+
|
67
|
+
super(name, *args)
|
68
|
+
@__sending_message = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# A mock providing a custom proxy that can verify the validity of any
|
73
|
+
# method stubs or expectations against the public instance methods of the
|
74
|
+
# given class.
|
75
|
+
#
|
76
|
+
# @private
|
77
|
+
class InstanceVerifyingDouble
|
78
|
+
include TestDouble
|
79
|
+
include VerifyingDouble
|
80
|
+
|
81
|
+
def __build_mock_proxy(order_group)
|
82
|
+
VerifyingProxy.new(self, order_group,
|
83
|
+
@doubled_module,
|
84
|
+
InstanceMethodReference
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# An awkward module necessary because we cannot otherwise have
|
90
|
+
# ClassVerifyingDouble inherit from Module and still share these methods.
|
91
|
+
#
|
92
|
+
# @private
|
93
|
+
module ObjectVerifyingDoubleMethods
|
94
|
+
include TestDouble
|
95
|
+
include VerifyingDouble
|
96
|
+
|
97
|
+
def as_stubbed_const(options={})
|
98
|
+
ConstantMutator.stub(@doubled_module.const_to_replace, self, options)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def __build_mock_proxy(order_group)
|
105
|
+
VerifyingProxy.new(self, order_group,
|
106
|
+
@doubled_module,
|
107
|
+
ObjectMethodReference
|
108
|
+
)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Similar to an InstanceVerifyingDouble, except that it verifies against
|
113
|
+
# public methods of the given object.
|
114
|
+
#
|
115
|
+
# @private
|
116
|
+
class ObjectVerifyingDouble
|
117
|
+
include ObjectVerifyingDoubleMethods
|
118
|
+
end
|
119
|
+
|
120
|
+
# Effectively the same as an ObjectVerifyingDouble (since a class is a type
|
121
|
+
# of object), except with Module in the inheritance chain so that
|
122
|
+
# transferring nested constants to work.
|
123
|
+
#
|
124
|
+
# @private
|
125
|
+
class ClassVerifyingDouble < Module
|
126
|
+
include ObjectVerifyingDoubleMethods
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
RSpec::Support.require_rspec_support 'method_signature_verifier'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
# A message expectation that knows about the real implementation of the
|
6
|
+
# message being expected, so that it can verify that any expectations
|
7
|
+
# have the valid arguments.
|
8
|
+
# @api private
|
9
|
+
class VerifyingMessageExpectation < MessageExpectation
|
10
|
+
# A level of indirection is used here rather than just passing in the
|
11
|
+
# method itself, since method look up is expensive and we only want to
|
12
|
+
# do it if actually needed.
|
13
|
+
#
|
14
|
+
# Conceptually the method reference makes more sense as a constructor
|
15
|
+
# argument since it should be immutable, but it is significantly more
|
16
|
+
# straight forward to build the object in pieces so for now it stays as
|
17
|
+
# an accessor.
|
18
|
+
attr_accessor :method_reference
|
19
|
+
|
20
|
+
def initialize(*args)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# @private
|
25
|
+
def with(*args, &block)
|
26
|
+
super(*args, &block).tap do
|
27
|
+
validate_expected_arguments! do |signature|
|
28
|
+
example_call_site_args = [:an_arg] * signature.min_non_kw_args
|
29
|
+
example_call_site_args << :kw_args_hash if signature.required_kw_args.any?
|
30
|
+
@argument_list_matcher.resolve_expected_args_based_on(example_call_site_args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def validate_expected_arguments!
|
38
|
+
return if method_reference.nil?
|
39
|
+
|
40
|
+
method_reference.with_signature do |signature|
|
41
|
+
args = yield signature
|
42
|
+
verifier = Support::LooseSignatureVerifier.new(signature, args)
|
43
|
+
|
44
|
+
unless verifier.valid?
|
45
|
+
# Fail fast is required, otherwise the message expectation will fail
|
46
|
+
# as well ("expected method not called") and clobber this one.
|
47
|
+
@failed_fast = true
|
48
|
+
@error_generator.raise_invalid_arguments_error(verifier)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|