rspec-mocks 2.99.4 → 3.0.0.beta1

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.
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