/
verifying_double.rb
129 lines (109 loc) · 3.46 KB
/
verifying_double.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
RSpec::Support.require_rspec_mocks 'verifying_proxy'
module RSpec
module Mocks
# @private
module VerifyingDouble
def respond_to?(message, include_private=false)
return super unless null_object?
method_ref = __mock_proxy.method_reference[message]
case method_ref.visibility
when :public then true
when :private then include_private
when :protected then include_private || RUBY_VERSION.to_f < 2.0
else !method_ref.unimplemented?
end
end
def method_missing(message, *args, &block)
# Null object conditional is an optimization. If not a null object,
# validity of method expectations will have been checked at definition
# time.
if null_object?
if @__sending_message == message
__mock_proxy.ensure_implemented(message)
else
__mock_proxy.ensure_publicly_implemented(message, self)
end
__mock_proxy.validate_arguments!(message, args)
end
super
end
# @private
module SilentIO
def self.method_missing(*); end
def self.respond_to?(*)
true
end
end
# Redefining `__send__` causes ruby to issue a warning.
old, $stderr = $stderr, SilentIO
def __send__(name, *args, &block)
@__sending_message = name
super
ensure
@__sending_message = nil
end
$stderr = old
def send(name, *args, &block)
__send__(name, *args, &block)
end
def initialize(doubled_module, *args)
@doubled_module = doubled_module
possible_name = args.first
name = if String === possible_name || Symbol === possible_name
args.shift
end
super(name, *args)
@__sending_message = nil
end
end
# A mock providing a custom proxy that can verify the validity of any
# method stubs or expectations against the public instance methods of the
# given class.
#
# @private
class InstanceVerifyingDouble
include TestDouble
include VerifyingDouble
def __build_mock_proxy(order_group)
VerifyingProxy.new(self, order_group,
@doubled_module,
InstanceMethodReference
)
end
end
# An awkward module necessary because we cannot otherwise have
# ClassVerifyingDouble inherit from Module and still share these methods.
#
# @private
module ObjectVerifyingDoubleMethods
include TestDouble
include VerifyingDouble
def as_stubbed_const(options={})
ConstantMutator.stub(@doubled_module.const_to_replace, self, options)
self
end
private
def __build_mock_proxy(order_group)
VerifyingProxy.new(self, order_group,
@doubled_module,
ObjectMethodReference
)
end
end
# Similar to an InstanceVerifyingDouble, except that it verifies against
# public methods of the given object.
#
# @private
class ObjectVerifyingDouble
include ObjectVerifyingDoubleMethods
end
# Effectively the same as an ObjectVerifyingDouble (since a class is a type
# of object), except with Module in the inheritance chain so that
# transferring nested constants to work.
#
# @private
class ClassVerifyingDouble < Module
include ObjectVerifyingDoubleMethods
end
end
end