rspec-mocks 2.0.0.a1

Sign up to get free protection for your applications and to get access to all the features.
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