rspec-mocks 3.0.0.beta1 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data.tar.gz.sig +1 -1
  2. data/Changelog.md +95 -3
  3. data/README.md +27 -13
  4. data/features/README.md +15 -7
  5. data/features/argument_matchers/README.md +5 -5
  6. data/features/argument_matchers/explicit.feature +6 -6
  7. data/features/argument_matchers/general_matchers.feature +4 -4
  8. data/features/argument_matchers/type_matchers.feature +2 -2
  9. data/features/message_expectations/README.md +29 -27
  10. data/features/message_expectations/call_original.feature +0 -1
  11. data/features/message_expectations/message_chains_using_expect.feature +49 -0
  12. data/features/method_stubs/README.md +2 -1
  13. data/features/method_stubs/{any_instance.feature → allow_any_instance_of.feature} +12 -12
  14. data/features/method_stubs/{stub_chain.feature → receive_message_chain.feature} +3 -3
  15. data/features/method_stubs/to_ary.feature +1 -1
  16. data/features/mutating_constants/stub_defined_constant.feature +0 -1
  17. data/features/outside_rspec/standalone.feature +1 -1
  18. data/features/spies/spy_pure_mock_method.feature +1 -1
  19. data/features/test_frameworks/test_unit.feature +21 -10
  20. data/features/verifying_doubles/README.md +17 -0
  21. data/features/verifying_doubles/class_doubles.feature +1 -16
  22. data/features/verifying_doubles/dynamic_classes.feature +0 -1
  23. data/features/verifying_doubles/{introduction.feature → instance_doubles.feature} +41 -23
  24. data/features/verifying_doubles/partial_doubles.feature +2 -2
  25. data/lib/rspec/mocks.rb +69 -82
  26. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +35 -0
  27. data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -2
  28. data/lib/rspec/mocks/any_instance/recorder.rb +52 -18
  29. data/lib/rspec/mocks/any_instance/stub_chain.rb +1 -1
  30. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +4 -0
  31. data/lib/rspec/mocks/argument_list_matcher.rb +10 -44
  32. data/lib/rspec/mocks/argument_matchers.rb +132 -163
  33. data/lib/rspec/mocks/configuration.rb +28 -4
  34. data/lib/rspec/mocks/error_generator.rb +46 -13
  35. data/lib/rspec/mocks/example_methods.rb +13 -12
  36. data/lib/rspec/mocks/extensions/marshal.rb +1 -1
  37. data/lib/rspec/mocks/framework.rb +3 -4
  38. data/lib/rspec/mocks/instance_method_stasher.rb +2 -3
  39. data/lib/rspec/mocks/matchers/have_received.rb +8 -6
  40. data/lib/rspec/mocks/matchers/receive.rb +28 -20
  41. data/lib/rspec/mocks/matchers/receive_message_chain.rb +65 -0
  42. data/lib/rspec/mocks/matchers/receive_messages.rb +3 -2
  43. data/lib/rspec/mocks/message_chain.rb +91 -0
  44. data/lib/rspec/mocks/message_expectation.rb +86 -80
  45. data/lib/rspec/mocks/method_double.rb +2 -11
  46. data/lib/rspec/mocks/method_reference.rb +82 -23
  47. data/lib/rspec/mocks/method_signature_verifier.rb +207 -0
  48. data/lib/rspec/mocks/mutate_const.rb +34 -50
  49. data/lib/rspec/mocks/object_reference.rb +0 -1
  50. data/lib/rspec/mocks/proxy.rb +70 -13
  51. data/lib/rspec/mocks/ruby_features.rb +24 -0
  52. data/lib/rspec/mocks/space.rb +105 -31
  53. data/lib/rspec/mocks/standalone.rb +2 -2
  54. data/lib/rspec/mocks/syntax.rb +43 -8
  55. data/lib/rspec/mocks/targets.rb +16 -7
  56. data/lib/rspec/mocks/test_double.rb +41 -15
  57. data/lib/rspec/mocks/verifying_double.rb +51 -4
  58. data/lib/rspec/mocks/verifying_message_expecation.rb +12 -12
  59. data/lib/rspec/mocks/verifying_proxy.rb +32 -19
  60. data/lib/rspec/mocks/version.rb +1 -1
  61. data/spec/rspec/mocks/and_call_original_spec.rb +28 -7
  62. data/spec/rspec/mocks/and_return_spec.rb +23 -0
  63. data/spec/rspec/mocks/and_yield_spec.rb +1 -2
  64. data/spec/rspec/mocks/any_instance_spec.rb +33 -17
  65. data/spec/rspec/mocks/array_including_matcher_spec.rb +6 -6
  66. data/spec/rspec/mocks/before_all_spec.rb +132 -0
  67. data/spec/rspec/mocks/block_return_value_spec.rb +12 -1
  68. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +9 -11
  69. data/spec/rspec/mocks/configuration_spec.rb +14 -1
  70. data/spec/rspec/mocks/double_spec.rb +867 -24
  71. data/spec/rspec/mocks/example_methods_spec.rb +13 -0
  72. data/spec/rspec/mocks/extensions/marshal_spec.rb +17 -17
  73. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +29 -1
  74. data/spec/rspec/mocks/hash_excluding_matcher_spec.rb +12 -12
  75. data/spec/rspec/mocks/hash_including_matcher_spec.rb +21 -17
  76. data/spec/rspec/mocks/instance_method_stasher_spec.rb +2 -3
  77. data/spec/rspec/mocks/matchers/have_received_spec.rb +7 -0
  78. data/spec/rspec/mocks/matchers/receive_message_chain_spec.rb +198 -0
  79. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +2 -2
  80. data/spec/rspec/mocks/matchers/receive_spec.rb +19 -6
  81. data/spec/rspec/mocks/method_signature_verifier_spec.rb +272 -0
  82. data/spec/rspec/mocks/methods_spec.rb +0 -1
  83. data/spec/rspec/mocks/multiple_return_value_spec.rb +2 -2
  84. data/spec/rspec/mocks/mutate_const_spec.rb +24 -1
  85. data/spec/rspec/mocks/nil_expectation_warning_spec.rb +6 -22
  86. data/spec/rspec/mocks/null_object_mock_spec.rb +13 -7
  87. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  88. data/spec/rspec/mocks/{partial_mock_spec.rb → partial_double_spec.rb} +5 -2
  89. data/spec/rspec/mocks/{partial_mock_using_mocks_directly_spec.rb → partial_double_using_mocks_directly_spec.rb} +1 -1
  90. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +18 -0
  91. data/spec/rspec/mocks/serialization_spec.rb +1 -0
  92. data/spec/rspec/mocks/space_spec.rb +218 -7
  93. data/spec/rspec/mocks/stub_chain_spec.rb +6 -0
  94. data/spec/rspec/mocks/stub_spec.rb +0 -6
  95. data/spec/rspec/mocks/syntax_spec.rb +19 -0
  96. data/spec/rspec/mocks/test_double_spec.rb +0 -1
  97. data/spec/rspec/mocks/verifying_double_spec.rb +281 -18
  98. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +7 -6
  99. data/spec/rspec/mocks_spec.rb +168 -42
  100. data/spec/spec_helper.rb +34 -22
  101. metadata +94 -63
  102. metadata.gz.sig +0 -0
  103. checksums.yaml +0 -15
  104. checksums.yaml.gz.sig +0 -2
  105. data/features/outside_rspec/configuration.feature +0 -60
  106. data/lib/rspec/mocks/arity_calculator.rb +0 -66
  107. data/lib/rspec/mocks/errors.rb +0 -12
  108. data/lib/rspec/mocks/mock.rb +0 -7
  109. data/lib/rspec/mocks/proxy_for_nil.rb +0 -37
  110. data/lib/rspec/mocks/stub_chain.rb +0 -51
  111. data/spec/rspec/mocks/argument_expectation_spec.rb +0 -32
  112. data/spec/rspec/mocks/arity_calculator_spec.rb +0 -95
  113. data/spec/rspec/mocks/mock_space_spec.rb +0 -113
  114. data/spec/rspec/mocks/mock_spec.rb +0 -788
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe ExampleMethods do
6
+ it 'does not define private helper methods since it gets included into a ' +
7
+ 'namespace where users define methods and could inadvertently overwrite ' +
8
+ 'them' do
9
+ expect(ExampleMethods.private_instance_methods).to eq([])
10
+ end
11
+ end
12
+ end
13
+ end
@@ -13,23 +13,6 @@ describe Marshal, 'extensions' do
13
13
  end
14
14
 
15
15
  describe '#dump' do
16
- context 'when rspec-mocks has not been fully initialized' do
17
- def without_space
18
- stashed_space, RSpec::Mocks.space = RSpec::Mocks.space, nil
19
- yield
20
- ensure
21
- RSpec::Mocks.space = stashed_space
22
- end
23
-
24
- it 'does not duplicate the object before serialization' do
25
- obj = UndupableObject.new
26
- without_space do
27
- serialized = Marshal.dump(obj)
28
- expect(Marshal.load(serialized)).to be_an(UndupableObject)
29
- end
30
- end
31
- end
32
-
33
16
  context 'when rspec-mocks has been fully initialized' do
34
17
  it 'duplicates objects with stubbed or mocked implementations before serialization' do
35
18
  obj = double(:foo => "bar")
@@ -50,5 +33,22 @@ describe Marshal, 'extensions' do
50
33
  expect(Marshal.load(serialized)).to be_nil
51
34
  end
52
35
  end
36
+
37
+ context 'outside the per-test lifecycle' do
38
+ def outside_per_test_lifecycle
39
+ RSpec::Mocks.teardown
40
+ yield
41
+ ensure
42
+ RSpec::Mocks.setup
43
+ end
44
+
45
+ it 'does not duplicate the object before serialization' do
46
+ obj = UndupableObject.new
47
+ outside_per_test_lifecycle do
48
+ serialized = Marshal.dump(obj)
49
+ expect(Marshal.load(serialized)).to be_an(UndupableObject)
50
+ end
51
+ end
52
+ end
53
53
  end
54
54
  end
@@ -63,9 +63,11 @@ module RSpec
63
63
  end
64
64
 
65
65
  it "matches against a Matcher" do
66
+ # This spec is generating warnings on 1.8.7, not sure why so
67
+ # this does with_isolated_stderr to kill them. @samphippen 3rd Jan 2013.
66
68
  expect do
67
69
  @double.should_receive(:msg).with(equal(3))
68
- @double.msg(37)
70
+ with_isolated_stderr { @double.msg(37) }
69
71
  end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (equal 3)\n got: (37)")
70
72
  end
71
73
 
@@ -103,6 +105,17 @@ module RSpec
103
105
  end.to raise_error(ArgumentError, /must have at least one argument/)
104
106
  end
105
107
 
108
+ it "fails when given an arbitrary object that returns false from #===" do
109
+ matcher = double
110
+ matcher.should_receive(:===).with(4).at_least(:once).and_return(false)
111
+
112
+ @double.should_receive(:foo).with(matcher)
113
+
114
+ expect {
115
+ @double.foo(4)
116
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
117
+ end
118
+
106
119
  it "fails with sensible message when args respond to #description" do
107
120
  arg = Class.new do
108
121
  def description
@@ -151,6 +164,21 @@ module RSpec
151
164
  @double.msg 3
152
165
  end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (my_thing)\n got: (3)")
153
166
  end
167
+
168
+ it "fails a class against an unrelated class" do
169
+ @double.should_receive(:foo).with(Fixnum)
170
+ expect {
171
+ @double.foo(Hash)
172
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
173
+ end
174
+
175
+ it "fails a class against an object of a different type" do
176
+ @double.should_receive(:foo).with(Fixnum)
177
+
178
+ expect {
179
+ @double.foo(3.2)
180
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
181
+ end
154
182
  end
155
183
  end
156
184
  end
@@ -11,54 +11,54 @@ module RSpec
11
11
 
12
12
  describe "passing" do
13
13
  it "matches a hash without the specified key" do
14
- expect(hash_not_including(:c)).to eq({:a => 1, :b => 2})
14
+ expect(hash_not_including(:c)).to be === {:a => 1, :b => 2}
15
15
  end
16
16
 
17
17
  it "matches a hash with the specified key, but different value" do
18
- expect(hash_not_including(:b => 3)).to eq({:a => 1, :b => 2})
18
+ expect(hash_not_including(:b => 3)).to be === {:a => 1, :b => 2}
19
19
  end
20
20
 
21
21
  it "matches a hash without the specified key, given as anything()" do
22
- expect(hash_not_including(:c => anything)).to eq({:a => 1, :b => 2})
22
+ expect(hash_not_including(:c => anything)).to be === {:a => 1, :b => 2}
23
23
  end
24
24
 
25
25
  it "matches an empty hash" do
26
- expect(hash_not_including(:a)).to eq({})
26
+ expect(hash_not_including(:a)).to be === {}
27
27
  end
28
28
 
29
29
  it "matches a hash without any of the specified keys" do
30
- expect(hash_not_including(:a, :b, :c)).to eq(:d => 7)
30
+ expect(hash_not_including(:a, :b, :c)).to be === { :d => 7 }
31
31
  end
32
32
 
33
33
  end
34
34
 
35
35
  describe "failing" do
36
36
  it "does not match a non-hash" do
37
- expect(hash_not_including(:a => 1)).not_to eq 1
37
+ expect(hash_not_including(:a => 1)).not_to be === 1
38
38
  end
39
39
 
40
40
  it "does not match a hash with a specified key" do
41
- expect(hash_not_including(:b)).not_to eq(:b => 2)
41
+ expect(hash_not_including(:b)).not_to be === { :b => 2 }
42
42
  end
43
43
 
44
44
  it "does not match a hash with the specified key/value pair" do
45
- expect(hash_not_including(:b => 2)).not_to eq(:a => 1, :b => 2)
45
+ expect(hash_not_including(:b => 2)).not_to be === { :a => 1, :b => 2 }
46
46
  end
47
47
 
48
48
  it "does not match a hash with the specified key" do
49
- expect(hash_not_including(:a, :b => 3)).not_to eq(:a => 1, :b => 2)
49
+ expect(hash_not_including(:a, :b => 3)).not_to be === { :a => 1, :b => 2 }
50
50
  end
51
51
 
52
52
  it "does not match a hash with one of the specified keys" do
53
- expect(hash_not_including(:a, :b)).not_to eq(:b => 2)
53
+ expect(hash_not_including(:a, :b)).not_to be === { :b => 2 }
54
54
  end
55
55
 
56
56
  it "does not match a hash with some of the specified keys" do
57
- expect(hash_not_including(:a, :b, :c)).not_to eq(:a => 1, :b => 2)
57
+ expect(hash_not_including(:a, :b, :c)).not_to be === { :a => 1, :b => 2 }
58
58
  end
59
59
 
60
60
  it "does not match a hash with one key/value pair included" do
61
- expect(hash_not_including(:a, :b, :c, :d => 7)).not_to eq(:d => 7)
61
+ expect(hash_not_including(:a, :b, :c, :d => 7)).not_to be === { :d => 7 }
62
62
  end
63
63
  end
64
64
  end
@@ -11,77 +11,81 @@ module RSpec
11
11
 
12
12
  describe "passing" do
13
13
  it "matches the same hash" do
14
- expect(hash_including(:a => 1)).to eq({:a => 1})
14
+ expect(hash_including(:a => 1)).to be === {:a => 1}
15
15
  end
16
16
 
17
17
  it "matches a hash with extra stuff" do
18
- expect(hash_including(:a => 1)).to eq({:a => 1, :b => 2})
18
+ expect(hash_including(:a => 1)).to be === {:a => 1, :b => 2}
19
19
  end
20
20
 
21
21
  describe "when matching against other matchers" do
22
22
  it "matches an int against anything()" do
23
- expect(hash_including(:a => anything, :b => 2)).to eq({:a => 1, :b => 2})
23
+ expect(hash_including(:a => anything, :b => 2)).to be === {:a => 1, :b => 2}
24
24
  end
25
25
 
26
26
  it "matches a string against anything()" do
27
- expect(hash_including(:a => anything, :b => 2)).to eq({:a => "1", :b => 2})
27
+ expect(hash_including(:a => anything, :b => 2)).to be === {:a => "1", :b => 2}
28
+ end
29
+
30
+ it 'can match against arbitrary objects that implement #===' do
31
+ expect(hash_including(:a => /foo/)).to be === { :a => "foobar" }
28
32
  end
29
33
  end
30
34
 
31
35
  describe "when passed only keys or keys mixed with key/value pairs" do
32
36
  it "matches if the key is present" do
33
- expect(hash_including(:a)).to eq({:a => 1, :b => 2})
37
+ expect(hash_including(:a)).to be === {:a => 1, :b => 2}
34
38
  end
35
39
 
36
40
  it "matches if more keys are present" do
37
- expect(hash_including(:a, :b)).to eq({:a => 1, :b => 2, :c => 3})
41
+ expect(hash_including(:a, :b)).to be === {:a => 1, :b => 2, :c => 3}
38
42
  end
39
43
 
40
44
  it "matches a string against a given key" do
41
- expect(hash_including(:a)).to eq({:a => "1", :b => 2})
45
+ expect(hash_including(:a)).to be === {:a => "1", :b => 2}
42
46
  end
43
47
 
44
48
  it "matches if passed one key and one key/value pair" do
45
- expect(hash_including(:a, :b => 2)).to eq({:a => 1, :b => 2})
49
+ expect(hash_including(:a, :b => 2)).to be === {:a => 1, :b => 2}
46
50
  end
47
51
 
48
52
  it "matches if passed many keys and one key/value pair" do
49
- expect(hash_including(:a, :b, :c => 3)).to eq({:a => 1, :b => 2, :c => 3, :d => 4})
53
+ expect(hash_including(:a, :b, :c => 3)).to be === {:a => 1, :b => 2, :c => 3, :d => 4}
50
54
  end
51
55
 
52
56
  it "matches if passed many keys and many key/value pairs" do
53
- expect(hash_including(:a, :b, :c => 3, :e => 5)).to eq({:a => 1, :b => 2, :c => 3, :d => 4, :e => 5})
57
+ expect(hash_including(:a, :b, :c => 3, :e => 5)).to be === {:a => 1, :b => 2, :c => 3, :d => 4, :e => 5}
54
58
  end
55
59
  end
56
60
  end
57
61
 
58
62
  describe "failing" do
59
63
  it "does not match a non-hash" do
60
- expect(hash_including(:a => 1)).not_to eq 1
64
+ expect(hash_including(:a => 1)).not_to be === 1
61
65
  end
62
66
 
63
67
  it "does not match a hash with a missing key" do
64
- expect(hash_including(:a => 1)).not_to eq(:b => 2)
68
+ expect(hash_including(:a => 1)).not_to be === { :b => 2 }
65
69
  end
66
70
 
67
71
  it "does not match a hash with a missing key" do
68
- expect(hash_including(:a)).not_to eq(:b => 2)
72
+ expect(hash_including(:a)).not_to be === { :b => 2 }
69
73
  end
70
74
 
71
75
  it "does not match an empty hash with a given key" do
72
- expect(hash_including(:a)).not_to eq({})
76
+ expect(hash_including(:a)).not_to be === {}
73
77
  end
74
78
 
75
79
  it "does not match a hash with a missing key when one pair is matching" do
76
- expect(hash_including(:a, :b => 2)).not_to eq(:b => 2)
80
+ expect(hash_including(:a, :b => 2)).not_to be === { :b => 2 }
77
81
  end
78
82
 
79
83
  it "does not match a hash with an incorrect value" do
80
- expect(hash_including(:a => 1, :b => 2)).not_to eq(:a => 1, :b => 3)
84
+ expect(hash_including(:a => 1, :b => 2)).not_to be === { :a => 1, :b => 3 }
81
85
  end
82
86
 
83
87
  it "does not match when values are nil but keys are different" do
84
- expect(hash_including(:a => nil)).not_to eq(:b => nil)
88
+ expect(hash_including(:a => nil)).not_to be === { :b => nil }
85
89
  end
86
90
  end
87
91
  end
@@ -24,7 +24,7 @@ module RSpec
24
24
  stashed_method = stasher_for(obj, :hello)
25
25
  stashed_method.stash
26
26
 
27
- def obj.hello; :overridden_hello; end
27
+ with_isolated_stderr { def obj.hello; :overridden_hello; end }
28
28
  expect(obj.hello).to eql :overridden_hello
29
29
 
30
30
  stashed_method.restore
@@ -39,7 +39,7 @@ module RSpec
39
39
  stashed_method = stasher_for(obj, :hello)
40
40
  stashed_method.stash
41
41
 
42
- def obj.hello; :overridden_hello; end
42
+ with_isolated_stderr { def obj.hello; :overridden_hello; end }
43
43
  stashed_method.restore
44
44
  expect(obj.send(:hello)).to eql :hello_defined_on_singleton_class
45
45
  end
@@ -72,4 +72,3 @@ module RSpec
72
72
  end
73
73
  end
74
74
  end
75
-
@@ -132,6 +132,13 @@ module RSpec
132
132
  expect(matcher.description).to eq 'have received expected_method(:expected_args) 1 time'
133
133
  end
134
134
 
135
+ it 'can generate a description after mocks have been torn down (e.g. when rspec-core requests it)' do
136
+ matcher = have_received(:expected_method).with(:expected_args).once
137
+ matcher.matches?(double(:expected_method => 1))
138
+ RSpec::Mocks.teardown
139
+ expect(matcher.description).to eq 'have received expected_method(:expected_args) 1 time'
140
+ end
141
+
135
142
  context "counts" do
136
143
  let(:dbl) { double(:expected_method => nil) }
137
144
 
@@ -0,0 +1,198 @@
1
+ require "spec_helper"
2
+
3
+
4
+ module RSpec::Mocks::Matchers
5
+ describe "receive_message_chain" do
6
+ let(:object) { double(:object) }
7
+
8
+ context "with only the expect syntax enabled" do
9
+ include_context "with syntax", :expect
10
+
11
+ it "errors with a negative allowance" do
12
+ expect {
13
+ allow(object).not_to receive_message_chain(:to_a)
14
+ }.to raise_error(RSpec::Mocks::NegationUnsupportedError)
15
+ end
16
+
17
+ it "errors with a negative expectation" do
18
+ expect {
19
+ expect(object).not_to receive_message_chain(:to_a)
20
+ }.to raise_error(RSpec::Mocks::NegationUnsupportedError)
21
+ end
22
+
23
+ it "errors with a negative any_instance expectation" do
24
+ expect {
25
+ expect_any_instance_of(Object).not_to receive_message_chain(:to_a)
26
+ }.to raise_error(RSpec::Mocks::NegationUnsupportedError)
27
+ end
28
+
29
+ it "errors with a negative any_instance allowance" do
30
+ expect {
31
+ allow_any_instance_of(Object).not_to receive_message_chain(:to_a)
32
+ }.to raise_error(RSpec::Mocks::NegationUnsupportedError)
33
+ end
34
+
35
+ it "works with a do block" do
36
+ allow(object).to receive_message_chain(:to_a, :length) do
37
+ 3
38
+ end
39
+
40
+ expect(object.to_a.length).to eq(3)
41
+ end
42
+
43
+ it "works with a {} block" do
44
+ allow(object).to receive_message_chain(:to_a, :length) { 3 }
45
+
46
+ expect(object.to_a.length).to eq(3)
47
+ end
48
+
49
+ it "gives the { } block prescedence over the do block" do
50
+ allow(object).to receive_message_chain(:to_a, :length) { 3 } do
51
+ 4
52
+ end
53
+
54
+ expect(object.to_a.length).to eq(3)
55
+ end
56
+
57
+ it "works with and_return" do
58
+ allow(object).to receive_message_chain(:to_a, :length).and_return(3)
59
+
60
+ expect(object.to_a.length).to eq(3)
61
+ end
62
+
63
+ it "works with and_call_original", :pending => "See https://github.com/rspec/rspec-mocks/pull/467#issuecomment-28631621" do
64
+ list = [1, 2, 3]
65
+ expect(list).to receive_message_chain(:to_a, :length).and_call_original
66
+ expect(list.to_a.length).to eq(3)
67
+ end
68
+
69
+ it "fails with and_call_original when the entire chain is not called", :pending => "See https://github.com/rspec/rspec-mocks/pull/467#issuecomment-28631621" do
70
+ list = [1, 2, 3]
71
+ expect(list).to receive_message_chain(:to_a, :length).and_call_original
72
+ expect(list.to_a).to eq([1, 2, 3])
73
+ end
74
+
75
+ it "works with and_raise" do
76
+ allow(object).to receive_message_chain(:to_a, :length).and_raise(StandardError.new("hi"))
77
+
78
+ expect { object.to_a.length }.to raise_error(StandardError, "hi")
79
+ end
80
+
81
+ it "works with and_throw" do
82
+ allow(object).to receive_message_chain(:to_a, :length).and_throw(:nope)
83
+
84
+ expect { object.to_a.length }.to throw_symbol(:nope)
85
+ end
86
+
87
+ it "works with and_yield" do
88
+ allow(object).to receive_message_chain(:to_a, :length).and_yield(3)
89
+
90
+ expect { |blk| object.to_a.length(&blk) }.to yield_with_args(3)
91
+ end
92
+
93
+ it "works with a string of messages to chain" do
94
+ allow(object).to receive_message_chain("to_a.length").and_yield(3)
95
+
96
+ expect { |blk| object.to_a.length(&blk) }.to yield_with_args(3)
97
+ end
98
+
99
+ it "works with a hash return as the last argument in the chain" do
100
+ allow(object).to receive_message_chain(:to_a, :length => 3)
101
+
102
+ expect(object.to_a.length).to eq(3)
103
+ end
104
+
105
+ it "accepts any number of arguments to the stubbed messages" do
106
+ allow(object).to receive_message_chain(:msg1, :msg2).and_return(:return_value)
107
+
108
+ expect(object.msg1("nonsense", :value).msg2("another", :nonsense, 3.0, "value")).to eq(:return_value)
109
+ end
110
+
111
+ it "accepts any number of arguments to the stubbed messages with an inline hash return value" do
112
+ allow(object).to receive_message_chain(:msg1, :msg2 => :return_value)
113
+
114
+ expect(object.msg1("nonsense", :value).msg2("another", :nonsense, 3.0, "value")).to eq(:return_value)
115
+ end
116
+
117
+ it "raises when expect is used and the entire chain isn't called" do
118
+ expect {
119
+ expect(object).to receive_message_chain(:to_a, :farce, :length => 3)
120
+ object.to_a
121
+ verify_all
122
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
123
+ end
124
+
125
+ it "does not raise when expect is used and the entire chain is called" do
126
+ expect {
127
+ expect(object).to receive_message_chain(:to_a, :length => 3)
128
+ object.to_a.length
129
+ verify_all
130
+ }.not_to raise_error
131
+ end
132
+
133
+ it "works with allow_any_instance" do
134
+ o = Object.new
135
+
136
+ allow_any_instance_of(Object).to receive_message_chain(:to_a, :length => 3)
137
+
138
+ expect(o.to_a.length).to eq(3)
139
+ end
140
+
141
+ it "fails when with expect_any_instance_of is used and the entire chain is not called" do
142
+ expect {
143
+ expect_any_instance_of(Object).to receive_message_chain(:to_a, :length => 3)
144
+ verify_all
145
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
146
+ end
147
+
148
+ it "passes when with expect_any_instance_of is used and the entire chain is called" do
149
+ o = Object.new
150
+
151
+ expect_any_instance_of(Object).to receive_message_chain(:to_a, :length => 3)
152
+ o.to_a.length
153
+ end
154
+
155
+ it "works with expect where the first level of the chain is already expected" do
156
+ o = Object.new
157
+ expect(o).to receive(:foo).and_return(double)
158
+ expect(o).to receive_message_chain(:foo, :bar, :baz)
159
+
160
+ o.foo.bar.baz
161
+ end
162
+
163
+ it "works with allow where the first level of the chain is already expected" do
164
+ o = Object.new
165
+ expect(o).to receive(:foo).and_return(double)
166
+ allow(o).to receive_message_chain(:foo, :bar, :baz).and_return(3)
167
+
168
+ expect(o.foo.bar.baz).to eq(3)
169
+ end
170
+
171
+ it "works with expect where the first level of the chain is already stubbed" do
172
+ o = Object.new
173
+ allow(o).to receive(:foo).and_return(double)
174
+ expect(o).to receive_message_chain(:foo, :bar, :baz)
175
+
176
+ o.foo.bar.baz
177
+ end
178
+
179
+ it "works with allow where the first level of the chain is already stubbed" do
180
+ o = Object.new
181
+ allow(o).to receive(:foo).and_return(double)
182
+ allow(o).to receive_message_chain(:foo, :bar, :baz).and_return(3)
183
+
184
+ expect(o.foo.bar.baz).to eq(3)
185
+ end
186
+ end
187
+
188
+ context "when the expect and should syntaxes are enabled" do
189
+ include_context "with syntax", [:expect, :should]
190
+
191
+ it "stubs the message correctly" do
192
+ allow(object).to receive_message_chain(:to_a, :length)
193
+
194
+ expect { object.to_a.length }.not_to raise_error
195
+ end
196
+ end
197
+ end
198
+ end