rspec-mocks 2.0.0.a1

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 (62) hide show
  1. data/.document +5 -0
  2. data/.gitignore +6 -0
  3. data/License.txt +22 -0
  4. data/README.markdown +8 -0
  5. data/Rakefile +50 -0
  6. data/VERSION +1 -0
  7. data/VERSION.yml +5 -0
  8. data/lib/rspec/mocks.rb +201 -0
  9. data/lib/rspec/mocks/argument_expectation.rb +51 -0
  10. data/lib/rspec/mocks/argument_matchers.rb +233 -0
  11. data/lib/rspec/mocks/error_generator.rb +81 -0
  12. data/lib/rspec/mocks/errors.rb +10 -0
  13. data/lib/rspec/mocks/extensions.rb +1 -0
  14. data/lib/rspec/mocks/extensions/object.rb +3 -0
  15. data/lib/rspec/mocks/framework.rb +15 -0
  16. data/lib/rspec/mocks/message_expectation.rb +326 -0
  17. data/lib/rspec/mocks/methods.rb +63 -0
  18. data/lib/rspec/mocks/mock.rb +65 -0
  19. data/lib/rspec/mocks/order_group.rb +29 -0
  20. data/lib/rspec/mocks/proxy.rb +230 -0
  21. data/lib/rspec/mocks/space.rb +28 -0
  22. data/lib/rspec/mocks/spec_methods.rb +39 -0
  23. data/lib/spec/mocks.rb +1 -0
  24. data/spec/rspec/mocks/any_number_of_times_spec.rb +36 -0
  25. data/spec/rspec/mocks/argument_expectation_spec.rb +23 -0
  26. data/spec/rspec/mocks/at_least_spec.rb +97 -0
  27. data/spec/rspec/mocks/at_most_spec.rb +93 -0
  28. data/spec/rspec/mocks/bug_report_10260_spec.rb +8 -0
  29. data/spec/rspec/mocks/bug_report_10263_spec.rb +27 -0
  30. data/spec/rspec/mocks/bug_report_11545_spec.rb +32 -0
  31. data/spec/rspec/mocks/bug_report_15719_spec.rb +29 -0
  32. data/spec/rspec/mocks/bug_report_496_spec.rb +17 -0
  33. data/spec/rspec/mocks/bug_report_600_spec.rb +22 -0
  34. data/spec/rspec/mocks/bug_report_7611_spec.rb +19 -0
  35. data/spec/rspec/mocks/bug_report_7805_spec.rb +22 -0
  36. data/spec/rspec/mocks/bug_report_8165_spec.rb +31 -0
  37. data/spec/rspec/mocks/bug_report_8302_spec.rb +26 -0
  38. data/spec/rspec/mocks/bug_report_830_spec.rb +21 -0
  39. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +95 -0
  40. data/spec/rspec/mocks/hash_including_matcher_spec.rb +90 -0
  41. data/spec/rspec/mocks/hash_not_including_matcher_spec.rb +67 -0
  42. data/spec/rspec/mocks/mock_ordering_spec.rb +94 -0
  43. data/spec/rspec/mocks/mock_space_spec.rb +54 -0
  44. data/spec/rspec/mocks/mock_spec.rb +583 -0
  45. data/spec/rspec/mocks/multiple_return_value_spec.rb +113 -0
  46. data/spec/rspec/mocks/nil_expectation_warning_spec.rb +63 -0
  47. data/spec/rspec/mocks/null_object_mock_spec.rb +54 -0
  48. data/spec/rspec/mocks/once_counts_spec.rb +53 -0
  49. data/spec/rspec/mocks/options_hash_spec.rb +35 -0
  50. data/spec/rspec/mocks/partial_mock_spec.rb +164 -0
  51. data/spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb +66 -0
  52. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +145 -0
  53. data/spec/rspec/mocks/precise_counts_spec.rb +52 -0
  54. data/spec/rspec/mocks/record_messages_spec.rb +26 -0
  55. data/spec/rspec/mocks/stub_chain_spec.rb +34 -0
  56. data/spec/rspec/mocks/stub_implementation_spec.rb +31 -0
  57. data/spec/rspec/mocks/stub_spec.rb +198 -0
  58. data/spec/rspec/mocks/stubbed_message_expectations_spec.rb +26 -0
  59. data/spec/rspec/mocks/twice_counts_spec.rb +67 -0
  60. data/spec/spec_helper.rb +52 -0
  61. data/spec/support/macros.rb +29 -0
  62. metadata +172 -0
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,6 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ rspec-mocks.gemspec
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2005-2009 The RSpec Development Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,8 @@
1
+ # RSpec Mocks
2
+
3
+ See README.markdown at [http://github.com/rspec/meta](http://github.com/rspec/meta)
4
+
5
+ #### Also see
6
+
7
+ * [http://github.com/rspec/core](http://github.com/rspec/core)
8
+ * [http://github.com/rspec/expectations](http://github.com/rspec/expectations)
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rspec-mocks"
8
+ gem.summary = "rspec-mocks"
9
+ gem.email = "dchelimsky@gmail.com;chad.humphries@gmail.com"
10
+ gem.homepage = "http://github.com/rspec/mocks"
11
+ gem.authors = ["David Chelimsky", "Chad Humphries"]
12
+ gem.add_development_dependency('rspec-core', '>= 2.0.0.a1')
13
+ gem.add_development_dependency('rspec-expectations', '>= 2.0.0.a1')
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ $:.unshift File.join(File.dirname(__FILE__), "/../core/lib")
22
+ require 'rspec/core/rake_task'
23
+ Rspec::Core::RakeTask.new(:spec) do |spec|
24
+ spec.pattern = 'spec/**/*_spec.rb'
25
+ end
26
+
27
+ Rspec::Core::RakeTask.new(:rcov) do |spec|
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.rcov = true
30
+ spec.rcov_opts = %[--exclude "core,expectations,gems/*,spec/resources,spec/spec,spec/spec_helper.rb,db/*,/Library/Ruby/*,config/*" --text-summary --sort coverage]
31
+ end
32
+
33
+
34
+ task :default => :spec
35
+
36
+ require 'rake/rdoctask'
37
+ Rake::RDocTask.new do |rdoc|
38
+ if File.exist?('VERSION.yml')
39
+ config = YAML.load(File.read('VERSION.yml'))
40
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
41
+ else
42
+ version = ""
43
+ end
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "rspec-mocks #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
50
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.0.a1
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 2
3
+ :minor: 0
4
+ :patch: 0
5
+ :build: a1
@@ -0,0 +1,201 @@
1
+ require 'rspec/mocks/framework'
2
+ require 'rspec/mocks/extensions/object'
3
+
4
+ module Rspec
5
+ # == Mocks and Stubs
6
+ #
7
+ # RSpec will create Mock Objects and Stubs for you at runtime, or attach stub/mock behaviour
8
+ # to any of your real objects (Partial Mock/Stub). Because the underlying implementation
9
+ # for mocks and stubs is the same, you can intermingle mock and stub
10
+ # behaviour in either dynamically generated mocks or your pre-existing classes.
11
+ # There is a semantic difference in how they are created, however,
12
+ # which can help clarify the role it is playing within a given spec.
13
+ #
14
+ # == Mock Objects
15
+ #
16
+ # Mocks are objects that allow you to set and verify expectations that they will
17
+ # receive specific messages during run time. They are very useful for specifying how the subject of
18
+ # the spec interacts with its collaborators. This approach is widely known as "interaction
19
+ # testing".
20
+ #
21
+ # Mocks are also very powerful as a design tool. As you are
22
+ # driving the implementation of a given class, Mocks provide an anonymous
23
+ # collaborator that can change in behaviour as quickly as you can write an expectation in your
24
+ # spec. This flexibility allows you to design the interface of a collaborator that often
25
+ # does not yet exist. As the shape of the class being specified becomes more clear, so do the
26
+ # requirements for its collaborators - often leading to the discovery of new types that are
27
+ # needed in your system.
28
+ #
29
+ # Read Endo-Testing[http://www.mockobjects.com/files/endotesting.pdf] for a much
30
+ # more in depth description of this process.
31
+ #
32
+ # == Stubs
33
+ #
34
+ # Stubs are objects that allow you to set "stub" responses to
35
+ # messages. As Martin Fowler points out on his site,
36
+ # mocks_arent_stubs[http://www.martinfowler.com/articles/mocksArentStubs.html].
37
+ # Paraphrasing Fowler's paraphrasing
38
+ # of Gerard Meszaros: Stubs provide canned responses to messages they might receive in a test, while
39
+ # mocks allow you to specify and, subsquently, verify that certain messages should be received during
40
+ # the execution of a test.
41
+ #
42
+ # == Partial Mocks/Stubs
43
+ #
44
+ # RSpec also supports partial mocking/stubbing, allowing you to add stub/mock behaviour
45
+ # to instances of your existing classes. This is generally
46
+ # something to be avoided, because changes to the class can have ripple effects on
47
+ # seemingly unrelated specs. When specs fail due to these ripple effects, the fact
48
+ # that some methods are being mocked can make it difficult to understand why a
49
+ # failure is occurring.
50
+ #
51
+ # That said, partials do allow you to expect and
52
+ # verify interactions with class methods such as +#find+ and +#create+
53
+ # on Ruby on Rails model classes.
54
+ #
55
+ # == Further Reading
56
+ #
57
+ # There are many different viewpoints about the meaning of mocks and stubs. If you are interested
58
+ # in learning more, here is some recommended reading:
59
+ #
60
+ # * Mock Objects: http://www.mockobjects.com/
61
+ # * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
62
+ # * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
63
+ # * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
64
+ # * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
65
+ #
66
+ # == Creating a Mock
67
+ #
68
+ # You can create a mock in any specification (or setup) using:
69
+ #
70
+ # mock(name, options={})
71
+ #
72
+ # The optional +options+ argument is a +Hash+. Currently the only supported
73
+ # option is +:null_object+. Setting this to true instructs the mock to ignore
74
+ # any messages it hasn’t been told to expect – and quietly return itself. For example:
75
+ #
76
+ # mock("person", :null_object => true)
77
+ #
78
+ # == Creating a Stub
79
+ #
80
+ # You can create a stub in any specification (or setup) using:
81
+ #
82
+ # stub(name, stub_methods_and_values_hash)
83
+ #
84
+ # For example, if you wanted to create an object that always returns
85
+ # "More?!?!?!" to "please_sir_may_i_have_some_more" you would do this:
86
+ #
87
+ # stub("Mr Sykes", :please_sir_may_i_have_some_more => "More?!?!?!")
88
+ #
89
+ # == Creating a Partial Mock
90
+ #
91
+ # You don't really "create" a partial mock, you simply add method stubs and/or
92
+ # mock expectations to existing classes and objects:
93
+ #
94
+ # Factory.should_receive(:find).with(id).and_return(value)
95
+ # obj.stub!(:to_i).and_return(3)
96
+ # etc ...
97
+ #
98
+ # == Expecting Messages
99
+ #
100
+ # my_mock.should_receive(:sym)
101
+ # my_mock.should_not_receive(:sym)
102
+ #
103
+ # == Expecting Arguments
104
+ #
105
+ # my_mock.should_receive(:sym).with(*args)
106
+ # my_mock.should_not_receive(:sym).with(*args)
107
+ #
108
+ # == Argument Matchers
109
+ #
110
+ # Arguments that are passed to #with are compared with actual arguments received
111
+ # using == by default. In cases in which you want to specify things about the arguments
112
+ # rather than the arguments themselves, you can use any of RSpec's Expression Matchers.
113
+ # They don't all make syntactic sense (they were primarily designed for use with
114
+ # Rspec::Expectations), but you are free to create your own custom Rspec::Matchers.
115
+ #
116
+ # Rspec::Mocks does provide one additional Matcher method named #ducktype.
117
+ #
118
+ # In addition, Rspec::Mocks adds some keyword Symbols that you can use to
119
+ # specify certain kinds of arguments:
120
+ #
121
+ # my_mock.should_receive(:sym).with(no_args())
122
+ # my_mock.should_receive(:sym).with(any_args())
123
+ # my_mock.should_receive(:sym).with(1, kind_of(Numeric), "b") #2nd argument can any kind of Numeric
124
+ # my_mock.should_receive(:sym).with(1, boolean(), "b") #2nd argument can true or false
125
+ # my_mock.should_receive(:sym).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
126
+ # my_mock.should_receive(:sym).with(1, anything(), "b") #2nd argument can be anything at all
127
+ # my_mock.should_receive(:sym).with(1, ducktype(:abs, :div), "b")
128
+ # #2nd argument can be object that responds to #abs and #div
129
+ #
130
+ # == Receive Counts
131
+ #
132
+ # my_mock.should_receive(:sym).once
133
+ # my_mock.should_receive(:sym).twice
134
+ # my_mock.should_receive(:sym).exactly(n).times
135
+ # my_mock.should_receive(:sym).at_least(:once)
136
+ # my_mock.should_receive(:sym).at_least(:twice)
137
+ # my_mock.should_receive(:sym).at_least(n).times
138
+ # my_mock.should_receive(:sym).at_most(:once)
139
+ # my_mock.should_receive(:sym).at_most(:twice)
140
+ # my_mock.should_receive(:sym).at_most(n).times
141
+ # my_mock.should_receive(:sym).any_number_of_times
142
+ #
143
+ # == Ordering
144
+ #
145
+ # my_mock.should_receive(:sym).ordered
146
+ # my_mock.should_receive(:other_sym).ordered
147
+ # #This will fail if the messages are received out of order
148
+ #
149
+ # == Setting Reponses
150
+ #
151
+ # Whether you are setting a mock expectation or a simple stub, you can tell the
152
+ # object precisely how to respond:
153
+ #
154
+ # my_mock.should_receive(:sym).and_return(value)
155
+ # my_mock.should_receive(:sym).exactly(3).times.and_return(value1, value2, value3)
156
+ # # returns value1 the first time, value2 the second, etc
157
+ # my_mock.should_receive(:sym).and_return { ... } #returns value returned by the block
158
+ # my_mock.should_receive(:sym).and_raise(error)
159
+ # #error can be an instantiated object or a class
160
+ # #if it is a class, it must be instantiable with no args
161
+ # my_mock.should_receive(:sym).and_throw(:sym)
162
+ # my_mock.should_receive(:sym).and_yield(values,to,yield)
163
+ # my_mock.should_receive(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
164
+ # # for methods that yield to a block multiple times
165
+ #
166
+ # Any of these responses can be applied to a stub as well, but stubs do
167
+ # not support any qualifiers about the message received (i.e. you can't specify arguments
168
+ # or receive counts):
169
+ #
170
+ # my_mock.stub!(:sym).and_return(value)
171
+ # my_mock.stub!(:sym).and_return(value1, value2, value3)
172
+ # my_mock.stub!(:sym).and_raise(error)
173
+ # my_mock.stub!(:sym).and_throw(:sym)
174
+ # my_mock.stub!(:sym).and_yield(values,to,yield)
175
+ # my_mock.stub!(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
176
+ #
177
+ # == Arbitrary Handling
178
+ #
179
+ # Once in a while you'll find that the available expectations don't solve the
180
+ # particular problem you are trying to solve. Imagine that you expect the message
181
+ # to come with an Array argument that has a specific length, but you don't care
182
+ # what is in it. You could do this:
183
+ #
184
+ # my_mock.should_receive(:sym) do |arg|
185
+ # arg.should be_an_istance_of(Array)
186
+ # arg.length.should == 7
187
+ # end
188
+ #
189
+ # Note that this would fail if the number of arguments received was different from
190
+ # the number of block arguments (in this case 1).
191
+ #
192
+ # == Combining Expectation Details
193
+ #
194
+ # Combining the message name with specific arguments, receive counts and responses
195
+ # you can get quite a bit of detail in your expectations:
196
+ #
197
+ # my_mock.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
198
+ module Mocks
199
+ end
200
+
201
+ end
@@ -0,0 +1,51 @@
1
+ module Rspec
2
+ module Mocks
3
+
4
+ class ArgumentExpectation
5
+ attr_reader :args
6
+
7
+ def initialize(args, &block)
8
+ @args = args
9
+ @matchers_block = block
10
+ @match_any_args = false
11
+ @matchers = nil
12
+
13
+ if ArgumentMatchers::AnyArgsMatcher === args.first
14
+ @match_any_args = true
15
+ elsif ArgumentMatchers::NoArgsMatcher === args.first
16
+ @matchers = []
17
+ else
18
+ @matchers = args.collect {|arg| matcher_for(arg)}
19
+ end
20
+ end
21
+
22
+ def matcher_for(arg)
23
+ return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
24
+ return ArgumentMatchers::RegexpMatcher.new(arg) if arg.is_a?(Regexp)
25
+ return ArgumentMatchers::EqualityProxy.new(arg)
26
+ end
27
+
28
+ def is_matcher?(obj)
29
+ return obj.respond_to?(:matches?) & obj.respond_to?(:description)
30
+ end
31
+
32
+ def args_match?(given_args)
33
+ match_any_args? || matchers_block_matches?(given_args) || matchers_match?(given_args)
34
+ end
35
+
36
+ def matchers_block_matches?(given_args)
37
+ @matchers_block ? @matchers_block.call(*given_args) : nil
38
+ end
39
+
40
+ def matchers_match?(given_args)
41
+ @matchers == given_args
42
+ end
43
+
44
+ def match_any_args?
45
+ @match_any_args
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,233 @@
1
+ module Rspec
2
+ module Mocks
3
+
4
+ # ArgumentMatchers are messages that you can include in message
5
+ # expectations to match arguments against a broader check than simple
6
+ # equality.
7
+ #
8
+ # With the exception of any_args() and no_args(), the matchers
9
+ # are all positional - they match against the arg in the given position.
10
+ module ArgumentMatchers
11
+
12
+ class AnyArgsMatcher
13
+ def description
14
+ "any args"
15
+ end
16
+ end
17
+
18
+ class AnyArgMatcher
19
+ def initialize(ignore)
20
+ end
21
+
22
+ def ==(other)
23
+ true
24
+ end
25
+ end
26
+
27
+ class NoArgsMatcher
28
+ def description
29
+ "no args"
30
+ end
31
+ end
32
+
33
+ class RegexpMatcher
34
+ def initialize(regexp)
35
+ @regexp = regexp
36
+ end
37
+
38
+ def ==(value)
39
+ return value =~ @regexp unless value.is_a?(Regexp)
40
+ value == @regexp
41
+ end
42
+ end
43
+
44
+ class BooleanMatcher
45
+ def initialize(ignore)
46
+ end
47
+
48
+ def ==(value)
49
+ TrueClass === value || FalseClass === value
50
+ end
51
+ end
52
+
53
+ class HashIncludingMatcher
54
+ def initialize(expected)
55
+ @expected = expected
56
+ end
57
+
58
+ def ==(actual)
59
+ @expected.each do | key, value |
60
+ return false unless actual.has_key?(key) && value == actual[key]
61
+ end
62
+ true
63
+ rescue NoMethodError => ex
64
+ return false
65
+ end
66
+
67
+ def description
68
+ "hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
69
+ end
70
+ end
71
+
72
+ class HashNotIncludingMatcher
73
+ def initialize(expected)
74
+ @expected = expected
75
+ end
76
+
77
+ def ==(actual)
78
+ @expected.each do | key, value |
79
+ return false if actual.has_key?(key) && value == actual[key]
80
+ end
81
+ true
82
+ rescue NoMethodError => ex
83
+ return false
84
+ end
85
+
86
+ def description
87
+ "hash_not_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
88
+ end
89
+ end
90
+
91
+ class DuckTypeMatcher
92
+ def initialize(*methods_to_respond_to)
93
+ @methods_to_respond_to = methods_to_respond_to
94
+ end
95
+
96
+ def ==(value)
97
+ @methods_to_respond_to.all? { |sym| value.respond_to?(sym) }
98
+ end
99
+ end
100
+
101
+ class MatcherMatcher
102
+ def initialize(matcher)
103
+ @matcher = matcher
104
+ end
105
+
106
+ def ==(value)
107
+ @matcher.matches?(value)
108
+ end
109
+ end
110
+
111
+ class EqualityProxy
112
+ def initialize(given)
113
+ @given = given
114
+ end
115
+
116
+ def ==(expected)
117
+ @given == expected
118
+ end
119
+ end
120
+
121
+ class InstanceOf
122
+ def initialize(klass)
123
+ @klass = klass
124
+ end
125
+
126
+ def ==(actual)
127
+ actual.instance_of?(@klass)
128
+ end
129
+ end
130
+
131
+ class KindOf
132
+ def initialize(klass)
133
+ @klass = klass
134
+ end
135
+
136
+ def ==(actual)
137
+ actual.kind_of?(@klass)
138
+ end
139
+ end
140
+
141
+ # :call-seq:
142
+ # object.should_receive(:message).with(any_args())
143
+ #
144
+ # Passes if object receives :message with any args at all. This is
145
+ # really a more explicit variation of object.should_receive(:message)
146
+ def any_args
147
+ AnyArgsMatcher.new
148
+ end
149
+
150
+ # :call-seq:
151
+ # object.should_receive(:message).with(anything())
152
+ #
153
+ # Passes as long as there is an argument.
154
+ def anything
155
+ AnyArgMatcher.new(nil)
156
+ end
157
+
158
+ # :call-seq:
159
+ # object.should_receive(:message).with(no_args)
160
+ #
161
+ # Passes if no arguments are passed along with the message
162
+ def no_args
163
+ NoArgsMatcher.new
164
+ end
165
+
166
+ # :call-seq:
167
+ # object.should_receive(:message).with(duck_type(:hello))
168
+ # object.should_receive(:message).with(duck_type(:hello, :goodbye))
169
+ #
170
+ # Passes if the argument responds to the specified messages.
171
+ #
172
+ # == Examples
173
+ #
174
+ # array = []
175
+ # display = mock('display')
176
+ # display.should_receive(:present_names).with(duck_type(:length, :each))
177
+ # => passes
178
+ def duck_type(*args)
179
+ DuckTypeMatcher.new(*args)
180
+ end
181
+
182
+ # :call-seq:
183
+ # object.should_receive(:message).with(boolean())
184
+ #
185
+ # Passes if the argument is boolean.
186
+ def boolean
187
+ BooleanMatcher.new(nil)
188
+ end
189
+
190
+ # :call-seq:
191
+ # object.should_receive(:message).with(hash_including(:key => val))
192
+ # object.should_receive(:message).with(hash_including(:key))
193
+ # object.should_receive(:message).with(hash_including(:key, :key2 => val2))
194
+ # Passes if the argument is a hash that includes the specified key(s) or key/value
195
+ # pairs. If the hash includes other keys, it will still pass.
196
+ def hash_including(*args)
197
+ HashIncludingMatcher.new(anythingize_lonely_keys(*args))
198
+ end
199
+
200
+ # :call-seq:
201
+ # object.should_receive(:message).with(hash_not_including(:key => val))
202
+ # object.should_receive(:message).with(hash_not_including(:key))
203
+ # object.should_receive(:message).with(hash_not_including(:key, :key2 => :val2))
204
+ #
205
+ # Passes if the argument is a hash that doesn't include the specified key(s) or key/value
206
+ def hash_not_including(*args)
207
+ HashNotIncludingMatcher.new(anythingize_lonely_keys(*args))
208
+ end
209
+
210
+ # Passes if arg.instance_of?(klass)
211
+ def instance_of(klass)
212
+ InstanceOf.new(klass)
213
+ end
214
+
215
+ alias_method :an_instance_of, :instance_of
216
+
217
+ # Passes if arg.kind_of?(klass)
218
+ def kind_of(klass)
219
+ KindOf.new(klass)
220
+ end
221
+
222
+ alias_method :a_kind_of, :kind_of
223
+
224
+ private
225
+
226
+ def anythingize_lonely_keys(*args)
227
+ hash = args.last.class == Hash ? args.delete_at(-1) : {}
228
+ args.each { | arg | hash[arg] = anything }
229
+ hash
230
+ end
231
+ end
232
+ end
233
+ end