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
@@ -85,6 +85,11 @@ module RSpec
85
85
  expect(configured_syntax).to eq([:should])
86
86
  end
87
87
 
88
+ it "does not warn about the should syntax" do
89
+ RSpec.should_not_receive(:deprecate)
90
+ Object.new.should_not_receive(:bees)
91
+ end
92
+
88
93
  it 'is a no-op when configured a second time' do
89
94
  Syntax.default_should_syntax_host.should_not_receive(:method_added)
90
95
  ::RSpec::Mocks::ExampleMethods.should_not_receive(:method_undefined)
@@ -110,6 +115,68 @@ module RSpec
110
115
  it 'reports that both syntaxes are enabled' do
111
116
  expect(configured_syntax).to eq([:should, :expect])
112
117
  end
118
+
119
+ it "does not warn about the should syntax" do
120
+ RSpec.should_not_receive(:deprecate)
121
+ Object.new.should_not_receive(:bees)
122
+ end
123
+ end
124
+
125
+ context "by default" do
126
+ before do
127
+ configure_default_syntax
128
+ end
129
+
130
+ let(:expected_arguments) {
131
+ [
132
+ /Using.*without explicitly enabling/,
133
+ {:replacement=>"the new `:expect` syntax or explicitly enable `:should`"}
134
+ ]
135
+ }
136
+
137
+ it "it warns about should once, regardless of how many times it is called" do
138
+ expect(RSpec).to receive(:deprecate).with(*expected_arguments)
139
+ o = Object.new
140
+ o2 = Object.new
141
+ o.should_receive(:bees)
142
+ o2.should_receive(:bees)
143
+
144
+ o.bees
145
+ o2.bees
146
+ end
147
+
148
+ it "warns about should not once, regardless of how many times it is called" do
149
+ expect(RSpec).to receive(:deprecate).with(*expected_arguments)
150
+ o = Object.new
151
+ o2 = Object.new
152
+ o.should_not_receive(:bees)
153
+ o2.should_not_receive(:bees)
154
+ end
155
+
156
+ it "warns about stubbing once, regardless of how many times it is called" do
157
+ expect(RSpec).to receive(:deprecate).with(*expected_arguments)
158
+ o = Object.new
159
+ o2 = Object.new
160
+
161
+ o.stub(:faces)
162
+ o2.stub(:faces)
163
+ end
164
+
165
+ it "doesn't warn about stubbing after a reset and setting should" do
166
+ expect(RSpec).not_to receive(:deprecate)
167
+ RSpec::Mocks.configuration.reset_syntaxes_to_default
168
+ RSpec::Mocks.configuration.syntax = :should
169
+ o = Object.new
170
+ o2 = Object.new
171
+ o.stub(:faces)
172
+ o2.stub(:faces)
173
+ end
174
+
175
+ it "includes the call site in the deprecation warning" do
176
+ obj = Object.new
177
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
178
+ obj.stub(:faces)
179
+ end
113
180
  end
114
181
  end
115
182
 
@@ -122,6 +189,10 @@ module RSpec
122
189
  def configured_syntax
123
190
  RSpec::Mocks.configuration.syntax
124
191
  end
192
+
193
+ def configure_default_syntax
194
+ RSpec::Mocks.configuration.reset_syntaxes_to_default
195
+ end
125
196
  end
126
197
  end
127
198
 
@@ -142,6 +213,14 @@ module RSpec
142
213
  end
143
214
  end
144
215
  end
216
+
217
+ def configure_default_syntax
218
+ RSpec.configure do |rspec|
219
+ rspec.mock_with :rspec do |c|
220
+ c.reset_syntaxes_to_default
221
+ end
222
+ end
223
+ end
145
224
  end
146
225
  end
147
226
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe "double" do
4
4
  it "is an alias for stub and mock" do
5
- expect(double()).to be_a(RSpec::Mocks::Double)
5
+ expect(double()).to be_a(RSpec::Mocks::Mock)
6
6
  end
7
7
 
8
8
  it "uses 'Double' in failure messages" do
@@ -10,16 +10,16 @@ describe "double" do
10
10
  expect {double.foo}.to raise_error(/Double "name" received/)
11
11
  end
12
12
 
13
- describe "deprecated aliases" do
14
- it "warns if #stub is used" do
15
- expect(RSpec).to receive(:deprecate).with("stub", :replacement => "double")
16
- stub("TestDouble")
17
- end
13
+ it "hides internals in its inspect representation" do
14
+ m = double('cup')
15
+ expect(m.inspect).to match(/#<RSpec::Mocks::Mock:0x[a-f0-9.]+ @name="cup">/)
16
+ end
18
17
 
19
- it "warns if #mock is used" do
20
- expect(RSpec).to receive(:deprecate).with("mock", :replacement => "double")
21
- mock("TestDouble")
22
- end
18
+ it 'restores standard object methods on reset' do
19
+ dbl = double(:tainted? => true)
20
+ expect(dbl.tainted?).to eq(true)
21
+ reset dbl
22
+ expect(dbl.tainted?).to eq(false)
23
23
  end
24
24
 
25
25
  it 'does not get string vs symbol messages confused' do
@@ -28,72 +28,4 @@ describe "double" do
28
28
  expect(dbl.foo).to eq(2)
29
29
  expect { reset dbl }.not_to raise_error
30
30
  end
31
-
32
- context "after it has been torn down" do
33
- let(:dbl) { double }
34
-
35
- before do
36
- expect(dbl).to receive(:foo).at_least(:once)
37
- allow(dbl).to receive(:bar)
38
- dbl.foo
39
-
40
- RSpec::Mocks.verify
41
- RSpec::Mocks.teardown
42
- RSpec::Mocks.setup
43
- end
44
-
45
- it 'warns when stubbing new methods (with receive)' do
46
- expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
47
- allow(dbl).to receive(:bazz).and_return(3)
48
- expect(dbl.bazz).to eq(3)
49
- end
50
-
51
- it 'warns when mocking new methods' do
52
- expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
53
- expect(dbl).to receive(:bazz)
54
- dbl.bazz
55
- end
56
-
57
- it 'warns when turned into a null object' do
58
- expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
59
- dbl.as_null_object
60
- dbl.foo.bar.bazz.goo
61
- end
62
-
63
- it 'warns when checked for nullness' do
64
- expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
65
- dbl.null_object?
66
- end
67
- end
68
-
69
- context 'when frozen' do
70
- it 'warns of deprecation' do
71
- expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
72
- double.freeze
73
- end
74
-
75
- it 'is really frozen' do
76
- expect(double.freeze).to be_frozen
77
- end
78
- end
79
-
80
- context 'when it has turned into a null object and been frozen' do
81
- before do
82
- double.as_null_object.freeze
83
- end
84
-
85
- context 'on tearing down' do
86
- it 'does not raise error' do
87
- expect { RSpec::Mocks.verify }.not_to raise_error
88
- end
89
- end
90
- end
91
-
92
- context 'when being deserialized from YAML' do
93
- let(:yaml) { YAML.dump(double) }
94
-
95
- it 'does not raise error' do
96
- expect { YAML.load(yaml) }.not_to raise_error
97
- end
98
- end
99
31
  end
@@ -31,21 +31,13 @@ describe Marshal, 'extensions' do
31
31
  end
32
32
 
33
33
  context 'when rspec-mocks has been fully initialized' do
34
- include_context 'with isolated configuration'
35
-
36
34
  it 'duplicates objects with stubbed or mocked implementations before serialization' do
37
- RSpec::Mocks.configuration.patch_marshal_to_support_partial_doubles = true
38
35
  obj = double(:foo => "bar")
39
36
 
40
37
  serialized = Marshal.dump(obj)
41
38
  expect(Marshal.load(serialized)).to be_an(obj.class)
42
39
  end
43
40
 
44
- it 'provides a deprecation warning' do
45
- expect_warn_deprecation_with_call_site('marshal_spec.rb', __LINE__ + 1)
46
- Marshal.dump double(:foo => "bar")
47
- end
48
-
49
41
  it 'does not duplicate other objects before serialization' do
50
42
  obj = UndupableObject.new
51
43
 
@@ -83,12 +83,24 @@ module RSpec
83
83
  end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (hash_including(:a=>1))\n got: ({})")
84
84
  end
85
85
 
86
- it "fails with block matchers" do
87
- allow_deprecation
86
+ it "fails array_including when args aren't array" do
87
+ expect do
88
+ @double.should_receive(:msg).with(array_including(1,2,3))
89
+ @double.msg(1,2,3)
90
+ end.to raise_error(/array_including\(1,2,3\)/)
91
+ end
92
+
93
+ it "fails array_including when arg doesn't contain all elements" do
94
+ expect do
95
+ @double.should_receive(:msg).with(array_including(1,2,3))
96
+ @double.msg(1,2)
97
+ end.to raise_error(/array_including\(1,2,3\)/)
98
+ end
99
+
100
+ it "fails with zero arguments" do
88
101
  expect do
89
102
  @double.should_receive(:msg).with {|arg| expect(arg).to eq :received }
90
- @double.msg :no_msg_for_you
91
- end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected: :received.*\s*.*got: :no_msg_for_you/)
103
+ end.to raise_error(ArgumentError, /must have at least one argument/)
92
104
  end
93
105
 
94
106
  it "fails with sensible message when args respond to #description" do
@@ -106,6 +118,39 @@ module RSpec
106
118
  @double.msg arg
107
119
  end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (3)\n got: (my_thing)")
108
120
  end
121
+
122
+ it "fails with sensible message when arg#description is nil" do
123
+ arg = Class.new do
124
+ def description
125
+ end
126
+
127
+ def inspect
128
+ "my_thing"
129
+ end
130
+ end.new
131
+
132
+ expect do
133
+ @double.should_receive(:msg).with(arg)
134
+ @double.msg 3
135
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (my_thing)\n got: (3)")
136
+ end
137
+
138
+ it "fails with sensible message when arg#description is blank" do
139
+ arg = Class.new do
140
+ def description
141
+ ""
142
+ end
143
+
144
+ def inspect
145
+ "my_thing"
146
+ end
147
+ end.new
148
+
149
+ expect do
150
+ @double.should_receive(:msg).with(arg)
151
+ @double.msg 3
152
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (my_thing)\n got: (3)")
153
+ end
109
154
  end
110
155
  end
111
156
  end
@@ -13,11 +13,15 @@ module RSpec
13
13
  class << obj; self; end
14
14
  end
15
15
 
16
+ def stasher_for(obj, method_name)
17
+ InstanceMethodStasher.new(obj, method_name)
18
+ end
19
+
16
20
  it "stashes the current implementation of an instance method so it can be temporarily replaced" do
17
21
  obj = Object.new
18
22
  def obj.hello; :hello_defined_on_singleton_class; end;
19
23
 
20
- stashed_method = InstanceMethodStasher.new(singleton_class_for(obj), :hello)
24
+ stashed_method = stasher_for(obj, :hello)
21
25
  stashed_method.stash
22
26
 
23
27
  def obj.hello; :overridden_hello; end
@@ -32,7 +36,7 @@ module RSpec
32
36
  def obj.hello; :hello_defined_on_singleton_class; end;
33
37
  singleton_class_for(obj).__send__(:private, :hello)
34
38
 
35
- stashed_method = InstanceMethodStasher.new(singleton_class_for(obj), :hello)
39
+ stashed_method = stasher_for(obj, :hello)
36
40
  stashed_method.stash
37
41
 
38
42
  def obj.hello; :overridden_hello; end
@@ -43,7 +47,7 @@ module RSpec
43
47
  it "only stashes methods directly defined on the given class, not its ancestors" do
44
48
  obj = ExampleClass.new
45
49
 
46
- stashed_method = InstanceMethodStasher.new(singleton_class_for(obj), :hello)
50
+ stashed_method = stasher_for(obj, :hello)
47
51
  stashed_method.stash
48
52
 
49
53
  def obj.hello; :overridden_hello; end;
@@ -52,6 +56,19 @@ module RSpec
52
56
  stashed_method.restore
53
57
  expect(obj.hello).to eql :overridden_hello
54
58
  end
59
+
60
+ it "does not unnecessarily create obfuscated aliased methods", :if => (RUBY_VERSION.to_f > 1.8) do
61
+ obj = Object.new
62
+ def obj.hello; :hello_defined_on_singleton_class; end;
63
+
64
+ stashed_method = stasher_for(obj, :hello)
65
+
66
+ expect {
67
+ stashed_method.stash
68
+ }.not_to change { obj.methods.count }
69
+
70
+ expect(obj.methods.grep(/rspec/)).to eq([])
71
+ end
55
72
  end
56
73
  end
57
74
  end
@@ -48,6 +48,58 @@ module RSpec
48
48
  }.to raise_error(/method has been mocked instead of stubbed/)
49
49
  end
50
50
 
51
+ it "takes a curly-bracket block and yields the arguments given to the stubbed method call" do
52
+ dbl = double(:foo => nil)
53
+ yielded = []
54
+ dbl.foo(:a, :b, :c)
55
+ expect(dbl).to have_received(:foo) { |*args|
56
+ yielded << args
57
+ }
58
+ expect(yielded).to include([:a,:b,:c])
59
+ end
60
+
61
+ it "takes a do-end block and yields the arguments given to the stubbed method call" do
62
+ dbl = double(:foo => nil)
63
+ yielded = []
64
+ dbl.foo(:a, :b, :c)
65
+ expect(dbl).to have_received(:foo) do |*args|
66
+ yielded << args
67
+ end
68
+ expect(yielded).to include([:a,:b,:c])
69
+ end
70
+
71
+ it "passes if expectations against the yielded arguments pass" do
72
+ dbl = double(:foo => nil)
73
+ dbl.foo(42)
74
+ expect {
75
+ expect(dbl).to have_received(:foo) { |arg|
76
+ expect(arg).to eq(42)
77
+ }
78
+ }.to_not raise_error
79
+ end
80
+
81
+ it "fails if expectations against the yielded arguments fail" do
82
+ dbl = double(:foo => nil)
83
+ dbl.foo(43)
84
+ expect {
85
+ expect(dbl).to have_received(:foo) { |arg|
86
+ expect(arg).to eq(42)
87
+ }
88
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
89
+ end
90
+
91
+ it 'gives precedence to a `{ ... }` block when both forms are provided ' +
92
+ 'since that form actually binds to `receive`' do
93
+ dbl = double(:foo => nil)
94
+ called = []
95
+ dbl.foo
96
+ expect(dbl).to have_received(:foo) { called << :curly } do
97
+ called << :do_end
98
+ end
99
+ expect(called).to include(:curly)
100
+ expect(called).not_to include(:do_end)
101
+ end
102
+
51
103
  it 'resets expectations on class methods when mocks are reset' do
52
104
  dbl = Object
53
105
  dbl.stub(:expected_method)
@@ -195,6 +247,28 @@ module RSpec
195
247
  end
196
248
  end
197
249
  end
250
+
251
+ context 'ordered' do
252
+ let(:dbl) { double :one => 1, :two => 2 }
253
+
254
+ it 'passes when the messages were received in order' do
255
+ dbl.one
256
+ dbl.two
257
+
258
+ expect(dbl).to have_received(:one).ordered
259
+ expect(dbl).to have_received(:two).ordered
260
+ end
261
+
262
+ it 'fails when the messages are received out of order' do
263
+ dbl.two
264
+ dbl.one
265
+
266
+ expect {
267
+ expect(dbl).to have_received(:one).ordered
268
+ expect(dbl).to have_received(:two).ordered
269
+ }.to raise_error(/received :two out of order/m)
270
+ end
271
+ end
198
272
  end
199
273
 
200
274
  describe "expect(...).not_to have_received" do
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ shared_examples_for "complains when given blocks" do
6
+ it "complains if a { } block is given" do
7
+ expect {
8
+ target.to receive_messages(:a => 1) { "implementation" }
9
+ }.to raise_error "Implementation blocks aren't supported with `receive_messages`"
10
+ end
11
+
12
+ it "complains if a do; end; block is given" do
13
+ expect {
14
+ target.to receive_messages(:a => 1) do
15
+ "implementation"
16
+ end
17
+ }.to raise_error "Implementation blocks aren't supported with `receive_messages`"
18
+ end
19
+ end
20
+
21
+ shared_examples_for "handles partially mocked objects correctly" do
22
+ let(:obj) { Struct.new(:a).new('original') }
23
+
24
+ it "resets partially mocked objects correctly" do
25
+ target.to receive_messages(:a => 1, :b => 2)
26
+
27
+ expect {
28
+ reset obj
29
+ }.to change { obj.a }.from(1).to("original")
30
+ end
31
+ end
32
+
33
+ describe "allow(...).to receive_messages(:a => 1, :b => 2)" do
34
+ let(:obj) { double "Object" }
35
+ let(:target) { allow(obj) }
36
+
37
+ it "allows the object to respond to multiple messages" do
38
+ allow(obj).to receive_messages(:a => 1, :b => 2)
39
+ expect(obj.a).to eq 1
40
+ expect(obj.b).to eq 2
41
+ end
42
+
43
+ it_behaves_like "complains when given blocks"
44
+ it_behaves_like "handles partially mocked objects correctly"
45
+ end
46
+
47
+ describe "allow_any_instance_of(...).to receive_messages(:a => 1, :b => 2)" do
48
+ let(:obj) { Object.new }
49
+ let(:target) { allow_any_instance_of(Object) }
50
+
51
+ it "allows the object to respond to multiple messages" do
52
+ allow_any_instance_of(Object).to receive_messages(:a => 1, :b => 2)
53
+ expect(obj.a).to eq 1
54
+ expect(obj.b).to eq 2
55
+ end
56
+
57
+ it_behaves_like "complains when given blocks"
58
+ end
59
+
60
+ describe "expect(...).to receive_messages(:a => 1, :b => 2)" do
61
+ let(:obj) { double "Object" }
62
+ let(:target) { expect(obj) }
63
+
64
+ let(:expectation_error) do
65
+ failure = nil
66
+ begin
67
+ RSpec::Mocks.space.verify_all
68
+ rescue RSpec::Mocks::MockExpectationError => error
69
+ failure = error
70
+ end
71
+ failure
72
+ end
73
+
74
+ it "sets up multiple expectations" do
75
+ expect(obj).to receive_messages(:a => 1, :b => 2)
76
+ obj.a
77
+ expect { RSpec::Mocks.space.verify_all }.to raise_error RSpec::Mocks::MockExpectationError
78
+ end
79
+
80
+ it 'fails with a sensible message' do
81
+ expect(obj).to receive_messages(:a => 1, :b => 2)
82
+ obj.b
83
+ expect(expectation_error.to_s).to eq %Q{(Double "Object").a(no args)\n expected: 1 time with any arguments\n received: 0 times}
84
+ end
85
+
86
+ it 'fails with the correct location' do
87
+ expect(obj).to receive_messages(:a => 1, :b => 2); line = __LINE__
88
+ expect(expectation_error.backtrace[0]).to match(/#{__FILE__}:#{line}/)
89
+ end
90
+
91
+ it_behaves_like "complains when given blocks"
92
+ it_behaves_like "handles partially mocked objects correctly"
93
+ end
94
+
95
+ describe "expect_any_instance_of(...).to receive_messages(:a => 1, :b => 2)" do
96
+ let(:obj) { Object.new }
97
+ let(:target) { expect_any_instance_of(Object) }
98
+
99
+ it "sets up multiple expectations" do
100
+ expect_any_instance_of(Object).to receive_messages(:a => 1, :b => 2)
101
+ obj.a
102
+ expect { RSpec::Mocks.space.verify_all }.to raise_error RSpec::Mocks::MockExpectationError
103
+ end
104
+
105
+ it_behaves_like "complains when given blocks"
106
+ end
107
+
108
+ describe "negative expectation failure" do
109
+ let(:obj) { Object.new }
110
+
111
+ example "allow(...).to_not receive_messages(:a => 1, :b => 2)" do
112
+ expect { allow(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
113
+ raise_error "`allow(...).to_not receive_messages` is not supported "+
114
+ "since it doesn't really make sense. What would it even mean?"
115
+ )
116
+ end
117
+
118
+ example "allow_any_instance_of(...).to_not receive_messages(:a => 1, :b => 2)" do
119
+ expect { allow_any_instance_of(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
120
+ raise_error "`allow_any_instance_of(...).to_not receive_messages` is not supported "+
121
+ "since it doesn't really make sense. What would it even mean?"
122
+ )
123
+ end
124
+
125
+ example "expect(...).to_not receive_messages(:a => 1, :b => 2)" do
126
+ expect { expect(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
127
+ raise_error "`expect(...).to_not receive_messages` is not supported "+
128
+ "since it doesn't really make sense. What would it even mean?"
129
+ )
130
+ end
131
+
132
+ example "expect_any_instance_of(...).to_not receive_messages(:a => 1, :b => 2)" do
133
+ expect { expect_any_instance_of(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
134
+ raise_error "`expect_any_instance_of(...).to_not receive_messages` is not supported "+
135
+ "since it doesn't really make sense. What would it even mean?"
136
+ )
137
+ end
138
+ end
139
+ end
140
+ end