hardmock 1.3.0 → 1.3.1

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.
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rubygems'
3
3
 
4
- HARDMOCK_VERSION = "1.3.0"
4
+ HARDMOCK_VERSION = "1.3.1"
5
5
 
6
6
  Dir["lib/tasks/*.rake"].each { |f| load f }
7
7
 
data/lib/hardmock.rb CHANGED
@@ -15,6 +15,11 @@ module Hardmock
15
15
  # with inherited, pre-mixed or post-added user teardowns.
16
16
  def self.included(base) #:nodoc:#
17
17
  base.class_eval do
18
+ # Core of our actual setup behavior
19
+ def hardmock_setup
20
+ prepare_hardmock_control
21
+ end
22
+
18
23
  # Core of our actual teardown behavior
19
24
  def hardmock_teardown
20
25
  verify_mocks
@@ -24,6 +29,24 @@ module Hardmock
24
29
  def self.method_added(symbol) #:nodoc:
25
30
  end
26
31
 
32
+ if method_defined?(:setup) then
33
+ # Wrap existing setup
34
+ alias_method :old_setup, :setup
35
+ define_method(:new_setup) do
36
+ begin
37
+ hardmock_setup
38
+ ensure
39
+ old_setup
40
+ end
41
+ end
42
+ else
43
+ # We don't need to account for previous setup
44
+ define_method(:new_setup) do
45
+ hardmock_setup
46
+ end
47
+ end
48
+ alias_method :setup, :new_setup
49
+
27
50
  if method_defined?(:teardown) then
28
51
  # Wrap existing teardown
29
52
  alias_method :old_teardown, :teardown
@@ -55,6 +78,17 @@ module Hardmock
55
78
  end
56
79
  end
57
80
  end
81
+ when :setup
82
+ unless method_defined?(:user_setup)
83
+ alias_method :user_setup, :setup
84
+ define_method(:setup) do
85
+ begin
86
+ new_setup
87
+ ensure
88
+ user_setup
89
+ end
90
+ end
91
+ end
58
92
  end
59
93
  end
60
94
  end
@@ -113,26 +147,21 @@ module Hardmock
113
147
  @main_mock_control.verify
114
148
  ensure
115
149
  @main_mock_control.clear_expectations if @main_mock_control
116
- Hardmock.restore_all_stubbed_methods
117
150
  $main_mock_control = nil
151
+ reset_stubs
118
152
  end
119
153
 
120
154
  # Purge the main MockControl of all expectations, restore all concrete stubbed/mocked methods
121
155
  def clear_expectations
122
156
  @main_mock_control.clear_expectations if @main_mock_control
123
- Hardmock.restore_all_stubbed_methods
157
+ reset_stubs
124
158
  $main_mock_control = nil
125
159
  end
126
160
 
127
- # def self.set_main_mock_control(control)
128
- # $main_mock_control = control
129
- # end
161
+ def reset_stubs
162
+ Hardmock.restore_all_replaced_methods
163
+ end
130
164
 
131
- # def self.main_mock_control
132
- # raise "No main mock control set yet... chickening out" if $main_mock_control.nil?
133
- # $main_mock_control
134
- # end
135
-
136
165
  end
137
166
 
138
167
  # Insert Hardmock functionality into the TestCase base class
@@ -23,6 +23,10 @@ class Object #:nodoc:#
23
23
  meta_eval { define_method name, &blk }
24
24
  end
25
25
 
26
+ # def meta_eval_string(str)
27
+ # metaclass.instance_eval(str)
28
+ # end
29
+
26
30
  # Defines an instance method within a class
27
31
  # def class_def(name, &blk) #:nodoc:#
28
32
  # class_eval { define_method name, &blk }
@@ -59,47 +63,47 @@ module Hardmock
59
63
  # Exists only for documentation
60
64
  end
61
65
 
62
- class StubbedMethod #:nodoc:#
66
+ class ReplacedMethod
63
67
  attr_reader :target, :method_name
64
68
 
65
69
  def initialize(target, method_name)
66
70
  @target = target
67
71
  @method_name = method_name
68
72
 
69
- Hardmock.add_stubbed_method self
73
+ Hardmock.track_replaced_method self
70
74
  end
75
+ end
71
76
 
77
+ class StubbedMethod < ReplacedMethod #:nodoc:#
72
78
  def invoke(args)
79
+ raise @raises if @raises
73
80
  @return_value
74
81
  end
75
82
 
76
83
  def returns(stubbed_return)
77
84
  @return_value = stubbed_return
78
85
  end
79
- end
80
-
81
- class MockedMethod < StubbedMethod #:nodoc:#
82
-
83
- def initialize(target, method_name, mock)
84
- super target,method_name
85
- @mock = mock
86
- end
87
86
 
88
- def invoke(args)
89
- @mock.__send__(self.method_name.to_sym, *args)
87
+ def raises(err)
88
+ err = RuntimeError.new(err) unless err.kind_of?(Exception)
89
+ @raises = err
90
+ # puts "Setup to raise #{@raises}"
90
91
  end
91
-
92
92
  end
93
93
 
94
94
  class ::Object
95
95
  def stubs!(method_name)
96
96
  _ensure_stubbable method_name
97
-
98
97
  method_name = method_name.to_s
98
+ already_stubbed = Hardmock.has_replaced_method?(self, method_name)
99
+
99
100
  stubbed_method = Hardmock::StubbedMethod.new(self, method_name)
100
101
 
101
- meta_eval do
102
- alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
102
+
103
+ unless _is_mock? or already_stubbed
104
+ meta_eval do
105
+ alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
106
+ end
103
107
  end
104
108
 
105
109
  meta_def method_name do |*args|
@@ -110,26 +114,41 @@ module Hardmock
110
114
  end
111
115
 
112
116
  def expects!(method_name, *args, &block)
117
+ if self._is_mock?
118
+ raise Hardmock::StubbingError, "Cannot use 'expects!(:#{method_name})' on a Mock object; try 'expects' instead"
119
+ end
113
120
  _ensure_stubbable method_name
114
121
 
115
122
  method_name = method_name.to_s
116
123
 
117
124
  if @_my_mock.nil?
118
125
  @_my_mock = Mock.new(_my_name, $main_mock_control)
119
- stubbed_method = Hardmock::MockedMethod.new(self, method_name, @_my_mock)
126
+ Hardmock::ReplacedMethod.new(self, method_name)
127
+
120
128
  meta_eval do
121
129
  alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
122
130
  end
123
- meta_def(method_name) do |*args|
124
- stubbed_method.invoke(args)
131
+
132
+ begin
133
+ $method_text_temp = %{
134
+ def #{method_name}(*args,&block)
135
+ @_my_mock.__send__(:#{method_name}, *args, &block)
136
+ end
137
+ }
138
+ class << self
139
+ eval $method_text_temp
140
+ end
141
+ ensure
142
+ $method_text_temp = nil
125
143
  end
144
+
126
145
  end
127
146
 
128
147
  return @_my_mock.expects(method_name, *args, &block)
129
148
  end
130
149
 
131
150
  def _ensure_stubbable(method_name)
132
- unless self.respond_to?(method_name.to_sym)
151
+ unless self.respond_to?(method_name.to_sym) or self._is_mock?
133
152
  msg = "Cannot stub non-existant "
134
153
  if self.kind_of?(Class)
135
154
  msg += "class method #{_my_name}."
@@ -141,6 +160,10 @@ module Hardmock
141
160
  end
142
161
  end
143
162
 
163
+ def _is_mock?
164
+ self.kind_of?(Mock)
165
+ end
166
+
144
167
  def _my_name
145
168
  self.kind_of?(Class) ? self.name : self.class.name
146
169
  end
@@ -152,21 +175,31 @@ module Hardmock
152
175
  end
153
176
 
154
177
  class << self
155
- def add_stubbed_method(stubbed_method)
156
- all_stubbed_methods << stubbed_method
178
+ def track_replaced_method(replaced_method)
179
+ all_replaced_methods << replaced_method
157
180
  end
158
181
 
159
- def all_stubbed_methods
160
- $all_stubbed_methods ||= []
182
+ def all_replaced_methods
183
+ $all_replaced_methods ||= []
184
+ end
185
+
186
+ def has_replaced_method?(obj, method_name)
187
+ hits = all_replaced_methods.select do |replaced|
188
+ (replaced.target.object_id == obj.object_id) and (replaced.method_name.to_s == method_name.to_s)
189
+ end
190
+ return !hits.empty?
161
191
  end
162
192
 
163
- def restore_all_stubbed_methods
164
- all_stubbed_methods.each do |sm|
165
- sm.target.meta_eval do
166
- alias_method sm.method_name.to_sym, "_hardmock_original_#{sm.method_name}".to_sym
193
+ def restore_all_replaced_methods
194
+ all_replaced_methods.each do |replaced|
195
+ unless replaced.target._is_mock?
196
+ replaced.target.meta_eval do
197
+ alias_method replaced.method_name.to_sym, "_hardmock_original_#{replaced.method_name}".to_sym
198
+ end
199
+ replaced.target._clear_mock
167
200
  end
168
- sm.target._clear_mock
169
201
  end
202
+ all_replaced_methods.clear
170
203
  end
171
204
  end
172
205
 
@@ -9,11 +9,9 @@ class HardmockTest < Test::Unit::TestCase
9
9
  #
10
10
 
11
11
  it "conveniently creates mocks using create_mock and create_mocks" do
12
- assert_nil @main_mock_control, "@main_mock_control not expected yet"
13
12
 
14
13
  h = create_mock :donkey
15
14
  assert_equal [ :donkey ], h.keys
16
- assert_not_nil @main_mock_control, "@main_mock_control should be here"
17
15
 
18
16
  assert_mock_exists :donkey
19
17
  assert_same @donkey, h[:donkey]
@@ -380,7 +378,7 @@ class HardmockTest < Test::Unit::TestCase
380
378
  assert_equal "<Mock hay_bailer>", @hay_bailer.inspect, "Wrong output from 'inspect'"
381
379
  end
382
380
 
383
- it "raises is prepare_hardmock_control is invoked after create_mocks, or more than once" do
381
+ it "raises if prepare_hardmock_control is invoked after create_mocks, or more than once" do
384
382
  create_mock :hi_there
385
383
  create_mocks :another, :one
386
384
  assert_error RuntimeError, /already setup/ do
@@ -8,7 +8,7 @@ class StubbingTest < Test::Unit::TestCase
8
8
  # TESTS
9
9
  #
10
10
 
11
- it "stubs a class method (and un-stubs after verify)" do
11
+ it "stubs a class method (and un-stubs after reset_stubs)" do
12
12
  assert_equal "stones and gravel", Concrete.pour
13
13
  assert_equal "glug glug", Jug.pour
14
14
 
@@ -23,7 +23,7 @@ class StubbingTest < Test::Unit::TestCase
23
23
 
24
24
  assert_equal "For roads", Concrete.describe, "'describe' method broken"
25
25
 
26
- verify_mocks
26
+ reset_stubs
27
27
 
28
28
  assert_equal "stones and gravel", Concrete.pour, "'pour' method not restored"
29
29
  assert_equal "For roads", Concrete.describe, "'describe' method broken after verify"
@@ -39,7 +39,7 @@ class StubbingTest < Test::Unit::TestCase
39
39
  assert_equal "awful", Concrete.describe
40
40
  assert_equal "milk", Jug.pour
41
41
 
42
- verify_mocks
42
+ reset_stubs
43
43
 
44
44
  assert_equal "stones and gravel", Concrete.pour
45
45
  assert_equal "For roads", Concrete.describe
@@ -53,7 +53,7 @@ class StubbingTest < Test::Unit::TestCase
53
53
  slab.stubs!(:hit).returns("slap")
54
54
  assert_equal "slap", slab.hit, "'hit' not stubbed"
55
55
 
56
- verify_mocks
56
+ reset_stubs
57
57
 
58
58
  assert_equal "bonk", slab.hit, "'hit' not restored"
59
59
  end
@@ -70,7 +70,7 @@ class StubbingTest < Test::Unit::TestCase
70
70
  assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken"
71
71
  assert_equal "For roads", Concrete.describe, "'describe' class method broken"
72
72
 
73
- verify_mocks
73
+ reset_stubs
74
74
 
75
75
  assert_equal "an instance", slab.describe, "'describe' instance method not restored"
76
76
  assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken after restore"
@@ -89,14 +89,47 @@ class StubbingTest < Test::Unit::TestCase
89
89
  end
90
90
  end
91
91
 
92
+ should "allow re-stubbing" do
93
+ Concrete.stubs!(:pour).returns("one")
94
+ assert_equal "one", Concrete.pour
95
+
96
+ Concrete.stubs!(:pour).raises("hell")
97
+ assert_error RuntimeError, /hell/ do
98
+ Concrete.pour
99
+ end
100
+
101
+ Concrete.stubs!(:pour).returns("two")
102
+ assert_equal "two", Concrete.pour
103
+
104
+ reset_stubs
105
+
106
+ assert_equal "stones and gravel", Concrete.pour
107
+ end
108
+
92
109
  it "does nothing with a runtime block when simply stubbing" do
93
- prepare_hardmock_control
110
+
94
111
  slab = Concrete.new
95
112
  slab.stubs!(:hit) do |nothing|
96
113
  raise "BOOOMM!"
97
114
  end
98
115
  slab.hit
99
- verify_mocks
116
+ reset_stubs
117
+ end
118
+
119
+ it "can raise errors from a stubbed method" do
120
+
121
+ Concrete.stubs!(:pour).raises(StandardError.new("no!"))
122
+ assert_error StandardError, /no!/ do
123
+ Concrete.pour
124
+ end
125
+ end
126
+
127
+ it "provides string syntax for convenient raising of RuntimeErrors" do
128
+
129
+ Concrete.stubs!(:pour).raises("never!")
130
+ assert_error RuntimeError, /never!/ do
131
+ Concrete.pour
132
+ end
100
133
  end
101
134
 
102
135
 
@@ -105,7 +138,7 @@ class StubbingTest < Test::Unit::TestCase
105
138
  #
106
139
 
107
140
  it "mocks specific methods on existing classes, and returns the class method to normal after verification" do
108
- prepare_hardmock_control
141
+
109
142
  assert_equal "stones and gravel", Concrete.pour, "Concrete.pour is already messed up"
110
143
 
111
144
  Concrete.expects!(:pour).returns("ALIGATORS")
@@ -116,7 +149,7 @@ class StubbingTest < Test::Unit::TestCase
116
149
  end
117
150
 
118
151
  it "flunks if expected class method is not invoked" do
119
- prepare_hardmock_control
152
+
120
153
  Concrete.expects!(:pour).returns("ALIGATORS")
121
154
  assert_error(Hardmock::VerifyError, /Concrete.pour/, /unmet expectations/i) do
122
155
  verify_mocks
@@ -125,7 +158,7 @@ class StubbingTest < Test::Unit::TestCase
125
158
  end
126
159
 
127
160
  it "supports all normal mock functionality for class methods" do
128
- prepare_hardmock_control
161
+
129
162
  Concrete.expects!(:pour, "two tons").returns("mice")
130
163
  Concrete.expects!(:pour, "three tons").returns("cats")
131
164
  Concrete.expects!(:pour, "four tons").raises("Can't do it")
@@ -160,14 +193,14 @@ class StubbingTest < Test::Unit::TestCase
160
193
  end
161
194
 
162
195
  should "not allow mocking non-existant class methods" do
163
- prepare_hardmock_control
196
+
164
197
  assert_error Hardmock::StubbingError, /non-existant/, /something/ do
165
198
  Concrete.expects!(:something)
166
199
  end
167
200
  end
168
201
 
169
202
  it "mocks specific methods on existing instances, then restore them after verify" do
170
- prepare_hardmock_control
203
+
171
204
  slab = Concrete.new
172
205
  assert_equal "bonk", slab.hit
173
206
 
@@ -179,7 +212,7 @@ class StubbingTest < Test::Unit::TestCase
179
212
  end
180
213
 
181
214
  it "flunks if expected instance method is not invoked" do
182
- prepare_hardmock_control
215
+
183
216
  slab = Concrete.new
184
217
  slab.expects!(:hit)
185
218
 
@@ -190,7 +223,7 @@ class StubbingTest < Test::Unit::TestCase
190
223
  end
191
224
 
192
225
  it "supports all normal mock functionality for instance methods" do
193
- prepare_hardmock_control
226
+
194
227
  slab = Concrete.new
195
228
 
196
229
  slab.expects!(:hit, "soft").returns("hey")
@@ -233,14 +266,50 @@ class StubbingTest < Test::Unit::TestCase
233
266
  end
234
267
 
235
268
  should "not allow mocking non-existant instance methods" do
236
- prepare_hardmock_control
269
+
237
270
  slab = Concrete.new
238
271
  assert_error Hardmock::StubbingError, /non-existant/, /something/ do
239
272
  slab.expects!(:something)
240
273
  end
241
274
  end
242
275
 
243
- should "support expectations that deal with runtime blocks"
276
+ should "support concrete expectations that deal with runtime blocks" do
277
+
278
+ Concrete.expects!(:pour, "a lot") do |how_much, block|
279
+ assert_equal "a lot", how_much, "Wrong how_much arg"
280
+ assert_not_nil block, "nil runtime block"
281
+ assert_equal "the block value", block.call, "Wrong runtime block value"
282
+ end
283
+
284
+ Concrete.pour("a lot") do
285
+ "the block value"
286
+ end
287
+
288
+ end
289
+
290
+ it "can stub methods on mock objects" do
291
+ create_mock :horse
292
+ @horse.stubs!(:speak).returns("silence")
293
+ @horse.stubs!(:hello).returns("nothing")
294
+ @horse.expects(:canter).returns("clip clop")
295
+
296
+ assert_equal "silence", @horse.speak
297
+ assert_equal "clip clop", @horse.canter
298
+ assert_equal "silence", @horse.speak
299
+ assert_equal "silence", @horse.speak
300
+ assert_equal "nothing", @horse.hello
301
+ assert_equal "nothing", @horse.hello
302
+
303
+ verify_mocks
304
+ reset_stubs
305
+ end
306
+
307
+ it "will not allow expects! to be used on a mock object" do
308
+ create_mock :cow
309
+ assert_error Hardmock::StubbingError, /expects!/, /mock/i, /something/ do
310
+ @cow.expects!(:something)
311
+ end
312
+ end
244
313
 
245
314
  #
246
315
  # HELPERS
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: hardmock
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.3.0
7
- date: 2007-11-12 00:00:00 -05:00
6
+ version: 1.3.1
7
+ date: 2007-11-17 00:00:00 -05:00
8
8
  summary: A strict, ordered, expectation-oriented mock object library.
9
9
  require_paths:
10
10
  - lib