rspec-mocks 2.99.4 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +1 -0
  4. data/Changelog.md +89 -105
  5. data/License.txt +1 -0
  6. data/README.md +77 -57
  7. data/features/argument_matchers/explicit.feature +5 -5
  8. data/features/argument_matchers/general_matchers.feature +10 -10
  9. data/features/argument_matchers/type_matchers.feature +3 -3
  10. data/features/message_expectations/allow_any_instance_of.feature +1 -1
  11. data/features/message_expectations/any_instance.feature +27 -5
  12. data/features/message_expectations/call_original.feature +2 -2
  13. data/features/message_expectations/expect_message_using_expect.feature +2 -2
  14. data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
  15. data/features/message_expectations/receive_counts.feature +7 -7
  16. data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
  17. data/features/method_stubs/README.md +3 -0
  18. data/features/method_stubs/any_instance.feature +11 -11
  19. data/features/method_stubs/as_null_object.feature +4 -4
  20. data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
  21. data/features/method_stubs/stub_chain.feature +3 -3
  22. data/features/method_stubs/stub_implementation.feature +2 -2
  23. data/features/method_stubs/to_ary.feature +2 -2
  24. data/features/mutating_constants/hiding_defined_constant.feature +2 -2
  25. data/features/mutating_constants/stub_defined_constant.feature +5 -5
  26. data/features/mutating_constants/stub_undefined_constant.feature +6 -6
  27. data/features/outside_rspec/configuration.feature +0 -2
  28. data/features/outside_rspec/standalone.feature +1 -1
  29. data/features/spies/spy_partial_mock_method.feature +2 -2
  30. data/features/spies/spy_pure_mock_method.feature +5 -5
  31. data/features/spies/spy_unstubbed_method.feature +1 -1
  32. data/features/support/env.rb +10 -1
  33. data/features/test_frameworks/test_unit.feature +1 -1
  34. data/features/verifying_doubles/class_doubles.feature +88 -0
  35. data/features/verifying_doubles/dynamic_classes.feature +72 -0
  36. data/features/verifying_doubles/introduction.feature +85 -0
  37. data/features/verifying_doubles/object_doubles.feature +65 -0
  38. data/features/verifying_doubles/partial_doubles.feature +34 -0
  39. data/lib/rspec/mocks.rb +8 -34
  40. data/lib/rspec/mocks/any_instance/chain.rb +4 -34
  41. data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
  42. data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
  43. data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
  44. data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
  45. data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
  46. data/lib/rspec/mocks/argument_matchers.rb +26 -12
  47. data/lib/rspec/mocks/arity_calculator.rb +66 -0
  48. data/lib/rspec/mocks/configuration.rb +42 -14
  49. data/lib/rspec/mocks/error_generator.rb +34 -10
  50. data/lib/rspec/mocks/example_methods.rb +64 -19
  51. data/lib/rspec/mocks/extensions/marshal.rb +0 -15
  52. data/lib/rspec/mocks/framework.rb +4 -4
  53. data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
  54. data/lib/rspec/mocks/matchers/have_received.rb +18 -14
  55. data/lib/rspec/mocks/matchers/receive.rb +29 -7
  56. data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  57. data/lib/rspec/mocks/message_expectation.rb +95 -148
  58. data/lib/rspec/mocks/method_double.rb +77 -139
  59. data/lib/rspec/mocks/method_reference.rb +95 -0
  60. data/lib/rspec/mocks/mock.rb +1 -1
  61. data/lib/rspec/mocks/mutate_const.rb +12 -9
  62. data/lib/rspec/mocks/object_reference.rb +90 -0
  63. data/lib/rspec/mocks/order_group.rb +49 -7
  64. data/lib/rspec/mocks/proxy.rb +72 -33
  65. data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
  66. data/lib/rspec/mocks/space.rb +13 -18
  67. data/lib/rspec/mocks/stub_chain.rb +2 -2
  68. data/lib/rspec/mocks/syntax.rb +61 -36
  69. data/lib/rspec/mocks/targets.rb +40 -19
  70. data/lib/rspec/mocks/test_double.rb +12 -56
  71. data/lib/rspec/mocks/verifying_double.rb +77 -0
  72. data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  73. data/lib/rspec/mocks/verifying_proxy.rb +151 -0
  74. data/lib/rspec/mocks/version.rb +1 -1
  75. data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
  76. data/spec/rspec/mocks/and_yield_spec.rb +2 -2
  77. data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
  78. data/spec/rspec/mocks/any_instance_spec.rb +53 -260
  79. data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
  80. data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
  81. data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
  82. data/spec/rspec/mocks/at_least_spec.rb +4 -32
  83. data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
  84. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
  85. data/spec/rspec/mocks/configuration_spec.rb +79 -0
  86. data/spec/rspec/mocks/double_spec.rb +10 -78
  87. data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
  88. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
  89. data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
  90. data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
  91. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
  92. data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
  93. data/spec/rspec/mocks/methods_spec.rb +1 -1
  94. data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
  95. data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
  96. data/spec/rspec/mocks/mock_space_spec.rb +10 -1
  97. data/spec/rspec/mocks/mock_spec.rb +26 -82
  98. data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
  99. data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
  100. data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
  101. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  102. data/spec/rspec/mocks/order_group_spec.rb +27 -0
  103. data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
  104. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
  105. data/spec/rspec/mocks/record_messages_spec.rb +4 -4
  106. data/spec/rspec/mocks/serialization_spec.rb +4 -6
  107. data/spec/rspec/mocks/space_spec.rb +3 -3
  108. data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
  109. data/spec/rspec/mocks/stub_spec.rb +23 -44
  110. data/spec/rspec/mocks/test_double_spec.rb +3 -22
  111. data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
  112. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
  113. data/spec/rspec/mocks_spec.rb +16 -39
  114. data/spec/spec_helper.rb +29 -18
  115. metadata +131 -86
  116. metadata.gz.sig +1 -0
  117. data/features/message_expectations/expect_any_instance_of.feature +0 -27
  118. data/lib/rspec/mocks/caller_filter.rb +0 -60
  119. data/lib/rspec/mocks/deprecation.rb +0 -26
  120. data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
  121. data/lib/rspec/mocks/extensions/proc.rb +0 -63
  122. data/lib/spec/mocks.rb +0 -4
  123. data/spec/rspec/mocks/and_return_spec.rb +0 -17
  124. data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
  125. data/spec/rspec/mocks/before_all_spec.rb +0 -74
  126. data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
  127. data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
  128. data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
  129. data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
  130. data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
  131. data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
  132. data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
  133. data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -0,0 +1,60 @@
1
+ require 'rspec/mocks/arity_calculator'
2
+
3
+ module RSpec
4
+ module Mocks
5
+
6
+ # A message expectation that knows about the real implementation of the
7
+ # message being expected, so that it can verify that any expectations
8
+ # have the correct arity.
9
+ class VerifyingMessageExpectation < MessageExpectation
10
+
11
+ # A level of indirection is used here rather than just passing in the
12
+ # method itself, since method look up is expensive and we only want to
13
+ # do it if actually needed.
14
+ #
15
+ # Conceptually the method reference makes more sense as a constructor
16
+ # argument since it should be immutable, but it is significantly more
17
+ # straight forward to build the object in pieces so for now it stays as
18
+ # an accessor.
19
+ attr_accessor :method_reference
20
+
21
+ def initialize(*args)
22
+ super
23
+ end
24
+
25
+ # @override
26
+ def with(*args, &block)
27
+ unless ArgumentMatchers::AnyArgsMatcher === args.first
28
+ expected_arity = if ArgumentMatchers::NoArgsMatcher === args.first
29
+ 0
30
+ elsif args.length > 0
31
+ args.length
32
+ else
33
+ # No arguments given, this will raise.
34
+ super
35
+ end
36
+
37
+ ensure_arity!(expected_arity)
38
+ end
39
+ super
40
+ end
41
+
42
+ private
43
+
44
+ def ensure_arity!(actual)
45
+ return if method_reference.nil?
46
+
47
+ method_reference.when_defined do |method|
48
+ calculator = ArityCalculator.new(method)
49
+ unless calculator.within_range?(actual)
50
+ # Fail fast is required, otherwise the message expecation will fail
51
+ # as well ("expected method not called") and clobber this one.
52
+ @failed_fast = true
53
+ @error_generator.raise_arity_error(calculator, actual)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,151 @@
1
+ require 'rspec/mocks/verifying_message_expecation'
2
+ require 'rspec/mocks/method_reference'
3
+
4
+ module RSpec
5
+ module Mocks
6
+
7
+ module VerifyingProxyMethods
8
+ def add_stub(location, method_name, opts={}, &implementation)
9
+ ensure_implemented(method_name)
10
+ super
11
+ end
12
+
13
+ def add_simple_stub(method_name, *args)
14
+ ensure_implemented(method_name)
15
+ super
16
+ end
17
+
18
+ def add_message_expectation(location, method_name, opts={}, &block)
19
+ ensure_implemented(method_name)
20
+ super
21
+ end
22
+
23
+ def ensure_implemented(method_name)
24
+ return unless @doubled_module.defined?
25
+
26
+ method_reference[method_name].when_unimplemented do
27
+ @error_generator.raise_unimplemented_error(
28
+ @doubled_module,
29
+ method_name
30
+ )
31
+ end
32
+ end
33
+ end
34
+
35
+ # A verifying proxy mostly acts like a normal proxy, except that it
36
+ # contains extra logic to try and determine the validity of any expectation
37
+ # set on it. This includes whether or not methods have been defined and the
38
+ # arity of method calls.
39
+ #
40
+ # In all other ways this behaves like a normal proxy. It only adds the
41
+ # verification behaviour to specific methods then delegates to the parent
42
+ # implementation.
43
+ #
44
+ # These checks are only activated if the doubled class has already been
45
+ # loaded, otherwise they are disabled. This allows for testing in
46
+ # isolation.
47
+ #
48
+ # @api private
49
+ class VerifyingProxy < Proxy
50
+ include VerifyingProxyMethods
51
+
52
+ def initialize(object, order_group, name, method_reference_class)
53
+ super(object, order_group)
54
+ @object = object
55
+ @doubled_module = name
56
+ @method_reference_class = method_reference_class
57
+
58
+ # A custom method double is required to pass through a way to lookup
59
+ # methods to determine their arity. This is only relevant if the doubled
60
+ # class is loaded.
61
+ @method_doubles = Hash.new do |h, k|
62
+ h[k] = VerifyingMethodDouble.new(@object, k, self, method_reference[k])
63
+ end
64
+ end
65
+
66
+ def method_reference
67
+ @method_reference ||= Hash.new do |h, k|
68
+ h[k] = @method_reference_class.new(@doubled_module, k)
69
+ end
70
+ end
71
+ end
72
+
73
+ class VerifyingPartialMockProxy < PartialMockProxy
74
+ include VerifyingProxyMethods
75
+
76
+ def initialize(object, expectation_ordering)
77
+ super(object, expectation_ordering)
78
+ @doubled_module = DirectObjectReference.new(object)
79
+
80
+ # A custom method double is required to pass through a way to lookup
81
+ # methods to determine their arity.
82
+ @method_doubles = Hash.new do |h, k|
83
+ h[k] = VerifyingExistingMethodDouble.new(object, k, self)
84
+ end
85
+ end
86
+
87
+ def method_reference
88
+ @method_doubles
89
+ end
90
+ end
91
+
92
+ # @api private
93
+ class VerifyingMethodDouble < MethodDouble
94
+ def initialize(object, method_name, proxy, method_reference)
95
+ super(object, method_name, proxy)
96
+ @method_reference = method_reference
97
+ end
98
+
99
+ def message_expectation_class
100
+ VerifyingMessageExpectation
101
+ end
102
+
103
+ def add_expectation(*arg)
104
+ super.tap { |x| x.method_reference = @method_reference }
105
+ end
106
+
107
+ def proxy_method_invoked(obj, *args, &block)
108
+ ensure_arity!(args.length)
109
+ super
110
+ end
111
+
112
+ private
113
+
114
+ def ensure_arity!(arity)
115
+ @method_reference.when_defined do |method|
116
+ calculator = ArityCalculator.new(method)
117
+ unless calculator.within_range?(arity)
118
+ raise ArgumentError, "wrong number of arguments (#{arity} for #{method.arity})"
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ # @api private
125
+ #
126
+ # A VerifyingMethodDouble fetches the method to verify against from the
127
+ # original object, using a MethodReference. This works for pure doubles,
128
+ # but when the original object is itself the one being modified we need to
129
+ # collapse the reference and the method double into a single object so that
130
+ # we can access the original pristine method definition.
131
+ class VerifyingExistingMethodDouble < VerifyingMethodDouble
132
+ def initialize(object, method_name, proxy)
133
+ super(object, method_name, proxy, self)
134
+
135
+ @valid_method = object.respond_to?(method_name)
136
+
137
+ # Trigger an eager find of the original method since if we find it any
138
+ # later we end up getting a stubbed method with incorrect arity.
139
+ save_original_method!
140
+ end
141
+
142
+ def when_defined
143
+ yield original_method
144
+ end
145
+
146
+ def when_unimplemented
147
+ yield unless @valid_method
148
+ end
149
+ end
150
+ end
151
+ end
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Mocks
3
3
  module Version
4
- STRING = '2.99.4'
4
+ STRING = '3.0.0.beta1'
5
5
  end
6
6
  end
7
7
  end
@@ -22,24 +22,36 @@ describe "and_call_original" do
22
22
  let(:instance) { klass.new }
23
23
 
24
24
  it 'passes the received message through to the original method' do
25
+ expect(instance).to receive(:meth_1).and_call_original
26
+ expect(instance.meth_1).to eq(:original)
27
+ end
28
+
29
+ it 'ignores prior declared stubs' do
30
+ instance.stub(:meth_1).and_return(:stubbed_value)
25
31
  instance.should_receive(:meth_1).and_call_original
26
32
  expect(instance.meth_1).to eq(:original)
27
33
  end
28
34
 
29
35
  it 'passes args and blocks through to the original method' do
30
- instance.should_receive(:meth_2).and_call_original
36
+ expect(instance).to receive(:meth_2).and_call_original
31
37
  value = instance.meth_2(:submitted_arg) { |a, b| [a, b] }
32
38
  expect(value).to eq([:submitted_arg, :additional_yielded_arg])
33
39
  end
34
40
 
35
41
  it 'errors when you pass through the wrong number of args' do
36
- instance.stub(:meth_1).and_call_original
37
- instance.stub(:meth_2).and_call_original
42
+ expect(instance).to receive(:meth_1).and_call_original
43
+ expect(instance).to receive(:meth_2).twice.and_call_original
38
44
  expect { instance.meth_1 :a }.to raise_error ArgumentError
39
45
  expect { instance.meth_2 {} }.to raise_error ArgumentError
40
46
  expect { instance.meth_2(:a, :b) {} }.to raise_error ArgumentError
41
47
  end
42
48
 
49
+ it 'warns when you override an existing implementation' do
50
+ expect(RSpec).to receive(:warning).with(/overriding a previous implementation/)
51
+ expect(instance).to receive(:meth_1) { true }.and_call_original
52
+ instance.meth_1
53
+ end
54
+
43
55
  context "for singleton methods" do
44
56
  it 'works' do
45
57
  def instance.foo; :bar; end
@@ -77,6 +89,15 @@ describe "and_call_original" do
77
89
  expect(sub_klass.foo).to eq(:sub_klass_bar)
78
90
  end
79
91
 
92
+ it "finds the method on the most direct singleton class ancestors even if the method " +
93
+ "is available on more distant ancestors" do
94
+ klass.extend Module.new { def foo; :klass_bar; end }
95
+ sub_klass = Class.new(klass) { def self.foo; :sub_klass_bar; end }
96
+ sub_sub_klass = Class.new(sub_klass)
97
+ sub_sub_klass.should_receive(:foo).and_call_original
98
+ expect(sub_sub_klass.foo).to eq(:sub_klass_bar)
99
+ end
100
+
80
101
  context 'when using any_instance' do
81
102
  it 'works for instance methods defined on the class' do
82
103
  klass.any_instance.should_receive(:meth_1).and_call_original
@@ -95,33 +116,16 @@ describe "and_call_original" do
95
116
  end
96
117
  end
97
118
 
98
- if RUBY_VERSION.to_f > 1.8
99
- it 'works for class methods defined on a superclass' do
100
- subclass = Class.new(klass)
101
- subclass.should_receive(:new_instance).and_call_original
102
- expect(subclass.new_instance).to be_a(subclass)
103
- end
104
-
105
- it 'works for class methods defined on a grandparent class' do
106
- sub_subclass = Class.new(Class.new(klass))
107
- sub_subclass.should_receive(:new_instance).and_call_original
108
- expect(sub_subclass.new_instance).to be_a(sub_subclass)
109
- end
110
- else
111
- it 'attempts to work for class methods defined on a superclass but ' +
112
- 'executes the method with `self` as the superclass' do
113
- ::Kernel.stub(:warn)
114
- subclass = Class.new(klass)
115
- subclass.should_receive(:new_instance).and_call_original
116
- expect(subclass.new_instance).to be_an_instance_of(klass)
117
- end
119
+ it 'works for class methods defined on a superclass' do
120
+ subclass = Class.new(klass)
121
+ subclass.should_receive(:new_instance).and_call_original
122
+ expect(subclass.new_instance).to be_a(subclass)
123
+ end
118
124
 
119
- it 'prints a warning to notify users that `self` will not be correct' do
120
- subclass = Class.new(klass)
121
- ::Kernel.should_receive(:warn).with(/may not work correctly/)
122
- subclass.should_receive(:new_instance).and_call_original
123
- subclass.new_instance
124
- end
125
+ it 'works for class methods defined on a grandparent class' do
126
+ sub_subclass = Class.new(Class.new(klass))
127
+ sub_subclass.should_receive(:new_instance).and_call_original
128
+ expect(sub_subclass.new_instance).to be_a(sub_subclass)
125
129
  end
126
130
 
127
131
  it 'works for class methods defined on the Class class' do
@@ -149,7 +153,7 @@ describe "and_call_original" do
149
153
 
150
154
  context 'on an object that defines method_missing' do
151
155
  before do
152
- klass.class_eval do
156
+ klass.class_exec do
153
157
  private
154
158
 
155
159
  def method_missing(name, *args)
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RSpec::Mocks::Double do
3
+ describe RSpec::Mocks::Mock do
4
4
 
5
5
  let(:obj) { double }
6
6
 
@@ -25,7 +25,7 @@ describe RSpec::Mocks::Double do
25
25
  obj.stub(:method_that_accepts_a_block).and_yield do |eval_context|
26
26
  evaluated = true
27
27
  end
28
- expect(evaluated).to be true
28
+ expect(evaluated).to be_truthy
29
29
  end
30
30
 
31
31
  it "passes an eval context object to the supplied block" do
@@ -4,7 +4,7 @@ describe RSpec::Mocks::AnyInstance::MessageChains do
4
4
  let(:recorder) { double }
5
5
  let(:chains) { RSpec::Mocks::AnyInstance::MessageChains.new }
6
6
  let(:stub_chain) { RSpec::Mocks::AnyInstance::StubChain.new recorder }
7
- let(:expectation_chain) { RSpec::Mocks::AnyInstance::ExpectationChain.new recorder }
7
+ let(:expectation_chain) { RSpec::Mocks::AnyInstance::PositiveExpectationChain.new recorder }
8
8
 
9
9
  it "knows if a method does not have an expectation set on it" do
10
10
  chains.add(:method_name, stub_chain)
@@ -37,7 +37,7 @@ module RSpec
37
37
  end
38
38
 
39
39
  context "#stub_chain" do
40
- it "raises an error if 'stub_chain' follows 'any_instance'" do
40
+ it "raises an error if 'stub_chain' follows 'and_return'" do
41
41
  expect { klass.any_instance.and_return("1").stub_chain(:foo, :bar) }.to raise_error(NoMethodError)
42
42
  end
43
43
  end
@@ -48,12 +48,12 @@ module RSpec
48
48
  end
49
49
 
50
50
  it "raises an error if 'with' follows 'and_return'" do
51
- skip "see Github issue #42"
51
+ pending "see Github issue #42"
52
52
  expect { klass.any_instance.should_receive(:foo).and_return(1).with("1") }.to raise_error(NoMethodError)
53
53
  end
54
54
 
55
55
  it "raises an error if 'with' follows 'and_raise'" do
56
- skip "see Github issue #42"
56
+ pending "see Github issue #42"
57
57
  expect { klass.any_instance.should_receive(:foo).and_raise(1).with("1") }.to raise_error(NoMethodError)
58
58
  end
59
59
  end
@@ -214,8 +214,6 @@ module RSpec
214
214
  end
215
215
 
216
216
  context "with a block" do
217
- before { allow_unavoidable_1_8_deprecation }
218
-
219
217
  it "stubs a method" do
220
218
  klass.any_instance.stub(:foo) { 1 }
221
219
  expect(klass.new.foo).to eq(1)
@@ -227,6 +225,24 @@ module RSpec
227
225
  end
228
226
  end
229
227
 
228
+ context "when partially mocking objects" do
229
+ let(:obj) { klass.new }
230
+
231
+ it "resets partially mocked objects correctly" do
232
+ allow_any_instance_of(klass).to receive(:existing_method).and_return("stubbed value")
233
+
234
+ # Simply resetting the proxy doesn't work
235
+ # what we need to have happen is
236
+ # ::RSpec::Mocks.any_instance_recorder_for(klass).stop_all_observation!
237
+ # but that is never invoked in ::
238
+ expect {
239
+ RSpec::Mocks.space.verify_all
240
+ }.to(
241
+ change { obj.existing_method }.from("stubbed value").to(:existing_method_return_value)
242
+ )
243
+ end
244
+ end
245
+
230
246
  context "core ruby objects" do
231
247
  it "works uniformly across *everything*" do
232
248
  Object.any_instance.stub(:foo).and_return(1)
@@ -267,22 +283,6 @@ module RSpec
267
283
  end
268
284
  end
269
285
 
270
- context "with #stub!" do
271
- it "raises with a message instructing the user to use stub instead" do
272
- expect do
273
- klass.any_instance.stub!(:foo)
274
- end.to raise_error(/Use stub instead/)
275
- end
276
- end
277
-
278
- context "with #unstub!" do
279
- it "raises with a message instructing the user to use unstub instead" do
280
- expect do
281
- klass.any_instance.unstub!(:foo)
282
- end.to raise_error(/Use unstub instead/)
283
- end
284
- end
285
-
286
286
  context "unstub implementation" do
287
287
  it "replaces the stubbed method with the original method" do
288
288
  klass.any_instance.stub(:existing_method)
@@ -377,7 +377,6 @@ module RSpec
377
377
  klass.any_instance.should_not_receive(:bar)
378
378
  klass.new.foo
379
379
  RSpec::Mocks.space.verify_all
380
- RSpec::Mocks.space.reset_all
381
380
  end
382
381
  end
383
382
 
@@ -400,36 +399,24 @@ module RSpec
400
399
 
401
400
  it "fails if an instance is created but no invocation occurs" do
402
401
  expect do
403
- begin
404
- klass.any_instance.should_receive(:foo)
405
- klass.new
406
- RSpec::Mocks.space.verify_all
407
- ensure
408
- RSpec::Mocks.space.reset_all
409
- end
402
+ klass.any_instance.should_receive(:foo)
403
+ klass.new
404
+ RSpec::Mocks.space.verify_all
410
405
  end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
411
406
  end
412
407
 
413
408
  it "fails if no instance is created" do
414
409
  expect do
415
- begin
416
- klass.any_instance.should_receive(:foo).and_return(1)
417
- RSpec::Mocks.space.verify_all
418
- ensure
419
- RSpec::Mocks.space.reset_all
420
- end
410
+ klass.any_instance.should_receive(:foo).and_return(1)
411
+ RSpec::Mocks.space.verify_all
421
412
  end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
422
413
  end
423
414
 
424
415
  it "fails if no instance is created and there are multiple expectations" do
425
416
  expect do
426
- begin
427
- klass.any_instance.should_receive(:foo)
428
- klass.any_instance.should_receive(:bar)
429
- RSpec::Mocks.space.verify_all
430
- ensure
431
- RSpec::Mocks.space.reset_all
432
- end
417
+ klass.any_instance.should_receive(:foo)
418
+ klass.any_instance.should_receive(:bar)
419
+ RSpec::Mocks.space.verify_all
433
420
  end.to raise_error(RSpec::Mocks::MockExpectationError, 'Exactly one instance should have received the following message(s) but didn\'t: bar, foo')
434
421
  end
435
422
 
@@ -491,36 +478,24 @@ module RSpec
491
478
 
492
479
  it "fails if an instance is created but no invocation occurs" do
493
480
  expect do
494
- begin
495
- klass.any_instance.should_receive(:existing_method)
496
- klass.new
497
- RSpec::Mocks.space.verify_all
498
- ensure
499
- RSpec::Mocks.space.reset_all
500
- end
481
+ klass.any_instance.should_receive(:existing_method)
482
+ klass.new
483
+ RSpec::Mocks.space.verify_all
501
484
  end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
502
485
  end
503
486
 
504
487
  it "fails if no instance is created" do
505
488
  expect do
506
- begin
507
- klass.any_instance.should_receive(:existing_method)
508
- RSpec::Mocks.space.verify_all
509
- ensure
510
- RSpec::Mocks.space.reset_all
511
- end
489
+ klass.any_instance.should_receive(:existing_method)
490
+ RSpec::Mocks.space.verify_all
512
491
  end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
513
492
  end
514
493
 
515
494
  it "fails if no instance is created and there are multiple expectations" do
516
495
  expect do
517
- begin
518
- klass.any_instance.should_receive(:existing_method)
519
- klass.any_instance.should_receive(:another_existing_method)
520
- RSpec::Mocks.space.verify_all
521
- ensure
522
- RSpec::Mocks.space.reset_all
523
- end
496
+ klass.any_instance.should_receive(:existing_method)
497
+ klass.any_instance.should_receive(:another_existing_method)
498
+ RSpec::Mocks.space.verify_all
524
499
  end.to raise_error(RSpec::Mocks::MockExpectationError, 'Exactly one instance should have received the following message(s) but didn\'t: another_existing_method, existing_method')
525
500
  end
526
501
 
@@ -613,24 +588,16 @@ module RSpec
613
588
 
614
589
  it "fails when no instances are declared" do
615
590
  expect do
616
- begin
617
- klass.any_instance.should_receive(:foo).once
618
- RSpec::Mocks.space.verify_all
619
- ensure
620
- RSpec::Mocks.space.reset_all
621
- end
591
+ klass.any_instance.should_receive(:foo).once
592
+ RSpec::Mocks.space.verify_all
622
593
  end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
623
594
  end
624
595
 
625
596
  it "fails when an instance is declared but there are no invocations" do
626
597
  expect do
627
- begin
628
- klass.any_instance.should_receive(:foo).once
629
- klass.new
630
- RSpec::Mocks.space.verify_all
631
- ensure
632
- RSpec::Mocks.space.reset_all
633
- end
598
+ klass.any_instance.should_receive(:foo).once
599
+ klass.new
600
+ RSpec::Mocks.space.verify_all
634
601
  end.to raise_error(RSpec::Mocks::MockExpectationError, foo_expectation_error_message)
635
602
  end
636
603
 
@@ -755,55 +722,9 @@ module RSpec
755
722
 
756
723
  it "fails when the other expecations are not met" do
757
724
  expect do
758
- begin
759
- klass.any_instance.should_receive(:foo).never
760
- klass.any_instance.should_receive(:existing_method).and_return(5)
761
- RSpec::Mocks.space.verify_all
762
- ensure
763
- RSpec::Mocks.space.reset_all
764
- end
765
- end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
766
- end
767
- end
768
- end
769
-
770
- context "the 'any_number_of_times' constraint" do
771
- it "passes for 0 invocations" do
772
- klass.any_instance.should_receive(:foo).any_number_of_times
773
- verify klass.new
774
- end
775
-
776
- it "passes for a non-zero number of invocations" do
777
- allow(RSpec).to receive(:deprecate).with("any_number_of_times", :replacement => "stub")
778
-
779
- klass.any_instance.should_receive(:foo).any_number_of_times
780
- instance = klass.new
781
- instance.foo
782
- verify instance
783
- end
784
-
785
- it "does not interfere with other expectations" do
786
- klass.any_instance.should_receive(:foo).any_number_of_times
787
- klass.any_instance.should_receive(:existing_method).and_return(5)
788
- expect(klass.new.existing_method).to eq(5)
789
- end
790
-
791
- context "when combined with other expectations" do
792
- it "passes when the other expecations are met" do
793
- klass.any_instance.should_receive(:foo).any_number_of_times
794
- klass.any_instance.should_receive(:existing_method).and_return(5)
795
- expect(klass.new.existing_method).to eq(5)
796
- end
797
-
798
- it "fails when the other expecations are not met" do
799
- expect do
800
- begin
801
- klass.any_instance.should_receive(:foo).any_number_of_times
802
- klass.any_instance.should_receive(:existing_method).and_return(5)
803
- RSpec::Mocks.space.verify_all
804
- ensure
805
- RSpec::Mocks.space.reset_all
806
- end
725
+ klass.any_instance.should_receive(:foo).never
726
+ klass.any_instance.should_receive(:existing_method).and_return(5)
727
+ RSpec::Mocks.space.verify_all
807
728
  end.to raise_error(RSpec::Mocks::MockExpectationError, existing_method_expectation_error_message)
808
729
  end
809
730
  end
@@ -823,14 +744,13 @@ module RSpec
823
744
  context "public methods" do
824
745
  before(:each) do
825
746
  klass.any_instance.stub(:existing_method).and_return(1)
826
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be true
747
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_truthy
827
748
  end
828
749
 
829
750
  it "restores the class to its original state after each example when no instance is created" do
830
751
  space.verify_all
831
- space.reset_all
832
752
 
833
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be false
753
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
834
754
  expect(klass.new.existing_method).to eq(existing_method_return_value)
835
755
  end
836
756
 
@@ -838,9 +758,8 @@ module RSpec
838
758
  klass.new.existing_method
839
759
 
840
760
  space.verify_all
841
- space.reset_all
842
761
 
843
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be false
762
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
844
763
  expect(klass.new.existing_method).to eq(existing_method_return_value)
845
764
  end
846
765
 
@@ -849,9 +768,8 @@ module RSpec
849
768
  klass.new.existing_method
850
769
 
851
770
  space.verify_all
852
- space.reset_all
853
771
 
854
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be false
772
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
855
773
  expect(klass.new.existing_method).to eq(existing_method_return_value)
856
774
  end
857
775
  end
@@ -860,15 +778,14 @@ module RSpec
860
778
  before :each do
861
779
  klass.any_instance.stub(:private_method).and_return(:something)
862
780
  space.verify_all
863
- space.reset_all
864
781
  end
865
782
 
866
783
  it "cleans up the backed up method" do
867
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be false
784
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
868
785
  end
869
786
 
870
787
  it "restores a stubbed private method after the spec is run" do
871
- expect(klass.private_method_defined?(:private_method)).to be true
788
+ expect(klass.private_method_defined?(:private_method)).to be_truthy
872
789
  end
873
790
 
874
791
  it "ensures that the restored method behaves as it originally did" do
@@ -883,15 +800,14 @@ module RSpec
883
800
  klass.any_instance.should_receive(:private_method).and_return(:something)
884
801
  klass.new.private_method
885
802
  space.verify_all
886
- space.reset_all
887
803
  end
888
804
 
889
805
  it "cleans up the backed up method" do
890
- expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be false
806
+ expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
891
807
  end
892
808
 
893
809
  it "restores a stubbed private method after the spec is run" do
894
- expect(klass.private_method_defined?(:private_method)).to be true
810
+ expect(klass.private_method_defined?(:private_method)).to be_truthy
895
811
  end
896
812
 
897
813
  it "ensures that the restored method behaves as it originally did" do
@@ -931,7 +847,6 @@ module RSpec
931
847
  klass.any_instance.should_receive(:existing_method).and_return(Object.new)
932
848
  klass.new.existing_method
933
849
  space.verify_all
934
- space.reset_all
935
850
 
936
851
  expect(klass.new.existing_method).to eq(existing_method_return_value)
937
852
  end
@@ -944,7 +859,6 @@ module RSpec
944
859
  klass.any_instance.stub(:existing_method).and_return(true)
945
860
 
946
861
  RSpec::Mocks.space.verify_all
947
- RSpec::Mocks.space.reset_all
948
862
  expect(klass.new).to respond_to(:existing_method)
949
863
  expect(klass.new.existing_method).to eq(existing_method_return_value)
950
864
  end
@@ -1034,126 +948,6 @@ module RSpec
1034
948
  end
1035
949
  end
1036
950
  end
1037
-
1038
- context "by default" do
1039
- def block_regex(line)
1040
- /as the first block argument.*#{__FILE__}:#{line}/m
1041
- end
1042
-
1043
- it "is off" do
1044
- expect(RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?).to be false
1045
- end
1046
-
1047
- it "will warn about allowances receiving blocks in 3.0" do
1048
- klass = Struct.new(:bees)
1049
-
1050
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1051
- allow_any_instance_of(klass).to receive(:foo) { |args| }
1052
- klass.new(:faces).foo
1053
- end
1054
-
1055
- it "will warn about expectations receiving blocks in 3.0" do
1056
- klass = Struct.new(:bees)
1057
-
1058
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1059
- expect_any_instance_of(klass).to receive(:foo) { |args| }
1060
- klass.new(:faces).foo
1061
- end
1062
-
1063
- it 'includes the line of the block declaration in the warning, ' +
1064
- 'even when it is different from the `any_instance` line', :unless => (RUBY_VERSION.to_f < 1.9) do
1065
- klass = Class.new
1066
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 3))
1067
- stub = klass.any_instance.stub(:foo)
1068
-
1069
- stub.with("bar") { |args| }
1070
- klass.new.foo("bar")
1071
- end
1072
-
1073
- it "will warn about expectations receiving blocks with a times restriction" do
1074
- klass = Struct.new(:bees)
1075
-
1076
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1077
- klass.any_instance.should_receive(:foo).exactly(3).times { |a| :some_return_value }
1078
-
1079
- instance = klass.new(:faces)
1080
- 3.times { instance.foo }
1081
- end
1082
-
1083
- it "will warn about expectations receiving blocks with an argument expectation" do
1084
- klass = Struct.new(:bees)
1085
-
1086
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1087
- klass.any_instance.should_receive(:foo).with(3) { |b| :some_return_value }
1088
-
1089
- instance = klass.new(:faces)
1090
- instance.foo(3)
1091
- end
1092
-
1093
- it "works with a do end style block" do
1094
- klass = Struct.new(:bees)
1095
-
1096
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1097
- klass.any_instance.should_receive(:foo).with(3) do |a|
1098
- :some_return_value
1099
- end
1100
-
1101
- instance = klass.new(:faces)
1102
- instance.foo(3)
1103
- end
1104
-
1105
- it "won't warn if there is no implementation block on an expectation" do
1106
- expect(RSpec).not_to receive(:warn_deprecation)
1107
-
1108
- klass = Struct.new(:bees)
1109
-
1110
- allow_any_instance_of(klass).to receive(:foo)
1111
- klass.new(:faces).foo
1112
- end
1113
-
1114
- it "won't warn if the implementation block ignores arguments", :if => (RUBY_VERSION.to_f > 1.8) do
1115
- expect(RSpec).not_to receive(:warn_deprecation)
1116
-
1117
- klass = Struct.new(:bees)
1118
- allow_any_instance_of(klass).to receive(:foo) { 5 }
1119
- klass.new(:faces).foo
1120
- end
1121
-
1122
- it "warns if the implementation block accepts a splat" do
1123
- klass = Struct.new(:bees)
1124
-
1125
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1126
- allow_any_instance_of(klass).to receive(:foo) { |*a| 5 }
1127
-
1128
- klass.new(:faces).foo
1129
- end
1130
-
1131
- it "warns if it the implementation is a lambda that expects no arguments" do
1132
- klass = Struct.new(:bees)
1133
-
1134
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1135
- allow_any_instance_of(klass).to receive(:foo, &lambda { 5 })
1136
-
1137
- klass.new(:faces).foo
1138
- end
1139
-
1140
- it "will warn about stubs receiving blocks in 3.0" do
1141
- klass = Struct.new(:bees)
1142
-
1143
- expect(RSpec).to receive(:warn_deprecation).with(block_regex(__LINE__ + 1))
1144
- expect_any_instance_of(klass).to receive(:foo) { |args| }
1145
- klass.new(:faces).foo
1146
- end
1147
-
1148
- it "won't warn if there is no implementation block on an stub" do
1149
- expect(RSpec).not_to receive(:warn_deprecation)
1150
-
1151
- klass = Struct.new(:bees)
1152
-
1153
- allow_any_instance_of(klass).to receive(:foo)
1154
- klass.new(:faces).foo
1155
- end
1156
- end
1157
951
  end
1158
952
 
1159
953
  context 'when used in conjunction with a `dup`' do
@@ -1226,7 +1020,6 @@ module RSpec
1226
1020
  expect(instance.existing_method).to eq :stubbed_return_value
1227
1021
 
1228
1022
  RSpec::Mocks.verify
1229
- RSpec::Mocks.teardown
1230
1023
 
1231
1024
  expect(instance.existing_method).to eq :existing_method_return_value
1232
1025
  end