mocha 0.4.0 → 0.5.0

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 (78) hide show
  1. data/Rakefile +28 -10
  2. data/examples/stubba.rb +1 -1
  3. data/lib/mocha/auto_verify.rb +6 -6
  4. data/lib/mocha/deprecation.rb +22 -0
  5. data/lib/mocha/exception_raiser.rb +17 -0
  6. data/lib/mocha/expectation.rb +167 -84
  7. data/lib/mocha/infinite_range.rb +4 -6
  8. data/lib/mocha/inspect.rb +3 -1
  9. data/lib/mocha/is_a.rb +9 -0
  10. data/lib/mocha/missing_expectation.rb +27 -0
  11. data/lib/mocha/mock.rb +191 -5
  12. data/lib/mocha/multiple_yields.rb +20 -0
  13. data/lib/mocha/no_yields.rb +11 -0
  14. data/lib/mocha/object.rb +11 -1
  15. data/lib/mocha/parameter_matchers.rb +9 -0
  16. data/lib/mocha/parameter_matchers/all_of.rb +39 -0
  17. data/lib/mocha/parameter_matchers/any_of.rb +44 -0
  18. data/lib/mocha/parameter_matchers/anything.rb +30 -0
  19. data/lib/mocha/parameter_matchers/has_entry.rb +39 -0
  20. data/lib/mocha/parameter_matchers/has_key.rb +39 -0
  21. data/lib/mocha/parameter_matchers/has_value.rb +39 -0
  22. data/lib/mocha/parameter_matchers/includes.rb +37 -0
  23. data/lib/mocha/return_values.rb +31 -0
  24. data/lib/mocha/single_return_value.rb +24 -0
  25. data/lib/mocha/single_yield.rb +18 -0
  26. data/lib/mocha/standalone.rb +2 -0
  27. data/lib/mocha/stub.rb +18 -0
  28. data/lib/mocha/yield_parameters.rb +31 -0
  29. data/test/{mocha_acceptance_test.rb → acceptance/mocha_acceptance_test.rb} +1 -1
  30. data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +72 -0
  31. data/test/acceptance/parameter_matcher_acceptance_test.rb +63 -0
  32. data/test/{standalone_acceptance_test.rb → acceptance/standalone_acceptance_test.rb} +22 -1
  33. data/test/{stubba_acceptance_test.rb → acceptance/stubba_acceptance_test.rb} +1 -1
  34. data/test/deprecation_disabler.rb +15 -0
  35. data/test/{mocha_test_result_integration_test.rb → integration/mocha_test_result_integration_test.rb} +1 -1
  36. data/test/{stubba_integration_test.rb → integration/stubba_integration_test.rb} +1 -1
  37. data/test/{stubba_test_result_integration_test.rb → integration/stubba_test_result_integration_test.rb} +1 -1
  38. data/test/test_helper.rb +8 -0
  39. data/test/test_runner.rb +31 -0
  40. data/test/{mocha → unit}/any_instance_method_test.rb +0 -0
  41. data/test/unit/array_inspect_test.rb +16 -0
  42. data/test/{mocha → unit}/auto_verify_test.rb +0 -0
  43. data/test/{mocha → unit}/central_test.rb +0 -0
  44. data/test/{mocha → unit}/class_method_test.rb +0 -0
  45. data/test/unit/date_time_inspect_test.rb +21 -0
  46. data/test/unit/expectation_raiser_test.rb +28 -0
  47. data/test/{mocha → unit}/expectation_test.rb +105 -63
  48. data/test/unit/hash_inspect_test.rb +16 -0
  49. data/test/{mocha → unit}/infinite_range_test.rb +8 -5
  50. data/test/{mocha → unit}/metaclass_test.rb +0 -0
  51. data/test/unit/missing_expectation_test.rb +51 -0
  52. data/test/unit/mock_test.rb +351 -0
  53. data/test/unit/multiple_yields_test.rb +18 -0
  54. data/test/unit/no_yield_test.rb +18 -0
  55. data/test/unit/object_inspect_test.rb +35 -0
  56. data/test/{mocha → unit}/object_test.rb +0 -0
  57. data/test/unit/parameter_matchers/all_of_test.rb +26 -0
  58. data/test/unit/parameter_matchers/any_of_test.rb +26 -0
  59. data/test/unit/parameter_matchers/anything_test.rb +21 -0
  60. data/test/unit/parameter_matchers/has_entry_test.rb +25 -0
  61. data/test/unit/parameter_matchers/has_key_test.rb +25 -0
  62. data/test/unit/parameter_matchers/has_value_test.rb +25 -0
  63. data/test/unit/parameter_matchers/includes_test.rb +25 -0
  64. data/test/unit/parameter_matchers/stub_matcher.rb +22 -0
  65. data/test/{mocha → unit}/pretty_parameters_test.rb +0 -0
  66. data/test/unit/return_values_test.rb +63 -0
  67. data/test/{mocha → unit}/setup_and_teardown_test.rb +0 -0
  68. data/test/unit/single_return_value_test.rb +33 -0
  69. data/test/unit/single_yield_test.rb +18 -0
  70. data/test/unit/string_inspect_test.rb +11 -0
  71. data/test/unit/stub_test.rb +24 -0
  72. data/test/unit/yield_parameters_test.rb +93 -0
  73. metadata +117 -73
  74. data/lib/mocha/mock_methods.rb +0 -122
  75. data/test/all_tests.rb +0 -75
  76. data/test/mocha/inspect_test.rb +0 -90
  77. data/test/mocha/mock_methods_test.rb +0 -235
  78. data/test/mocha/mock_test.rb +0 -84
@@ -12,15 +12,13 @@ class Range
12
12
  1/0.0
13
13
  end
14
14
 
15
- alias_method :__to_s__, :to_s
16
-
17
- def to_s
18
- if first.to_f.infinite? then
15
+ def mocha_inspect
16
+ if first.respond_to?(:to_f) and first.to_f.infinite? then
19
17
  return "at most #{last}"
20
- elsif last.to_f.infinite? then
18
+ elsif last.respond_to?(:to_f) and last.to_f.infinite? then
21
19
  return "at least #{first}"
22
20
  else
23
- __to_s__
21
+ to_s
24
22
  end
25
23
  end
26
24
 
data/lib/mocha/inspect.rb CHANGED
@@ -2,7 +2,9 @@ require 'date'
2
2
 
3
3
  class Object
4
4
  def mocha_inspect
5
- inspect =~ /#</ ? "#<#{self.class}:0x#{self.__id__.to_s(16)}>" : inspect
5
+ address = self.__id__ * 2
6
+ address += 0x100000000 if address < 0
7
+ inspect =~ /#</ ? "#<#{self.class}:0x#{'%x' % address}>" : inspect
6
8
  end
7
9
  end
8
10
 
data/lib/mocha/is_a.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Object
2
+
3
+ # :stopdoc:
4
+
5
+ alias_method :__is_a__, :is_a?
6
+
7
+ # :startdoc:
8
+
9
+ end
@@ -0,0 +1,27 @@
1
+ require 'mocha/expectation'
2
+
3
+ module Mocha # :nodoc:
4
+
5
+ class MissingExpectation < Expectation # :nodoc:
6
+
7
+ def initialize(mock, method_name)
8
+ super
9
+ @invoked_count = true
10
+ end
11
+
12
+ def verify
13
+ msg = error_message(0, 1)
14
+ similar_expectations_list = similar_expectations.collect { |expectation| expectation.method_signature }.join("\n")
15
+ msg << "\nSimilar expectations:\n#{similar_expectations_list}" unless similar_expectations.empty?
16
+ error = ExpectationError.new(msg)
17
+ error.set_backtrace(filtered_backtrace)
18
+ raise error if @invoked_count
19
+ end
20
+
21
+ def similar_expectations
22
+ @mock.expectations.select { |expectation| expectation.method_name == self.method_name }
23
+ end
24
+
25
+ end
26
+
27
+ end
data/lib/mocha/mock.rb CHANGED
@@ -1,19 +1,205 @@
1
- require 'mocha/mock_methods'
1
+ require 'mocha/expectation'
2
+ require 'mocha/stub'
3
+ require 'mocha/missing_expectation'
4
+ require 'mocha/metaclass'
2
5
 
3
- module Mocha
6
+ module Mocha # :nodoc:
4
7
 
8
+ # Traditional mock object.
9
+ #
10
+ # Methods return an Expectation which can be further modified by methods on Expectation.
5
11
  class Mock
6
12
 
7
- include MockMethods
8
-
13
+ # :stopdoc:
14
+
9
15
  def initialize(stub_everything = false, name = nil)
10
16
  @stub_everything = stub_everything
11
17
  @mock_name = name
18
+ @expectations = []
19
+ end
20
+
21
+ attr_reader :stub_everything, :expectations
22
+
23
+ # :startdoc:
24
+
25
+ # :call-seq: expects(method_name) -> expectation
26
+ # expects(method_names) -> last expectation
27
+ #
28
+ # Adds an expectation that a method identified by +method_name+ symbol must be called exactly once with any parameters.
29
+ # Returns the new expectation which can be further modified by methods on Expectation.
30
+ # object = mock()
31
+ # object.expects(:method1)
32
+ # object.method1
33
+ # # no error raised
34
+ #
35
+ # object = mock()
36
+ # object.expects(:method1)
37
+ # # error raised, because method1 not called exactly once
38
+ # If +method_names+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
39
+ # object = mock()
40
+ # object.expects(:method1 => :result1, :method2 => :result2)
41
+ #
42
+ # # exactly equivalent to
43
+ #
44
+ # object = mock()
45
+ # object.expects(:method1).returns(:result1)
46
+ # object.expects(:method2).returns(:result2)
47
+ #
48
+ # Aliased by <tt>\_\_expects\_\_</tt>
49
+ def expects(method_name_or_hash, backtrace = nil)
50
+ if method_name_or_hash.is_a?(Hash) then
51
+ method_name_or_hash.each do |method_name, return_value|
52
+ add_expectation(Expectation.new(self, method_name, backtrace).returns(return_value))
53
+ end
54
+ else
55
+ add_expectation(Expectation.new(self, method_name_or_hash, backtrace))
56
+ end
57
+ end
58
+
59
+ # :call-seq: stubs(method_name) -> expectation
60
+ # stubs(method_names) -> last expectation
61
+ #
62
+ # Adds an expectation that a method identified by +method_name+ symbol may be called any number of times with any parameters.
63
+ # Returns the new expectation which can be further modified by methods on Expectation.
64
+ # object = mock()
65
+ # object.stubs(:method1)
66
+ # object.method1
67
+ # object.method1
68
+ # # no error raised
69
+ # If +method_names+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
70
+ # object = mock()
71
+ # object.stubs(:method1 => :result1, :method2 => :result2)
72
+ #
73
+ # # exactly equivalent to
74
+ #
75
+ # object = mock()
76
+ # object.stubs(:method1).returns(:result1)
77
+ # object.stubs(:method2).returns(:result2)
78
+ #
79
+ # Aliased by <tt>\_\_stubs\_\_</tt>
80
+ def stubs(method_name_or_hash, backtrace = nil)
81
+ if method_name_or_hash.is_a?(Hash) then
82
+ method_name_or_hash.each do |method_name, return_value|
83
+ add_expectation(Stub.new(self, method_name, backtrace).returns(return_value))
84
+ end
85
+ else
86
+ add_expectation(Stub.new(self, method_name_or_hash, backtrace))
87
+ end
88
+ end
89
+
90
+ # :call-seq: responds_like(responder) -> mock
91
+ #
92
+ # Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
93
+ #
94
+ # A +NoMethodError+ will be raised if the +responder+ does not <tt>respond_to?</tt> a method invocation (even if the method has been expected or stubbed).
95
+ #
96
+ # The +mock+ will delegate its <tt>respond_to?</tt> method to the +responder+.
97
+ # class Sheep
98
+ # def chew(grass); end
99
+ # def self.number_of_legs; end
100
+ # end
101
+ #
102
+ # sheep = mock('sheep')
103
+ # sheep.expects(:chew)
104
+ # sheep.expects(:foo)
105
+ # sheep.respond_to?(:chew) # => true
106
+ # sheep.respond_to?(:foo) # => true
107
+ # sheep.chew
108
+ # sheep.foo
109
+ # # no error raised
110
+ #
111
+ # sheep = mock('sheep')
112
+ # sheep.responds_like(Sheep.new)
113
+ # sheep.expects(:chew)
114
+ # sheep.expects(:foo)
115
+ # sheep.respond_to?(:chew) # => true
116
+ # sheep.respond_to?(:foo) # => false
117
+ # sheep.chew
118
+ # sheep.foo # => raises NoMethodError exception
119
+ #
120
+ # sheep_class = mock('sheep_class')
121
+ # sheep_class.responds_like(Sheep)
122
+ # sheep_class.stubs(:number_of_legs).returns(4)
123
+ # sheep_class.expects(:foo)
124
+ # sheep_class.respond_to?(:number_of_legs) # => true
125
+ # sheep_class.respond_to?(:foo) # => false
126
+ # assert_equal 4, sheep_class.number_of_legs
127
+ # sheep_class.foo # => raises NoMethodError exception
128
+ #
129
+ # Aliased by +quacks_like+
130
+ def responds_like(object)
131
+ @responder = object
132
+ self
12
133
  end
134
+
135
+ # :stopdoc:
136
+
137
+ alias_method :__expects__, :expects
13
138
 
139
+ alias_method :__stubs__, :stubs
140
+
141
+ alias_method :quacks_like, :responds_like
142
+
143
+ def add_expectation(expectation)
144
+ @expectations << expectation
145
+ method_name = expectation.method_name
146
+ self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)
147
+ expectation
148
+ end
149
+
150
+ def method_missing(symbol, *arguments, &block)
151
+ if @responder and not @responder.respond_to?(symbol)
152
+ raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
153
+ end
154
+ matching_expectation = matching_expectation(symbol, *arguments)
155
+ if matching_expectation then
156
+ matching_expectation.invoke(&block)
157
+ elsif stub_everything then
158
+ return
159
+ else
160
+ begin
161
+ super_method_missing(symbol, *arguments, &block)
162
+ rescue NoMethodError
163
+ unexpected_method_called(symbol, *arguments)
164
+ end
165
+ end
166
+ end
167
+
168
+ def respond_to?(symbol)
169
+ if @responder then
170
+ @responder.respond_to?(symbol)
171
+ else
172
+ @expectations.any? { |expectation| expectation.method_name == symbol }
173
+ end
174
+ end
175
+
176
+ def super_method_missing(symbol, *arguments, &block)
177
+ raise NoMethodError
178
+ end
179
+
180
+ def unexpected_method_called(symbol, *arguments)
181
+ MissingExpectation.new(self, symbol).with(*arguments).verify
182
+ end
183
+
184
+ def matching_expectation(symbol, *arguments)
185
+ @expectations.reverse.detect { |expectation| expectation.match?(symbol, *arguments) }
186
+ end
187
+
188
+ def verify(&block)
189
+ @expectations.each { |expectation| expectation.verify(&block) }
190
+ end
191
+
14
192
  def mocha_inspect
15
- @mock_name ? "#<Mock:#{@mock_name}>" : "#<Mock:0x#{__id__.to_s(16)}>"
193
+ address = self.__id__ * 2
194
+ address += 0x100000000 if address < 0
195
+ @mock_name ? "#<Mock:#{@mock_name}>" : "#<Mock:0x#{'%x' % address}>"
16
196
  end
197
+
198
+ def inspect
199
+ mocha_inspect
200
+ end
201
+
202
+ # :startdoc:
17
203
 
18
204
  end
19
205
 
@@ -0,0 +1,20 @@
1
+ module Mocha # :nodoc:
2
+
3
+ class MultipleYields # :nodoc:
4
+
5
+ attr_reader :parameter_groups
6
+
7
+ def initialize(*parameter_groups)
8
+ @parameter_groups = parameter_groups
9
+ end
10
+
11
+ def each
12
+ @parameter_groups.each do |parameter_group|
13
+ yield(parameter_group)
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
@@ -0,0 +1,11 @@
1
+ module Mocha # :nodoc:
2
+
3
+ class NoYields # :nodoc:
4
+
5
+ def each
6
+ end
7
+
8
+ end
9
+
10
+ end
11
+
data/lib/mocha/object.rb CHANGED
@@ -3,7 +3,9 @@ require 'mocha/instance_method'
3
3
  require 'mocha/class_method'
4
4
  require 'mocha/any_instance_method'
5
5
 
6
- # Methods added all Objects.
6
+ # Methods added all objects to allow mocking and stubbing on real objects.
7
+ #
8
+ # Methods return a Mocha::Expectation which can be further modified by methods on Mocha::Expectation.
7
9
  class Object
8
10
 
9
11
  def mocha # :nodoc:
@@ -29,6 +31,10 @@ class Object
29
31
  # product = Product.new
30
32
  # product.expects(:save).returns(true)
31
33
  # assert_equal false, product.save
34
+ #
35
+ # The original implementation of <tt>Product#save</tt> is replaced temporarily.
36
+ #
37
+ # The original implementation of <tt>Product#save</tt> is restored at the end of the test.
32
38
  def expects(symbol)
33
39
  method = stubba_method.new(stubba_object, symbol)
34
40
  $stubba.stub(method)
@@ -42,6 +48,10 @@ class Object
42
48
  # product = Product.new
43
49
  # product.stubs(:save).returns(true)
44
50
  # assert_equal false, product.save
51
+ #
52
+ # The original implementation of <tt>Product#save</tt> is replaced temporarily.
53
+ #
54
+ # The original implementation of <tt>Product#save</tt> is restored at the end of the test.
45
55
  def stubs(symbol)
46
56
  method = stubba_method.new(stubba_object, symbol)
47
57
  $stubba.stub(method)
@@ -0,0 +1,9 @@
1
+ module Mocha
2
+
3
+ # Used as parameters for Expectation#with to restrict the parameter values which will match the expectation.
4
+ module ParameterMatchers; end
5
+
6
+ end
7
+
8
+
9
+ Dir[File.expand_path(File.join(File.dirname(__FILE__), 'parameter_matchers', "*.rb"))].each { |lib| require lib }
@@ -0,0 +1,39 @@
1
+ module Mocha
2
+
3
+ module ParameterMatchers
4
+
5
+ # :call-seq: all_of -> parameter_matcher
6
+ #
7
+ # Matches if all +matchers+ match.
8
+ # object = mock()
9
+ # object.expects(:method_1).with(all_of(includes(1), includes(3)))
10
+ # object.method_1([1, 3])
11
+ # # no error raised
12
+ #
13
+ # object = mock()
14
+ # object.expects(:method_1).with(all_of(includes(1), includes(3)))
15
+ # object.method_1([1, 2])
16
+ # # error raised, because method_1 was not called with object including 1 and 3
17
+ def all_of(*matchers)
18
+ AllOf.new(*matchers)
19
+ end
20
+
21
+ class AllOf # :nodoc:
22
+
23
+ def initialize(*matchers)
24
+ @matchers = matchers
25
+ end
26
+
27
+ def ==(parameter)
28
+ @matchers.all? { |matcher| matcher == parameter }
29
+ end
30
+
31
+ def mocha_inspect
32
+ "all_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,44 @@
1
+ module Mocha
2
+
3
+ module ParameterMatchers
4
+
5
+ # :call-seq: any_of -> parameter_matcher
6
+ #
7
+ # Matches if any +matchers+ match.
8
+ # object = mock()
9
+ # object.expects(:method_1).with(any_of(1, 3))
10
+ # object.method_1(1)
11
+ # # no error raised
12
+ #
13
+ # object = mock()
14
+ # object.expects(:method_1).with(any_of(1, 3))
15
+ # object.method_1(3)
16
+ # # no error raised
17
+ #
18
+ # object = mock()
19
+ # object.expects(:method_1).with(any_of(1, 3))
20
+ # object.method_1(2)
21
+ # # error raised, because method_1 was not called with 1 or 3
22
+ def any_of(*matchers)
23
+ AnyOf.new(*matchers)
24
+ end
25
+
26
+ class AnyOf # :nodoc:
27
+
28
+ def initialize(*matchers)
29
+ @matchers = matchers
30
+ end
31
+
32
+ def ==(parameter)
33
+ @matchers.any? { |matcher| matcher == parameter }
34
+ end
35
+
36
+ def mocha_inspect
37
+ "any_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end