rspec-mocks 2.6.0 → 2.7.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.
- data/README.md +0 -19
- data/features/Scope.md +17 -0
- data/features/argument_matchers/README.md +27 -0
- data/features/argument_matchers/explicit.feature +60 -0
- data/features/argument_matchers/general_matchers.feature +85 -0
- data/features/argument_matchers/type_matchers.feature +25 -0
- data/features/message_expectations/any_instance.feature +2 -0
- data/features/message_expectations/receive_counts.feature +209 -0
- data/features/method_stubs/README.md +6 -10
- data/features/method_stubs/any_instance.feature +111 -1
- data/features/method_stubs/simple_return_value.feature +34 -25
- data/features/method_stubs/stub_implementation.feature +1 -1
- data/features/method_stubs/to_ary.feature +12 -10
- data/features/support/env.rb +1 -1
- data/lib/rspec/mocks/any_instance/chain.rb +49 -0
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +33 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +48 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +168 -0
- data/lib/rspec/mocks/any_instance/stub_chain.rb +35 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +34 -0
- data/lib/rspec/mocks/any_instance.rb +8 -235
- data/lib/rspec/mocks/argument_expectation.rb +1 -1
- data/lib/rspec/mocks/argument_matchers.rb +19 -25
- data/lib/rspec/mocks/extensions/marshal.rb +1 -1
- data/lib/rspec/mocks/extensions/psych.rb +1 -1
- data/lib/rspec/mocks/message_expectation.rb +7 -4
- data/lib/rspec/mocks/methods.rb +6 -8
- data/lib/rspec/mocks/mock.rb +2 -2
- data/lib/rspec/mocks/proxy.rb +4 -4
- data/lib/rspec/mocks/version.rb +4 -4
- data/lib/rspec/mocks.rb +13 -14
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +40 -0
- data/spec/rspec/mocks/any_instance_spec.rb +219 -24
- data/spec/rspec/mocks/any_number_of_times_spec.rb +2 -2
- data/spec/rspec/mocks/argument_expectation_spec.rb +15 -3
- data/spec/rspec/mocks/at_least_spec.rb +1 -1
- data/spec/rspec/mocks/at_most_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_10263_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_7611_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_8165_spec.rb +2 -2
- data/spec/rspec/mocks/bug_report_957_spec.rb +2 -2
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +1 -1
- data/spec/rspec/mocks/hash_including_matcher_spec.rb +11 -11
- data/spec/rspec/mocks/hash_not_including_matcher_spec.rb +6 -6
- data/spec/rspec/mocks/mock_spec.rb +49 -43
- data/spec/rspec/mocks/multiple_return_value_spec.rb +26 -26
- data/spec/rspec/mocks/partial_mock_spec.rb +3 -2
- data/spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb +1 -0
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -3
- data/spec/rspec/mocks/precise_counts_spec.rb +1 -1
- data/spec/rspec/mocks/serialization_spec.rb +7 -2
- data/spec/rspec/mocks/stub_implementation_spec.rb +6 -6
- data/spec/rspec/mocks/stub_spec.rb +6 -6
- data/spec/rspec/mocks/to_ary_spec.rb +9 -0
- metadata +45 -42
- data/.autotest +0 -7
- data/.document +0 -5
- data/.gitignore +0 -10
- data/.travis.yml +0 -7
- data/Gemfile +0 -40
- data/Guardfile +0 -8
- data/License.txt +0 -22
- data/Rakefile +0 -75
- data/autotest/discover.rb +0 -1
- data/cucumber.yml +0 -2
- data/features/.nav +0 -17
- data/features/Changelog.md +0 -80
- data/rspec-mocks.gemspec +0 -25
- data/specs.watchr +0 -57
|
@@ -1,55 +1,64 @@
|
|
|
1
1
|
Feature: stub with a simple return value
|
|
2
2
|
|
|
3
3
|
Use the `stub` method on a test double or a real object to tell the object to
|
|
4
|
-
return a value (or values) in response to a given message.
|
|
5
|
-
never received
|
|
4
|
+
return a value (or values) in response to a given message. Nothing happens if
|
|
5
|
+
the message is never received.
|
|
6
6
|
|
|
7
|
-
Scenario:
|
|
7
|
+
Scenario: stub with no return value
|
|
8
8
|
Given a file named "example_spec.rb" with:
|
|
9
9
|
"""
|
|
10
|
-
describe "a
|
|
11
|
-
let(:
|
|
10
|
+
describe "a stub with no return value specified" do
|
|
11
|
+
let(:collaborator) { double("collaborator") }
|
|
12
12
|
|
|
13
13
|
it "returns nil" do
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it "quietly carries on when not called" do
|
|
19
|
-
receiver.stub(:message)
|
|
14
|
+
collaborator.stub(:message)
|
|
15
|
+
collaborator.message.should be(nil)
|
|
20
16
|
end
|
|
21
17
|
end
|
|
22
18
|
"""
|
|
23
19
|
When I run `rspec example_spec.rb`
|
|
24
|
-
Then the
|
|
20
|
+
Then the examples should all pass
|
|
25
21
|
|
|
26
|
-
Scenario:
|
|
22
|
+
Scenario: stubs with return values
|
|
27
23
|
Given a file named "example_spec.rb" with:
|
|
28
24
|
"""
|
|
29
|
-
describe "a
|
|
25
|
+
describe "a stub with a return value" do
|
|
30
26
|
context "specified in a block" do
|
|
31
27
|
it "returns the specified value" do
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
collaborator = double("collaborator")
|
|
29
|
+
collaborator.stub(:message) { :value }
|
|
30
|
+
collaborator.message.should eq(:value)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "specified with #and_return" do
|
|
35
|
+
it "returns the specified value" do
|
|
36
|
+
collaborator = double("collaborator")
|
|
37
|
+
collaborator.stub(:message).and_return(:value)
|
|
38
|
+
collaborator.message.should eq(:value)
|
|
35
39
|
end
|
|
36
40
|
end
|
|
37
41
|
|
|
38
|
-
context "specified
|
|
42
|
+
context "specified with a hash passed to #stub" do
|
|
39
43
|
it "returns the specified value" do
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
collaborator = double("collaborator")
|
|
45
|
+
collaborator.stub(:message_1 => :value_1, :message_2 => :value_2)
|
|
46
|
+
collaborator.message_1.should eq(:value_1)
|
|
47
|
+
collaborator.message_2.should eq(:value_2)
|
|
42
48
|
end
|
|
43
49
|
end
|
|
44
50
|
|
|
45
|
-
context "specified with
|
|
51
|
+
context "specified with a hash passed to #double" do
|
|
46
52
|
it "returns the specified value" do
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
collaborator = double("collaborator",
|
|
54
|
+
:message_1 => :value_1,
|
|
55
|
+
:message_2 => :value_2
|
|
56
|
+
)
|
|
57
|
+
collaborator.message_1.should eq(:value_1)
|
|
58
|
+
collaborator.message_2.should eq(:value_2)
|
|
50
59
|
end
|
|
51
60
|
end
|
|
52
61
|
end
|
|
53
62
|
"""
|
|
54
63
|
When I run `rspec example_spec.rb`
|
|
55
|
-
Then the
|
|
64
|
+
Then the examples should all pass
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
Feature: double handling to_ary
|
|
2
2
|
|
|
3
|
-
Ruby implicitly sends to_ary to
|
|
4
|
-
receives `flatten`:
|
|
3
|
+
Ruby implicitly sends `to_ary` to all of the objects in an `Array` when the
|
|
4
|
+
array receives `flatten`:
|
|
5
5
|
|
|
6
6
|
[obj].flatten # => obj.to_ary
|
|
7
7
|
|
|
8
|
+
If `to_ary` raises a `NoMethodError`, Ruby sees that the object can not be coerced
|
|
9
|
+
into an array and moves on to the next object.
|
|
10
|
+
|
|
8
11
|
To support this, an RSpec double will raise a NoMethodError when it receives
|
|
9
|
-
`to_ary
|
|
12
|
+
`to_ary` _even if it is set `as_null_object`_, unless `to_ary` is explicitly
|
|
13
|
+
stubbed.
|
|
10
14
|
|
|
11
15
|
Scenario: double receiving to_ary
|
|
12
16
|
Given a file named "example.rb" with:
|
|
13
17
|
"""
|
|
14
|
-
describe "
|
|
18
|
+
describe "#to_ary" do
|
|
15
19
|
shared_examples "to_ary" do
|
|
16
|
-
it "
|
|
17
|
-
expect
|
|
18
|
-
obj.to_ary.should be_nil
|
|
19
|
-
end.to raise_error(NoMethodError)
|
|
20
|
+
it "raises a NoMethodError" do
|
|
21
|
+
expect { obj.to_ary }.to raise_error(NoMethodError)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
it "can be overridden with a stub" do
|
|
@@ -30,12 +32,12 @@ Feature: double handling to_ary
|
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
context "double as_null_object" do
|
|
35
|
+
context "sent to a double as_null_object" do
|
|
34
36
|
let(:obj) { double('obj').as_null_object }
|
|
35
37
|
include_examples "to_ary"
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
context "double without as_null_object" do
|
|
40
|
+
context "sent to a double without as_null_object" do
|
|
39
41
|
let(:obj) { double('obj') }
|
|
40
42
|
include_examples "to_ary"
|
|
41
43
|
end
|
data/features/support/env.rb
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class Chain
|
|
5
|
+
[
|
|
6
|
+
:with, :and_return, :and_raise, :and_yield,
|
|
7
|
+
:once, :twice, :any_number_of_times,
|
|
8
|
+
:exactly, :times, :never,
|
|
9
|
+
:at_least, :at_most
|
|
10
|
+
].each do |method_name|
|
|
11
|
+
class_eval(<<-EOM, __FILE__, __LINE__)
|
|
12
|
+
def #{method_name}(*args, &block)
|
|
13
|
+
record(:#{method_name}, *args, &block)
|
|
14
|
+
end
|
|
15
|
+
EOM
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def playback!(instance)
|
|
19
|
+
messages.inject(instance) do |_instance, message|
|
|
20
|
+
_instance.__send__(*message.first, &message.last)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def constrained_to_any_of?(*constraints)
|
|
25
|
+
constraints.any? do |constraint|
|
|
26
|
+
messages.any? do |message|
|
|
27
|
+
message.first.first == constraint
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def messages
|
|
34
|
+
@messages ||= []
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def last_message
|
|
38
|
+
messages.last.first.first unless messages.empty?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def record(rspec_method_name, *args, &block)
|
|
42
|
+
verify_invocation_order(rspec_method_name, *args, &block)
|
|
43
|
+
messages << [args.unshift(rspec_method_name), block]
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class ExpectationChain < Chain
|
|
5
|
+
def initialize(*args, &block)
|
|
6
|
+
record(:should_receive, *args, &block)
|
|
7
|
+
@expectation_fulfilled = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def invocation_order
|
|
11
|
+
@invocation_order ||= {
|
|
12
|
+
:should_receive => [nil],
|
|
13
|
+
:with => [:should_receive],
|
|
14
|
+
:and_return => [:with, :should_receive],
|
|
15
|
+
:and_raise => [:with, :should_receive]
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def expectation_fulfilled!
|
|
20
|
+
@expectation_fulfilled = true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def expectation_fulfilled?
|
|
24
|
+
@expectation_fulfilled || constrained_to_any_of?(:never, :any_number_of_times)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class MessageChains < Hash
|
|
5
|
+
def add(method_name, chain)
|
|
6
|
+
(self[method_name] ||= []) << chain
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def remove_stub_chains_for!(method_name)
|
|
10
|
+
chains = self[method_name]
|
|
11
|
+
chains.reject! { |chain| chain.is_a?(StubChain) || chain.is_a?(StubChainChain) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def has_expectation?(method_name)
|
|
15
|
+
!!self[method_name].find{|chain| chain.is_a?(ExpectationChain)}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def each_expectation_fulfilled?
|
|
19
|
+
self.all? do |method_name, chains|
|
|
20
|
+
chains.all? { |chain| chain.expectation_fulfilled? }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def unfulfilled_expectations
|
|
25
|
+
self.map do |method_name, chains|
|
|
26
|
+
method_name.to_s if chains.last.is_a?(ExpectationChain) unless chains.last.expectation_fulfilled?
|
|
27
|
+
end.compact
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def received_expected_message!(method_name)
|
|
31
|
+
self[method_name].each do |chain|
|
|
32
|
+
chain.expectation_fulfilled!
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def playback!(instance, method_name)
|
|
37
|
+
self[method_name].each do |chain|
|
|
38
|
+
@instance_with_expectation = instance if instance.is_a?(ExpectationChain) && !@instance_with_expectation
|
|
39
|
+
if instance.is_a?(ExpectationChain) && !@instance_with_expectation.equal?(instance)
|
|
40
|
+
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
|
|
41
|
+
end
|
|
42
|
+
chain.playback!(instance)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class Recorder
|
|
5
|
+
attr_reader :message_chains
|
|
6
|
+
def initialize(klass)
|
|
7
|
+
@message_chains = MessageChains.new
|
|
8
|
+
@observed_methods = []
|
|
9
|
+
@played_methods = {}
|
|
10
|
+
@klass = klass
|
|
11
|
+
@expectation_set = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def unstub(method_name)
|
|
15
|
+
unless @observed_methods.include?(method_name.to_sym)
|
|
16
|
+
raise RSpec::Mocks::MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
|
|
17
|
+
end
|
|
18
|
+
message_chains.remove_stub_chains_for!(method_name)
|
|
19
|
+
stop_observing!(method_name) unless message_chains.has_expectation?(method_name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def stub(method_name_or_method_map, *args, &block)
|
|
23
|
+
if method_name_or_method_map.is_a?(Hash)
|
|
24
|
+
method_map = method_name_or_method_map
|
|
25
|
+
method_map.each do |method_name, return_value|
|
|
26
|
+
observe!(method_name)
|
|
27
|
+
message_chains.add(method_name, chain = StubChain.new(method_name))
|
|
28
|
+
chain.and_return(return_value)
|
|
29
|
+
end
|
|
30
|
+
method_map
|
|
31
|
+
else
|
|
32
|
+
method_name = method_name_or_method_map
|
|
33
|
+
observe!(method_name)
|
|
34
|
+
message_chains.add(method_name, chain = StubChain.new(method_name, *args, &block))
|
|
35
|
+
chain
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def stub!(*)
|
|
40
|
+
raise "stub! is not supported on any_instance. Use stub instead."
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def stub_chain(method_name_or_string_chain, *args, &block)
|
|
44
|
+
if period_separated_method_chain?(method_name_or_string_chain)
|
|
45
|
+
first_method_name = method_name_or_string_chain.split('.').first.to_sym
|
|
46
|
+
else
|
|
47
|
+
first_method_name = method_name_or_string_chain
|
|
48
|
+
end
|
|
49
|
+
observe!(first_method_name)
|
|
50
|
+
message_chains.add(first_method_name, chain = StubChainChain.new(method_name_or_string_chain, *args, &block))
|
|
51
|
+
chain
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def should_receive(method_name, *args, &block)
|
|
55
|
+
observe!(method_name)
|
|
56
|
+
@expectation_set = true
|
|
57
|
+
message_chains.add(method_name, chain = ExpectationChain.new(method_name, *args, &block))
|
|
58
|
+
chain
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def stop_all_observation!
|
|
62
|
+
@observed_methods.each do |method_name|
|
|
63
|
+
restore_method!(method_name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def playback!(instance, method_name)
|
|
68
|
+
RSpec::Mocks::space.add(instance)
|
|
69
|
+
message_chains.playback!(instance, method_name)
|
|
70
|
+
@played_methods[method_name] = instance
|
|
71
|
+
received_expected_message!(method_name) if message_chains.has_expectation?(method_name)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def instance_that_received(method_name)
|
|
75
|
+
@played_methods[method_name]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def verify
|
|
79
|
+
if @expectation_set && !message_chains.each_expectation_fulfilled?
|
|
80
|
+
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
def period_separated_method_chain?(method_name)
|
|
86
|
+
method_name.is_a?(String) && method_name.include?('.')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def received_expected_message!(method_name)
|
|
90
|
+
message_chains.received_expected_message!(method_name)
|
|
91
|
+
restore_method!(method_name)
|
|
92
|
+
mark_invoked!(method_name)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def restore_method!(method_name)
|
|
96
|
+
if public_protected_or_private_method_defined?(build_alias_method_name(method_name))
|
|
97
|
+
restore_original_method!(method_name)
|
|
98
|
+
else
|
|
99
|
+
remove_dummy_method!(method_name)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def build_alias_method_name(method_name)
|
|
104
|
+
"__#{method_name}_without_any_instance__"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def restore_original_method!(method_name)
|
|
108
|
+
alias_method_name = build_alias_method_name(method_name)
|
|
109
|
+
@klass.class_eval do
|
|
110
|
+
remove_method method_name
|
|
111
|
+
alias_method method_name, alias_method_name
|
|
112
|
+
remove_method alias_method_name
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def remove_dummy_method!(method_name)
|
|
117
|
+
@klass.class_eval do
|
|
118
|
+
remove_method method_name
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def backup_method!(method_name)
|
|
123
|
+
alias_method_name = build_alias_method_name(method_name)
|
|
124
|
+
@klass.class_eval do
|
|
125
|
+
alias_method alias_method_name, method_name
|
|
126
|
+
end if public_protected_or_private_method_defined?(method_name)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def public_protected_or_private_method_defined?(method_name)
|
|
130
|
+
@klass.method_defined?(method_name) || @klass.private_method_defined?(method_name)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def stop_observing!(method_name)
|
|
134
|
+
restore_method!(method_name)
|
|
135
|
+
@observed_methods.delete(method_name)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def already_observing?(method_name)
|
|
139
|
+
@observed_methods.include?(method_name)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def observe!(method_name)
|
|
143
|
+
stop_observing!(method_name) if already_observing?(method_name)
|
|
144
|
+
@observed_methods << method_name
|
|
145
|
+
backup_method!(method_name)
|
|
146
|
+
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
|
|
147
|
+
def #{method_name}(*args, &blk)
|
|
148
|
+
self.class.__recorder.playback!(self, :#{method_name})
|
|
149
|
+
self.__send__(:#{method_name}, *args, &blk)
|
|
150
|
+
end
|
|
151
|
+
EOM
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def mark_invoked!(method_name)
|
|
155
|
+
backup_method!(method_name)
|
|
156
|
+
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
|
|
157
|
+
def #{method_name}(*args, &blk)
|
|
158
|
+
method_name = :#{method_name}
|
|
159
|
+
current_instance = self
|
|
160
|
+
invoked_instance = self.class.__recorder.instance_that_received(method_name)
|
|
161
|
+
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
|
|
162
|
+
end
|
|
163
|
+
EOM
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class StubChain < Chain
|
|
5
|
+
def initialize(*args, &block)
|
|
6
|
+
record(:stub, *args, &block)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def invocation_order
|
|
10
|
+
@invocation_order ||= {
|
|
11
|
+
:stub => [nil],
|
|
12
|
+
:with => [:stub],
|
|
13
|
+
:and_return => [:with, :stub],
|
|
14
|
+
:and_raise => [:with, :stub],
|
|
15
|
+
:and_yield => [:with, :stub]
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def expectation_fulfilled?
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def expectation_fulfilled!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
28
|
+
unless invocation_order[rspec_method_name].include?(last_message)
|
|
29
|
+
raise(NoMethodError, "Undefined method #{rspec_method_name}")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class StubChainChain < Chain
|
|
5
|
+
def initialize(*args, &block)
|
|
6
|
+
record(:stub_chain, *args, &block)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def invocation_order
|
|
10
|
+
@invocation_order ||= {
|
|
11
|
+
:stub_chain => [nil],
|
|
12
|
+
:and_return => [:stub_chain],
|
|
13
|
+
:and_raise => [:stub_chain],
|
|
14
|
+
:and_yield => [:stub_chain]
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def expectation_fulfilled?
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def expectation_fulfilled!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
27
|
+
unless invocation_order[rspec_method_name].include?(last_message)
|
|
28
|
+
raise(NoMethodError, "Undefined method #{rspec_method_name}")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|