rspec-mocks 2.6.0 → 2.7.0.rc1

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 (66) hide show
  1. data/features/Scope.md +17 -0
  2. data/features/argument_matchers/README.md +27 -0
  3. data/features/argument_matchers/explicit.feature +60 -0
  4. data/features/argument_matchers/general_matchers.feature +85 -0
  5. data/features/argument_matchers/type_matchers.feature +25 -0
  6. data/features/message_expectations/any_instance.feature +2 -0
  7. data/features/message_expectations/receive_counts.feature +209 -0
  8. data/features/method_stubs/README.md +6 -10
  9. data/features/method_stubs/any_instance.feature +111 -1
  10. data/features/method_stubs/simple_return_value.feature +34 -25
  11. data/features/method_stubs/stub_implementation.feature +1 -1
  12. data/features/method_stubs/to_ary.feature +12 -10
  13. data/features/support/env.rb +1 -1
  14. data/lib/rspec/mocks.rb +1 -1
  15. data/lib/rspec/mocks/any_instance.rb +8 -235
  16. data/lib/rspec/mocks/any_instance/chain.rb +49 -0
  17. data/lib/rspec/mocks/any_instance/expectation_chain.rb +33 -0
  18. data/lib/rspec/mocks/any_instance/message_chains.rb +48 -0
  19. data/lib/rspec/mocks/any_instance/recorder.rb +162 -0
  20. data/lib/rspec/mocks/any_instance/stub_chain.rb +35 -0
  21. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +34 -0
  22. data/lib/rspec/mocks/argument_expectation.rb +1 -1
  23. data/lib/rspec/mocks/extensions/marshal.rb +1 -1
  24. data/lib/rspec/mocks/extensions/psych.rb +1 -1
  25. data/lib/rspec/mocks/methods.rb +1 -1
  26. data/lib/rspec/mocks/mock.rb +2 -2
  27. data/lib/rspec/mocks/proxy.rb +1 -1
  28. data/lib/rspec/mocks/version.rb +1 -1
  29. data/spec/rspec/mocks/any_instance/message_chains_spec.rb +40 -0
  30. data/spec/rspec/mocks/any_instance_spec.rb +147 -2
  31. data/spec/rspec/mocks/any_number_of_times_spec.rb +2 -2
  32. data/spec/rspec/mocks/argument_expectation_spec.rb +15 -3
  33. data/spec/rspec/mocks/at_least_spec.rb +1 -1
  34. data/spec/rspec/mocks/at_most_spec.rb +1 -1
  35. data/spec/rspec/mocks/bug_report_10263_spec.rb +1 -1
  36. data/spec/rspec/mocks/bug_report_7611_spec.rb +1 -1
  37. data/spec/rspec/mocks/bug_report_8165_spec.rb +2 -2
  38. data/spec/rspec/mocks/bug_report_957_spec.rb +2 -2
  39. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +1 -1
  40. data/spec/rspec/mocks/hash_including_matcher_spec.rb +11 -11
  41. data/spec/rspec/mocks/hash_not_including_matcher_spec.rb +6 -6
  42. data/spec/rspec/mocks/mock_spec.rb +49 -43
  43. data/spec/rspec/mocks/multiple_return_value_spec.rb +26 -26
  44. data/spec/rspec/mocks/partial_mock_spec.rb +3 -2
  45. data/spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb +1 -0
  46. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -3
  47. data/spec/rspec/mocks/precise_counts_spec.rb +1 -1
  48. data/spec/rspec/mocks/serialization_spec.rb +7 -2
  49. data/spec/rspec/mocks/stub_implementation_spec.rb +6 -6
  50. data/spec/rspec/mocks/stub_spec.rb +6 -6
  51. data/spec/rspec/mocks/to_ary_spec.rb +9 -0
  52. metadata +54 -47
  53. data/.autotest +0 -7
  54. data/.document +0 -5
  55. data/.gitignore +0 -10
  56. data/.travis.yml +0 -7
  57. data/Gemfile +0 -40
  58. data/Guardfile +0 -8
  59. data/License.txt +0 -22
  60. data/Rakefile +0 -75
  61. data/autotest/discover.rb +0 -1
  62. data/cucumber.yml +0 -2
  63. data/features/.nav +0 -17
  64. data/features/Changelog.md +0 -80
  65. data/rspec-mocks.gemspec +0 -25
  66. data/specs.watchr +0 -57
@@ -6,7 +6,7 @@ Feature: stub on any instance of a class
6
6
 
7
7
  Messages can be stubbed on any class, including those in Ruby's core library.
8
8
 
9
- Scenario: simple any_instance stub with a single return value
9
+ Scenario: any_instance stub with a single return value
10
10
  Given a file named "example_spec.rb" with:
11
11
  """
12
12
  describe "any_instance.stub" do
@@ -20,4 +20,114 @@ Feature: stub on any instance of a class
20
20
  """
21
21
  When I run `rspec example_spec.rb`
22
22
  Then the examples should all pass
23
+
24
+ Scenario: any_instance stub with a hash
25
+ Given a file named "example_spec.rb" with:
26
+ """
27
+ describe "any_instance.stub" do
28
+ context "with a hash" do
29
+ it "returns the hash values on any instance of the class" do
30
+ Object.any_instance.stub(:foo => 'foo', :bar => 'bar')
31
+
32
+ o = Object.new
33
+ o.foo.should eq('foo')
34
+ o.bar.should eq('bar')
35
+ end
36
+ end
37
+ end
38
+ """
39
+ When I run `rspec example_spec.rb`
40
+ Then the examples should all pass
41
+
42
+ Scenario: any_instance stub with specific arguments matchers
43
+ Given a file named "example_spec.rb" with:
44
+ """
45
+ describe "any_instance.stub" do
46
+ context "with arguments" do
47
+ it "returns the stubbed value when arguments match" do
48
+ Object.any_instance.stub(:foo).with(:param_one, :param_two).and_return(:result_one)
49
+ Object.any_instance.stub(:foo).with(:param_three, :param_four).and_return(:result_two)
50
+
51
+ o = Object.new
52
+ o.foo(:param_one, :param_two).should eq(:result_one)
53
+ o.foo(:param_three, :param_four).should eq(:result_two)
54
+ end
55
+ end
56
+ end
57
+ """
58
+ When I run `rspec example_spec.rb`
59
+ Then the examples should all pass
60
+
61
+ Scenario: any_instance unstub
62
+ Given a file named "example_spec.rb" with:
63
+ """
64
+ describe "any_instance.unstub" do
65
+ it "unstubs a stubbed method" do
66
+ class Object
67
+ def foo
68
+ :foo
69
+ end
70
+ end
71
+
72
+ Object.any_instance.stub(:foo)
73
+ Object.any_instance.unstub(:foo)
74
+
75
+ Object.new.foo.should eq(:foo)
76
+ end
77
+ end
78
+ """
79
+ When I run `rspec example_spec.rb`
80
+ Then the examples should all pass
81
+
82
+ Scenario: any_instance unstub
83
+ Given a file named "example_spec.rb" with:
84
+ """
85
+ describe "any_instance.unstub" do
86
+ context "with both an expectation and a stub already set" do
87
+ it "only removes the stub" do
88
+ class Object
89
+ def foo
90
+ :foo
91
+ end
92
+ end
93
+ Object.any_instance.should_receive(:foo).and_return(:bar)
94
+ Object.any_instance.stub(:foo)
95
+ Object.any_instance.unstub(:foo)
96
+
97
+ Object.new.foo.should eq(:bar)
98
+ end
99
+ end
100
+ end
101
+ """
102
+ When I run `rspec example_spec.rb`
103
+ Then the examples should all pass
104
+
105
+ Scenario: stub a chain of methods an any instance
106
+ Given a file named "stub_chain_spec.rb" with:
107
+ """
108
+ describe "stubbing a chain of methods" do
109
+ context "given symbols representing methods" do
110
+ it "returns the correct value" do
111
+ Object.any_instance.stub_chain(:one, :two, :three).and_return(:four)
112
+ Object.new.one.two.three.should eq(:four)
113
+ end
114
+ end
115
+
116
+ context "given a hash at the end" do
117
+ it "returns the correct value" do
118
+ Object.any_instance.stub_chain(:one, :two, :three => :four)
119
+ Object.new.one.two.three.should eq(:four)
120
+ end
121
+ end
23
122
 
123
+ context "given a string of methods separated by dots" do
124
+ it "returns the correct value" do
125
+ Object.any_instance.stub_chain("one.two.three").and_return(:four)
126
+ Object.new.one.two.three.should eq(:four)
127
+ end
128
+ end
129
+ end
130
+ """
131
+ When I run `rspec stub_chain_spec.rb`
132
+ Then the examples should all pass
133
+
@@ -1,55 +1,64 @@
1
1
  Feature: stub with a simple return value
2
2
 
3
3
  Use the `stub` method on a test double or a real object to tell the object to
4
- return a value (or values) in response to a given message. If the message is
5
- never received, nothing happens.
4
+ return a value (or values) in response to a given message. Nothing happens if
5
+ the message is never received.
6
6
 
7
- Scenario: simple stub with no return value
7
+ Scenario: stub with no return value
8
8
  Given a file named "example_spec.rb" with:
9
9
  """
10
- describe "a simple stub with no return value specified" do
11
- let(:receiver) { double("receiver") }
10
+ describe "a stub with no return value specified" do
11
+ let(:collaborator) { double("collaborator") }
12
12
 
13
13
  it "returns nil" do
14
- receiver.stub(:message)
15
- receiver.message.should be(nil)
16
- end
17
-
18
- it "quietly carries on when not called" do
19
- receiver.stub(:message)
14
+ collaborator.stub(:message)
15
+ collaborator.message.should be(nil)
20
16
  end
21
17
  end
22
18
  """
23
19
  When I run `rspec example_spec.rb`
24
- Then the output should contain "0 failures"
20
+ Then the examples should all pass
25
21
 
26
- Scenario: single return value
22
+ Scenario: stubs with return values
27
23
  Given a file named "example_spec.rb" with:
28
24
  """
29
- describe "a simple stub with a return value" do
25
+ describe "a stub with a return value" do
30
26
  context "specified in a block" do
31
27
  it "returns the specified value" do
32
- receiver = double("receiver")
33
- receiver.stub(:message) { :return_value }
34
- receiver.message.should eq(:return_value)
28
+ collaborator = double("collaborator")
29
+ collaborator.stub(:message) { :value }
30
+ collaborator.message.should eq(:value)
31
+ end
32
+ end
33
+
34
+ context "specified with #and_return" do
35
+ it "returns the specified value" do
36
+ collaborator = double("collaborator")
37
+ collaborator.stub(:message).and_return(:value)
38
+ collaborator.message.should eq(:value)
35
39
  end
36
40
  end
37
41
 
38
- context "specified in the double declaration" do
42
+ context "specified with a hash passed to #stub" do
39
43
  it "returns the specified value" do
40
- receiver = double("receiver", :message => :return_value)
41
- receiver.message.should eq(:return_value)
44
+ collaborator = double("collaborator")
45
+ collaborator.stub(:message_1 => :value_1, :message_2 => :value_2)
46
+ collaborator.message_1.should eq(:value_1)
47
+ collaborator.message_2.should eq(:value_2)
42
48
  end
43
49
  end
44
50
 
45
- context "specified with and_return" do
51
+ context "specified with a hash passed to #double" do
46
52
  it "returns the specified value" do
47
- receiver = double("receiver")
48
- receiver.stub(:message).and_return(:return_value)
49
- receiver.message.should eq(:return_value)
53
+ collaborator = double("collaborator",
54
+ :message_1 => :value_1,
55
+ :message_2 => :value_2
56
+ )
57
+ collaborator.message_1.should eq(:value_1)
58
+ collaborator.message_2.should eq(:value_2)
50
59
  end
51
60
  end
52
61
  end
53
62
  """
54
63
  When I run `rspec example_spec.rb`
55
- Then the output should contain "0 failures"
64
+ Then the examples should all pass
@@ -1,7 +1,7 @@
1
1
  Feature: stub with substitute implementation
2
2
 
3
3
  You can stub an implementation of a method (a.k.a. fake) by passing a block
4
- to the stub() method.
4
+ to the `stub` method.
5
5
 
6
6
  Scenario: stub implementation
7
7
  Given a file named "stub_implementation_spec.rb" with:
@@ -1,22 +1,24 @@
1
1
  Feature: double handling to_ary
2
2
 
3
- Ruby implicitly sends to_ary to any objects in an Array when the array
4
- receives `flatten`:
3
+ Ruby implicitly sends `to_ary` to all of the objects in an `Array` when the
4
+ array receives `flatten`:
5
5
 
6
6
  [obj].flatten # => obj.to_ary
7
7
 
8
+ If `to_ary` raises a `NoMethodError`, Ruby sees that the object can not be coerced
9
+ into an array and moves on to the next object.
10
+
8
11
  To support this, an RSpec double will raise a NoMethodError when it receives
9
- `to_ary`, unless that method is explicitly stubbed.
12
+ `to_ary` _even if it is set `as_null_object`_, unless `to_ary` is explicitly
13
+ stubbed.
10
14
 
11
15
  Scenario: double receiving to_ary
12
16
  Given a file named "example.rb" with:
13
17
  """
14
- describe "a double receiving to_ary" do
18
+ describe "#to_ary" do
15
19
  shared_examples "to_ary" do
16
- it "returns nil" do
17
- expect do
18
- obj.to_ary.should be_nil
19
- end.to raise_error(NoMethodError)
20
+ it "raises a NoMethodError" do
21
+ expect { obj.to_ary }.to raise_error(NoMethodError)
20
22
  end
21
23
 
22
24
  it "can be overridden with a stub" do
@@ -30,12 +32,12 @@ Feature: double handling to_ary
30
32
  end
31
33
  end
32
34
 
33
- context "double as_null_object" do
35
+ context "sent to a double as_null_object" do
34
36
  let(:obj) { double('obj').as_null_object }
35
37
  include_examples "to_ary"
36
38
  end
37
39
 
38
- context "double without as_null_object" do
40
+ context "sent to a double without as_null_object" do
39
41
  let(:obj) { double('obj') }
40
42
  include_examples "to_ary"
41
43
  end
@@ -2,5 +2,5 @@ require 'aruba/cucumber'
2
2
  require 'rspec/expectations'
3
3
 
4
4
  Before do
5
- @aruba_timeout_seconds = 3
5
+ RUBY_PLATFORM =~ /java/ ? @aruba_timeout_seconds = 60 : @aruba_timeout_seconds = 5
6
6
  end
@@ -152,7 +152,7 @@ module RSpec
152
152
  #
153
153
  # double.should_receive(:msg) do |arg|
154
154
  # arg.should be_an_istance_of(Array)
155
- # arg.length.should == 7
155
+ # arg.length.should eq 7
156
156
  # end
157
157
  #
158
158
  # == Combining Expectation Details
@@ -1,245 +1,18 @@
1
+ require 'rspec/mocks/any_instance/chain'
2
+ require 'rspec/mocks/any_instance/stub_chain'
3
+ require 'rspec/mocks/any_instance/stub_chain_chain'
4
+ require 'rspec/mocks/any_instance/expectation_chain'
5
+ require 'rspec/mocks/any_instance/message_chains'
6
+ require 'rspec/mocks/any_instance/recorder'
7
+
1
8
  module RSpec
2
9
  module Mocks
3
10
  module AnyInstance
4
- class Chain
5
- [
6
- :with, :and_return, :and_raise, :and_yield,
7
- :once, :twice, :any_number_of_times,
8
- :exactly, :times, :never,
9
- :at_least, :at_most
10
- ].each do |method_name|
11
- class_eval(<<-EOM, __FILE__, __LINE__)
12
- def #{method_name}(*args, &block)
13
- record(:#{method_name}, *args, &block)
14
- end
15
- EOM
16
- end
17
-
18
- def playback!(instance)
19
- messages.inject(instance) do |instance, message|
20
- instance.send(*message.first, &message.last)
21
- end
22
- end
23
-
24
- def constrained_to_any_of?(*constraints)
25
- constraints.any? do |constraint|
26
- messages.any? do |message|
27
- message.first.first == constraint
28
- end
29
- end
30
- end
31
-
32
- private
33
- def messages
34
- @messages ||= []
35
- end
36
-
37
- def last_message
38
- messages.last.first.first unless messages.empty?
39
- end
40
-
41
- def record(rspec_method_name, *args, &block)
42
- verify_invocation_order(rspec_method_name, *args, &block)
43
- messages << [args.unshift(rspec_method_name), block]
44
- self
45
- end
46
- end
47
-
48
- class StubChain < Chain
49
- def initialize(*args, &block)
50
- record(:stub, *args, &block)
51
- end
52
-
53
- def invocation_order
54
- @invocation_order ||= {
55
- :stub => [nil],
56
- :with => [:stub],
57
- :and_return => [:with, :stub],
58
- :and_raise => [:with, :stub],
59
- :and_yield => [:with, :stub]
60
- }
61
- end
62
-
63
- def expectation_filfilled?
64
- true
65
- end
66
-
67
- private
68
- def verify_invocation_order(rspec_method_name, *args, &block)
69
- unless invocation_order[rspec_method_name].include?(last_message)
70
- raise(NoMethodError, "Undefined method #{rspec_method_name}")
71
- end
72
- end
73
- end
74
-
75
- class ExpectationChain < Chain
76
- def initialize(*args, &block)
77
- record(:should_receive, *args, &block)
78
- @expectation_fulfilled = false
79
- end
80
-
81
- def invocation_order
82
- @invocation_order ||= {
83
- :should_receive => [nil],
84
- :with => [:should_receive],
85
- :and_return => [:with, :should_receive],
86
- :and_raise => [:with, :should_receive]
87
- }
88
- end
89
-
90
- def expectation_fulfilled!
91
- @expectation_fulfilled = true
92
- end
93
-
94
- def expectation_filfilled?
95
- @expectation_fulfilled || constrained_to_any_of?(:never, :any_number_of_times)
96
- end
97
-
98
- private
99
- def verify_invocation_order(rspec_method_name, *args, &block)
100
- end
101
- end
102
-
103
- class Recorder
104
- def initialize(klass)
105
- @message_chains = {}
106
- @observed_methods = []
107
- @played_methods = {}
108
- @klass = klass
109
- @expectation_set = false
110
- end
111
-
112
- def stub(method_name, *args, &block)
113
- observe!(method_name)
114
- @message_chains[method_name] = StubChain.new(method_name, *args, &block)
115
- end
116
-
117
- def should_receive(method_name, *args, &block)
118
- observe!(method_name)
119
- @expectation_set = true
120
- @message_chains[method_name] = ExpectationChain.new(method_name, *args, &block)
121
- end
122
-
123
- def stop_all_observation!
124
- @observed_methods.each do |method_name|
125
- restore_method!(method_name)
126
- end
127
- end
128
-
129
- def playback!(instance, method_name)
130
- RSpec::Mocks::space.add(instance)
131
- @message_chains[method_name].playback!(instance)
132
- @played_methods[method_name] = instance
133
- received_expected_message!(method_name) if has_expectation?(method_name)
134
- end
135
-
136
- def instance_that_received(method_name)
137
- @played_methods[method_name]
138
- end
139
-
140
- def verify
141
- if @expectation_set && !each_expectation_filfilled?
142
- raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
143
- end
144
- end
145
-
146
- private
147
- def each_expectation_filfilled?
148
- @message_chains.all? do |method_name, chain|
149
- chain.expectation_filfilled?
150
- end
151
- end
152
-
153
- def has_expectation?(method_name)
154
- @message_chains[method_name].is_a?(ExpectationChain)
155
- end
156
-
157
- def unfulfilled_expectations
158
- @message_chains.map do |method_name, chain|
159
- method_name.to_s if chain.is_a?(ExpectationChain) unless chain.expectation_filfilled?
160
- end.compact
161
- end
162
-
163
- def received_expected_message!(method_name)
164
- @message_chains[method_name].expectation_fulfilled!
165
- restore_method!(method_name)
166
- mark_invoked!(method_name)
167
- end
168
-
169
- def restore_method!(method_name)
170
- if @klass.method_defined?(build_alias_method_name(method_name))
171
- restore_original_method!(method_name)
172
- else
173
- remove_dummy_method!(method_name)
174
- end
175
- end
176
-
177
- def build_alias_method_name(method_name)
178
- "__#{method_name}_without_any_instance__"
179
- end
180
-
181
- def restore_original_method!(method_name)
182
- alias_method_name = build_alias_method_name(method_name)
183
- @klass.class_eval do
184
- alias_method method_name, alias_method_name
185
- remove_method alias_method_name
186
- end
187
- end
188
-
189
- def remove_dummy_method!(method_name)
190
- @klass.class_eval do
191
- remove_method method_name
192
- end
193
- end
194
-
195
- def backup_method!(method_name)
196
- alias_method_name = build_alias_method_name(method_name)
197
- @klass.class_eval do
198
- if method_defined?(method_name)
199
- alias_method alias_method_name, method_name
200
- end
201
- end
202
- end
203
-
204
- def stop_observing!(method_name)
205
- restore_method!(method_name)
206
- @observed_methods.delete(method_name)
207
- end
208
-
209
- def already_observing?(method_name)
210
- @observed_methods.include?(method_name)
211
- end
212
-
213
- def observe!(method_name)
214
- stop_observing!(method_name) if already_observing?(method_name)
215
- @observed_methods << method_name
216
- backup_method!(method_name)
217
- @klass.class_eval(<<-EOM, __FILE__, __LINE__)
218
- def #{method_name}(*args, &blk)
219
- self.class.__recorder.playback!(self, :#{method_name})
220
- self.send(:#{method_name}, *args, &blk)
221
- end
222
- EOM
223
- end
224
-
225
- def mark_invoked!(method_name)
226
- backup_method!(method_name)
227
- @klass.class_eval(<<-EOM, __FILE__, __LINE__)
228
- def #{method_name}(*args, &blk)
229
- method_name = :#{method_name}
230
- current_instance = self
231
- invoked_instance = self.class.__recorder.instance_that_received(method_name)
232
- raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
233
- end
234
- EOM
235
- end
236
- end
237
-
238
11
  def any_instance
239
12
  RSpec::Mocks::space.add(self)
240
13
  __recorder
241
14
  end
242
-
15
+
243
16
  def rspec_verify
244
17
  __recorder.verify
245
18
  super