minilab 1.0.0-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +2 -0
- data/CHANGES +2 -0
- data/LICENSE +19 -0
- data/README +107 -0
- data/Rakefile +145 -0
- data/config/environment.rb +15 -0
- data/config/objects.yml +22 -0
- data/lib/analog_io.rb +30 -0
- data/lib/digital_auxport_io.rb +49 -0
- data/lib/digital_configuration.rb +66 -0
- data/lib/digital_port_io.rb +68 -0
- data/lib/extension/extconf.rb +4 -0
- data/lib/extension/minilab_hardware.c +235 -0
- data/lib/extension/minilab_hardware.so +0 -0
- data/lib/library_translator.rb +48 -0
- data/lib/minilab.rb +149 -0
- data/lib/minilab_context.rb +39 -0
- data/lib/result_verifier.rb +14 -0
- data/test/integration/analog_input_output_test.rb +43 -0
- data/test/integration/connect_to_hardware_test.rb +13 -0
- data/test/integration/digital_input_output_test.rb +114 -0
- data/test/integration/integration_test.rb +53 -0
- data/test/integration/require_minilab_test.rb +9 -0
- data/test/system/analog_input.test +3 -0
- data/test/system/analog_output.test +37 -0
- data/test/system/digital_port_input.test +5 -0
- data/test/system/digital_port_output.test +39 -0
- data/test/system/digital_port_read_byte.test +26 -0
- data/test/system/digital_screw_terminals_input.test +2 -0
- data/test/system/digital_screw_terminals_output.test +11 -0
- data/test/system/minilab_driver.rb +85 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/analog_io_test.rb +87 -0
- data/test/unit/digital_auxport_io_test.rb +114 -0
- data/test/unit/digital_configuration_test.rb +136 -0
- data/test/unit/digital_port_io_test.rb +117 -0
- data/test/unit/library_translator_test.rb +100 -0
- data/test/unit/minilab_context_test.rb +82 -0
- data/test/unit/minilab_hardware_test.rb +83 -0
- data/test/unit/minilab_test.rb +131 -0
- data/test/unit/result_verifier_test.rb +33 -0
- data/vendor/behaviors/lib/behaviors.rb +50 -0
- data/vendor/behaviors/tasks/behaviors_tasks.rake +140 -0
- data/vendor/behaviors/test/behaviors_tasks_test.rb +71 -0
- data/vendor/behaviors/test/behaviors_test.rb +50 -0
- data/vendor/behaviors/test/tasks_test/Rakefile +16 -0
- data/vendor/behaviors/test/tasks_test/doc/behaviors.html +55 -0
- data/vendor/behaviors/test/tasks_test/lib/user.rb +2 -0
- data/vendor/behaviors/test/tasks_test/test/user_test.rb +17 -0
- data/vendor/constructor/Rakefile +44 -0
- data/vendor/constructor/config/environment.rb +12 -0
- data/vendor/constructor/lib/constructor.rb +132 -0
- data/vendor/constructor/test/constructor_test.rb +366 -0
- data/vendor/constructor/test/helper.rb +3 -0
- data/vendor/diy/README +26 -0
- data/vendor/diy/Rakefile +18 -0
- data/vendor/diy/lib/constructor.rb +114 -0
- data/vendor/diy/lib/diy.rb +329 -0
- data/vendor/diy/proto/context.rb +117 -0
- data/vendor/diy/proto/context.yml +20 -0
- data/vendor/diy/test/diy_test.rb +370 -0
- data/vendor/diy/test/files/broken_construction.yml +7 -0
- data/vendor/diy/test/files/cat/cat.rb +4 -0
- data/vendor/diy/test/files/cat/extra_conflict.yml +5 -0
- data/vendor/diy/test/files/cat/heritage.rb +2 -0
- data/vendor/diy/test/files/cat/needs_input.yml +3 -0
- data/vendor/diy/test/files/cat/the_cat_lineage.rb +1 -0
- data/vendor/diy/test/files/dog/dog_model.rb +4 -0
- data/vendor/diy/test/files/dog/dog_presenter.rb +4 -0
- data/vendor/diy/test/files/dog/dog_view.rb +2 -0
- data/vendor/diy/test/files/dog/file_resolver.rb +2 -0
- data/vendor/diy/test/files/dog/other_thing.rb +2 -0
- data/vendor/diy/test/files/dog/simple.yml +11 -0
- data/vendor/diy/test/files/donkey/foo.rb +8 -0
- data/vendor/diy/test/files/donkey/foo/bar/qux.rb +7 -0
- data/vendor/diy/test/files/fud/objects.yml +13 -0
- data/vendor/diy/test/files/fud/toy.rb +15 -0
- data/vendor/diy/test/files/gnu/objects.yml +14 -0
- data/vendor/diy/test/files/gnu/thinger.rb +8 -0
- data/vendor/diy/test/files/goat/base.rb +8 -0
- data/vendor/diy/test/files/goat/can.rb +6 -0
- data/vendor/diy/test/files/goat/goat.rb +6 -0
- data/vendor/diy/test/files/goat/objects.yml +12 -0
- data/vendor/diy/test/files/goat/paper.rb +6 -0
- data/vendor/diy/test/files/goat/plane.rb +8 -0
- data/vendor/diy/test/files/goat/shirt.rb +6 -0
- data/vendor/diy/test/files/goat/wings.rb +8 -0
- data/vendor/diy/test/files/horse/holder_thing.rb +4 -0
- data/vendor/diy/test/files/horse/objects.yml +7 -0
- data/vendor/diy/test/files/yak/core_model.rb +4 -0
- data/vendor/diy/test/files/yak/core_presenter.rb +4 -0
- data/vendor/diy/test/files/yak/core_view.rb +1 -0
- data/vendor/diy/test/files/yak/data_source.rb +1 -0
- data/vendor/diy/test/files/yak/fringe_model.rb +4 -0
- data/vendor/diy/test/files/yak/fringe_presenter.rb +4 -0
- data/vendor/diy/test/files/yak/fringe_view.rb +1 -0
- data/vendor/diy/test/files/yak/my_objects.yml +21 -0
- data/vendor/diy/test/test_helper.rb +40 -0
- data/vendor/hardmock/CHANGES +8 -0
- data/vendor/hardmock/LICENSE +7 -0
- data/vendor/hardmock/README +48 -0
- data/vendor/hardmock/Rakefile +100 -0
- data/vendor/hardmock/TODO +7 -0
- data/vendor/hardmock/config/environment.rb +12 -0
- data/vendor/hardmock/homepage/demo.rb +21 -0
- data/vendor/hardmock/homepage/hardmock_sample.png +0 -0
- data/vendor/hardmock/homepage/index.html +65 -0
- data/vendor/hardmock/init.rb +3 -0
- data/vendor/hardmock/lib/hardmock.rb +634 -0
- data/vendor/hardmock/lib/method_cleanout.rb +14 -0
- data/vendor/hardmock/rcov.rake +18 -0
- data/vendor/hardmock/test/functional/assert_error_test.rb +52 -0
- data/vendor/hardmock/test/functional/auto_verify_test.rb +192 -0
- data/vendor/hardmock/test/functional/direct_mock_usage_test.rb +396 -0
- data/vendor/hardmock/test/functional/hardmock_test.rb +380 -0
- data/vendor/hardmock/test/test_helper.rb +23 -0
- data/vendor/hardmock/test/unit/expectation_builder_test.rb +18 -0
- data/vendor/hardmock/test/unit/expector_test.rb +56 -0
- data/vendor/hardmock/test/unit/method_cleanout_test.rb +35 -0
- data/vendor/hardmock/test/unit/mock_control_test.rb +172 -0
- data/vendor/hardmock/test/unit/mock_test.rb +273 -0
- data/vendor/hardmock/test/unit/simple_expectation_test.rb +345 -0
- data/vendor/hardmock/test/unit/trapper_test.rb +60 -0
- data/vendor/hardmock/test/unit/verify_error_test.rb +34 -0
- data/vendor/systir/systir.rb +403 -0
- data/vendor/systir/test/unit/ui/xml/testrunner.rb +192 -0
- data/vendor/systir/test/unit/ui/xml/xmltestrunner.xslt +109 -0
- metadata +235 -0
@@ -0,0 +1,345 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
|
+
require 'hardmock'
|
3
|
+
|
4
|
+
class SimpleExpectationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@mock = TheMock.new
|
8
|
+
end
|
9
|
+
#
|
10
|
+
# HELPERS
|
11
|
+
#
|
12
|
+
|
13
|
+
class TheMock
|
14
|
+
def _name; 'the_mock'; end
|
15
|
+
end
|
16
|
+
class OtherMock
|
17
|
+
def _name; 'other_mock'; end
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# TESTS
|
22
|
+
#
|
23
|
+
|
24
|
+
def test_to_s
|
25
|
+
ex = SimpleExpectation.new( :mock => @mock, :method => 'a_func', :arguments => [1, "two", :three, { :four => 4 }] )
|
26
|
+
assert_equal %|the_mock.a_func(1, "two", :three, {:four=>4})|, ex.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_apply_method_call
|
30
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'some_func',
|
31
|
+
:arguments => [1,'two',:three] )
|
32
|
+
|
33
|
+
# Try it good:
|
34
|
+
assert_nothing_raised ExpectationError do
|
35
|
+
se.apply_method_call( @mock, 'some_func', [1,'two',:three], nil )
|
36
|
+
end
|
37
|
+
|
38
|
+
# Bad func name:
|
39
|
+
err = assert_raise ExpectationError do
|
40
|
+
se.apply_method_call( @mock, 'wrong_func', [1,'two',:three], nil )
|
41
|
+
end
|
42
|
+
assert_match(/wrong method/i, err.message)
|
43
|
+
assert_match(/wrong_func/i, err.message)
|
44
|
+
assert_match(/[1, "two", :three]/i, err.message)
|
45
|
+
assert_match(/some_func/i, err.message)
|
46
|
+
assert_match(/the_mock/i, err.message)
|
47
|
+
|
48
|
+
# Wrong mock
|
49
|
+
err = assert_raise ExpectationError do
|
50
|
+
se.apply_method_call( OtherMock.new, 'some_func', [1,'two',:three], nil )
|
51
|
+
end
|
52
|
+
assert_match(/[1, "two", :three]/i, err.message)
|
53
|
+
assert_match(/some_func/i, err.message)
|
54
|
+
assert_match(/the_mock/i, err.message)
|
55
|
+
assert_match(/other_mock/i, err.message)
|
56
|
+
|
57
|
+
# Wrong args
|
58
|
+
err = assert_raise ExpectationError do
|
59
|
+
se.apply_method_call( @mock, 'some_func', [1,'two',:four], nil)
|
60
|
+
end
|
61
|
+
assert_match(/[1, "two", :three]/i, err.message)
|
62
|
+
assert_match(/[1, "two", :four]/i, err.message)
|
63
|
+
assert_match(/wrong arguments/i, err.message)
|
64
|
+
assert_match(/some_func/i, err.message)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_apply_method_call_should_call_proc_when_given
|
68
|
+
# now with a proc
|
69
|
+
thinger = nil
|
70
|
+
the_proc = Proc.new { thinger = :shaq }
|
71
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'some_func',
|
72
|
+
:block => the_proc)
|
73
|
+
|
74
|
+
# Try it good:
|
75
|
+
assert_nil thinger
|
76
|
+
assert_nothing_raised ExpectationError do
|
77
|
+
se.apply_method_call(@mock, 'some_func', [], nil)
|
78
|
+
end
|
79
|
+
assert_equal :shaq, thinger, 'wheres shaq??'
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_apply_method_call_passes_runtime_block_as_last_argument_to_expectation_block
|
83
|
+
|
84
|
+
passed_block = nil
|
85
|
+
exp_block_called = false
|
86
|
+
exp_block = Proc.new { |blk|
|
87
|
+
exp_block_called = true
|
88
|
+
passed_block = blk
|
89
|
+
}
|
90
|
+
|
91
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'some_func', :block => exp_block,
|
92
|
+
:arguments => [])
|
93
|
+
|
94
|
+
set_flag = false
|
95
|
+
runtime_block = Proc.new { set_flag = true }
|
96
|
+
|
97
|
+
assert_nil passed_block, "Passed block should be nil"
|
98
|
+
assert !set_flag, "set_flag should be off"
|
99
|
+
|
100
|
+
# Go
|
101
|
+
se.apply_method_call( @mock, 'some_func', [], runtime_block)
|
102
|
+
|
103
|
+
# Examine the passed block
|
104
|
+
assert exp_block_called, "Expectation block not called"
|
105
|
+
assert_not_nil passed_block, "Should have been passed a block"
|
106
|
+
assert !set_flag, "set_flag should still be off"
|
107
|
+
passed_block.call
|
108
|
+
assert set_flag, "set_flag should be on"
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_apply_method_call_fails_when_theres_no_expectation_block_to_handle_the_runtime_block
|
112
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'some_func', :arguments => [])
|
113
|
+
runtime_block = Proc.new { set_flag = true }
|
114
|
+
err = assert_raise ExpectationError do
|
115
|
+
se.apply_method_call( @mock, 'some_func', [], runtime_block)
|
116
|
+
end
|
117
|
+
assert_match(/unexpected block/i, err.message)
|
118
|
+
assert_match(/the_mock.some_func()/i, err.message)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_returns
|
122
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'some_func',
|
123
|
+
:arguments => [1,'two',:three])
|
124
|
+
|
125
|
+
se.returns "A value"
|
126
|
+
|
127
|
+
assert_equal "A value", se.apply_method_call(@mock, 'some_func', [1,'two',:three], nil)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_apply_method_call_captures_block_value
|
131
|
+
the_proc = lambda { "in the block" }
|
132
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_proc)
|
133
|
+
|
134
|
+
assert_nil se.block_value, "Block value starts out nil"
|
135
|
+
|
136
|
+
se.apply_method_call(@mock, 'do_it', [], nil)
|
137
|
+
|
138
|
+
assert_equal "in the block", se.block_value, "Block value not captured"
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_trigger
|
142
|
+
# convenience method for block_value.call
|
143
|
+
target = false
|
144
|
+
inner_proc = lambda { target = true }
|
145
|
+
the_proc = lambda { inner_proc }
|
146
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_proc)
|
147
|
+
|
148
|
+
assert_nil se.block_value, "Block value starts out nil"
|
149
|
+
se.apply_method_call(@mock, 'do_it', [], nil)
|
150
|
+
assert_not_nil se.block_value, "Block value not set"
|
151
|
+
|
152
|
+
assert !target, "Target should still be false"
|
153
|
+
se.trigger
|
154
|
+
assert target, "Target not true!"
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_trigger_with_arguments
|
158
|
+
# convenience method for block_value.call
|
159
|
+
target = nil
|
160
|
+
inner_proc = lambda { |one,two| target = [one,two] }
|
161
|
+
the_proc = lambda { inner_proc }
|
162
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_proc)
|
163
|
+
|
164
|
+
assert_nil se.block_value, "Block value starts out nil"
|
165
|
+
se.apply_method_call(@mock, 'do_it', [], nil)
|
166
|
+
assert_not_nil se.block_value, "Block value not set"
|
167
|
+
|
168
|
+
assert_nil target, "target should still be nil"
|
169
|
+
se.trigger 'cat','dog'
|
170
|
+
assert_equal ['cat','dog'], target
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_trigger_nil_block_value
|
174
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [])
|
175
|
+
|
176
|
+
assert_nil se.block_value, "Block value starts out nil"
|
177
|
+
se.apply_method_call(@mock, 'do_it', [], nil)
|
178
|
+
assert_nil se.block_value, "Block value should still be nil"
|
179
|
+
|
180
|
+
err = assert_raise ExpectationError do
|
181
|
+
se.trigger
|
182
|
+
end
|
183
|
+
assert_match(/do_it/i, err.message)
|
184
|
+
assert_match(/block value/i, err.message)
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_trigger_non_proc_block_value
|
188
|
+
the_block = lambda { "woops" }
|
189
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_block)
|
190
|
+
|
191
|
+
se.apply_method_call(@mock, 'do_it', [], nil)
|
192
|
+
assert_equal "woops", se.block_value
|
193
|
+
|
194
|
+
err = assert_raise ExpectationError do
|
195
|
+
se.trigger
|
196
|
+
end
|
197
|
+
assert_match(/do_it/i, err.message)
|
198
|
+
assert_match(/trigger/i, err.message)
|
199
|
+
assert_match(/woops/i, err.message)
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
def test_proc_used_for_return
|
205
|
+
the_proc = lambda { "in the block" }
|
206
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_proc)
|
207
|
+
|
208
|
+
assert_equal "in the block", se.apply_method_call(@mock, 'do_it', [], nil)
|
209
|
+
assert_equal "in the block", se.block_value, "Captured block value affected wrongly"
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_explicit_return_overrides_proc_return
|
213
|
+
the_proc = lambda { "in the block" }
|
214
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'do_it', :arguments => [], :block => the_proc)
|
215
|
+
se.returns "the override"
|
216
|
+
assert_equal "the override", se.apply_method_call(@mock, 'do_it', [], nil)
|
217
|
+
assert_equal "in the block", se.block_value, "Captured block value affected wrongly"
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_yields
|
221
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
222
|
+
se.yields :bean1, :bean2
|
223
|
+
|
224
|
+
things = []
|
225
|
+
a_block = lambda { |thinger| things << thinger }
|
226
|
+
|
227
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
228
|
+
assert_equal [:bean1,:bean2], things, "Wrong things"
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_yields_block_takes_no_arguments
|
232
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
233
|
+
se.yields
|
234
|
+
|
235
|
+
things = []
|
236
|
+
a_block = lambda { things << 'OOF' }
|
237
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
238
|
+
assert_equal ['OOF'], things
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_yields_params_to_block_takes_no_arguments
|
242
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
243
|
+
se.yields :wont_fit
|
244
|
+
|
245
|
+
things = []
|
246
|
+
a_block = lambda { things << 'WUP' }
|
247
|
+
|
248
|
+
err = assert_raise ExpectationError do
|
249
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
250
|
+
end
|
251
|
+
assert_match(/wont_fit/i, err.message)
|
252
|
+
assert_match(/arity -1/i, err.message)
|
253
|
+
assert_equal [], things, "Wrong things"
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_yields_with_returns
|
257
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] ,
|
258
|
+
:returns => 'the results')
|
259
|
+
|
260
|
+
exp = se.yields :bean1, :bean2
|
261
|
+
assert_same se, exp, "'yields' needs to return a reference to the expectation"
|
262
|
+
things = []
|
263
|
+
a_block = lambda { |thinger| things << thinger }
|
264
|
+
returned = se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
265
|
+
assert_equal [:bean1,:bean2], things, "Wrong things"
|
266
|
+
assert_equal 'the results', returned, "Wrong return value"
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_yields_with_raises
|
270
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot],
|
271
|
+
:raises => RuntimeError.new("kerboom"))
|
272
|
+
|
273
|
+
exp = se.yields :bean1, :bean2
|
274
|
+
assert_same se, exp, "'yields' needs to return a reference to the expectation"
|
275
|
+
things = []
|
276
|
+
a_block = lambda { |thinger| things << thinger }
|
277
|
+
err = assert_raise RuntimeError do
|
278
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
279
|
+
end
|
280
|
+
assert_match(/kerboom/i, err.message)
|
281
|
+
assert_equal [:bean1,:bean2], things, "Wrong things"
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_yields_and_inner_block_explodes
|
285
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot])
|
286
|
+
|
287
|
+
exp = se.yields :bean1, :bean2
|
288
|
+
assert_same se, exp, "'yields' needs to return a reference to the expectation"
|
289
|
+
things = []
|
290
|
+
a_block = lambda { |thinger|
|
291
|
+
things << thinger
|
292
|
+
raise "nasty"
|
293
|
+
}
|
294
|
+
err = assert_raise RuntimeError do
|
295
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
296
|
+
end
|
297
|
+
assert_match(/nasty/i, err.message)
|
298
|
+
assert_equal [:bean1], things, "Wrong things"
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_yields_with_several_arrays
|
302
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
303
|
+
se.yields ['a','b'], ['c','d']
|
304
|
+
|
305
|
+
things = []
|
306
|
+
a_block = lambda { |thinger| things << thinger }
|
307
|
+
|
308
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
309
|
+
assert_equal [ ['a','b'], ['c','d'] ], things, "Wrong things"
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_yields_tuples
|
313
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
314
|
+
se.yields ['a','b','c'], ['d','e','f']
|
315
|
+
|
316
|
+
things = []
|
317
|
+
a_block = lambda { |left,mid,right|
|
318
|
+
things << { :left => left, :mid => mid, :right => right }
|
319
|
+
}
|
320
|
+
|
321
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
322
|
+
assert_equal [
|
323
|
+
{:left => 'a', :mid => 'b', :right => 'c' },
|
324
|
+
{:left => 'd', :mid => 'e', :right => 'f' },
|
325
|
+
], things, "Wrong things"
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_yields_tuples_size_mismatch
|
329
|
+
se = SimpleExpectation.new(:mock => @mock, :method => 'each_bean', :arguments => [:side_slot] )
|
330
|
+
se.yields ['a','b','c'], ['d','e','f']
|
331
|
+
|
332
|
+
things = []
|
333
|
+
a_block = lambda { |left,mid|
|
334
|
+
things << { :left => left, :mid => mid }
|
335
|
+
}
|
336
|
+
|
337
|
+
err = assert_raise ExpectationError do
|
338
|
+
se.apply_method_call(@mock,'each_bean',[:side_slot],a_block)
|
339
|
+
end
|
340
|
+
assert_match(/arity/i, err.message)
|
341
|
+
assert_match(/the_mock.each_bean/i, err.message)
|
342
|
+
assert_match(/"a", "b", "c"/i, err.message)
|
343
|
+
assert_equal [], things, "Wrong things"
|
344
|
+
end
|
345
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
|
+
require 'hardmock'
|
3
|
+
|
4
|
+
class TrapperTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@mock = Object.new
|
8
|
+
@mock_control = MyControl.new
|
9
|
+
@builder = ExpBuilder.new
|
10
|
+
@trapper = Trapper.new(@mock, @mock_control, @builder)
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# HELPERS
|
15
|
+
#
|
16
|
+
|
17
|
+
class MyControl
|
18
|
+
attr_reader :added
|
19
|
+
def add_expectation(expectation)
|
20
|
+
@added ||= []
|
21
|
+
@added << expectation
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ExpBuilder
|
26
|
+
attr_reader :options
|
27
|
+
def build_expectation(options)
|
28
|
+
@options = options
|
29
|
+
"dummy expectation"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# TESTS
|
35
|
+
#
|
36
|
+
|
37
|
+
def test_method_missing
|
38
|
+
|
39
|
+
output = @trapper.change(:less)
|
40
|
+
|
41
|
+
assert_same @mock, @builder.options[:mock]
|
42
|
+
assert_equal :change, @builder.options[:method]
|
43
|
+
assert_equal [:less], @builder.options[:arguments]
|
44
|
+
assert_not_nil @builder.options[:block]
|
45
|
+
assert @builder.options[:suppress_arguments_to_block], ":suppress_arguments_to_block should be set"
|
46
|
+
assert_equal [ "dummy expectation" ], @mock_control.added,
|
47
|
+
"Wrong expectation added to control"
|
48
|
+
|
49
|
+
assert_equal "dummy expectation", output, "Expectation should have been returned"
|
50
|
+
|
51
|
+
# Examine the block. It should take one argument and simply return
|
52
|
+
# that argument. because of the 'suppress arguments to block'
|
53
|
+
# setting, the argument can only end up being a block, in practice.
|
54
|
+
trapper_block = @builder.options[:block]
|
55
|
+
assert_equal "the argument", trapper_block.call("the argument"),
|
56
|
+
"The block should merely return the passed argument"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
|
+
require 'hardmock'
|
3
|
+
|
4
|
+
class VerifyErrorTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
#
|
7
|
+
# TESTS
|
8
|
+
#
|
9
|
+
|
10
|
+
def test_formatted_list_of_unmet_expectations
|
11
|
+
mock1 = Mock.new('mock1')
|
12
|
+
mock2 = Mock.new('mock2')
|
13
|
+
exp1 = SimpleExpectation.new( :mock => mock1, :method => 'send_parts', :arguments => [1,2,:a] )
|
14
|
+
exp2 = SimpleExpectation.new( :mock => mock2, :method => 'grind_it', :arguments => [] )
|
15
|
+
|
16
|
+
exp_list = [ exp1, exp2 ]
|
17
|
+
|
18
|
+
err = VerifyError.new("This is the error", exp_list)
|
19
|
+
assert_equal "This is the error:\n * #{exp1.to_s}\n * #{exp2.to_s}", err.message
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_empty_list_of_expectations
|
23
|
+
# this is not a normal case; not spending a lot of time to make this better
|
24
|
+
exp_list = []
|
25
|
+
err = VerifyError.new("This is the error:\n", exp_list)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_nil_expectation_list
|
29
|
+
# this is not a normal case; not spending a lot of time to make this better
|
30
|
+
exp_list = []
|
31
|
+
err = VerifyError.new("This is the error:\n", exp_list)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,403 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# = DESCRIPTION
|
4
|
+
#
|
5
|
+
# Systir stands for "SYStem Testing In Ruby". It's a framework for
|
6
|
+
# automating system-level tests using domain-specific language, and contains
|
7
|
+
# some tools and hints on how to construct and utilize your own domain language.
|
8
|
+
#
|
9
|
+
# The breakdown of using Systir for test automation is:
|
10
|
+
# 1. Tester defines test steps using project- and technology-specific language.
|
11
|
+
# * Tests are written in files like +authentication+.+test+ and
|
12
|
+
# +order_placement+.+test+
|
13
|
+
# 2. The Toolsmith implements a driver to support the syntax of that language
|
14
|
+
# * In a project-specific module, the Toolsmith writes an extension of the
|
15
|
+
# Systir::LanguageDriver class to support the macros used in *.test
|
16
|
+
# 3. The Tester's "scripts" are gathered up by Systir, executed, and a report
|
17
|
+
# is generated.
|
18
|
+
# * Toolsmith writes a short script which uses Systest::Launcher to compose
|
19
|
+
# *.test files into a suite for execution.
|
20
|
+
#
|
21
|
+
# = TECHNICAL NOTE
|
22
|
+
# Under the hood, Systir is an extension of Test::Unit. The output from
|
23
|
+
# executing the test suite should therefor be familiar to a Ruby coder.
|
24
|
+
# Additionally, it might be educational to the Toolsmith to understand that
|
25
|
+
# LanguageDriver is a derivative of Test::Unit::TestCase, and that all *.test
|
26
|
+
# files become test methods inside the TestCase which is then composed as a
|
27
|
+
# Test::Unit::TestSuite
|
28
|
+
#
|
29
|
+
|
30
|
+
require 'test/unit'
|
31
|
+
require 'test/unit/ui/console/testrunner'
|
32
|
+
require 'test/unit/ui/xml/testrunner'
|
33
|
+
require 'find'
|
34
|
+
require 'stringio'
|
35
|
+
require 'ostruct'
|
36
|
+
|
37
|
+
# This disables the auto-run-at-exit feature inside test/unit.rb:
|
38
|
+
Test::Unit.run = true
|
39
|
+
|
40
|
+
module Test
|
41
|
+
module Unit
|
42
|
+
class TestResult
|
43
|
+
attr_reader :failures, :errors, :assertion_count
|
44
|
+
attr_accessor :output
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Systir contains classes and modules to support writing and launching
|
51
|
+
# high-level test scripts.
|
52
|
+
#
|
53
|
+
module Systir
|
54
|
+
|
55
|
+
VERSION = '0.5'
|
56
|
+
|
57
|
+
#
|
58
|
+
# Systir::LanguageDriver is a special derivative of TestCase designed to
|
59
|
+
# contain user code written to support more macro-fied testing scripts.
|
60
|
+
#
|
61
|
+
class LanguageDriver < Test::Unit::TestCase
|
62
|
+
attr_accessor :params
|
63
|
+
|
64
|
+
# == Description
|
65
|
+
# Installs a back-reference from this Driver instance into the specified Helper
|
66
|
+
# and returns a reference to that Helper. Typically thismethod is called
|
67
|
+
# on the same line you return the helper from once it's built.
|
68
|
+
#
|
69
|
+
# == Params
|
70
|
+
# +helper+ :: The Helper instance you're handing control over to
|
71
|
+
#
|
72
|
+
# == Return
|
73
|
+
# The same +helper+ reference that was sent in as a parameter.
|
74
|
+
#
|
75
|
+
# == Details
|
76
|
+
#
|
77
|
+
# Since Helpers are usually built as support for domain-level syntax,
|
78
|
+
# they usually require a direct reference to macro functions built into
|
79
|
+
# the driver. Additionally, the Helper may need to make assertions
|
80
|
+
# defined in the driver, or test/unit itself, and only the Driver may
|
81
|
+
# count assertions; the Helper must use a special internal implementation
|
82
|
+
# of 'add_assertion' in order to increment the test's assertion count.
|
83
|
+
#
|
84
|
+
# Some aliases have been added to aid readability
|
85
|
+
#
|
86
|
+
def associate_helper(helper)
|
87
|
+
unless helper.respond_to? :driver=
|
88
|
+
raise "helper doesn't support 'driver=' method"
|
89
|
+
end
|
90
|
+
helper.driver = self
|
91
|
+
return helper
|
92
|
+
end
|
93
|
+
alias_method :return_helper, :associate_helper
|
94
|
+
alias_method :hand_off_to, :associate_helper
|
95
|
+
|
96
|
+
# (INTERNAL USE)
|
97
|
+
# Sneaky trick to expose the private mix-in method +add_assertion+ from
|
98
|
+
# Test::Unit::Assertions. Helpers derivatives that make assertions are
|
99
|
+
# able to have them counted because of this method.
|
100
|
+
# (See associate_helper.)
|
101
|
+
def collect_assertion
|
102
|
+
add_assertion
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# = Description
|
107
|
+
# Imports test scripts into the given driver class
|
108
|
+
# and produces a TestSuite ready for execution
|
109
|
+
class Builder
|
110
|
+
def initialize(driver_class)
|
111
|
+
raise 'driver class must be a Systir::LanguageDriver' unless driver_class < Systir::LanguageDriver
|
112
|
+
@driver_class = driver_class
|
113
|
+
remove_test_methods
|
114
|
+
end
|
115
|
+
|
116
|
+
# Read contents from_file, wrap text in 'def',
|
117
|
+
# add the resulting code as a new method on the target driver class
|
118
|
+
def import_test(test)
|
119
|
+
# Transform the test script into a test method inside
|
120
|
+
# the driver class:
|
121
|
+
text = File.readlines(test.path)
|
122
|
+
text = "def test_#{test.fullname}\n#{text}\nend\n";
|
123
|
+
|
124
|
+
# Dynamically define the method:
|
125
|
+
@driver_class.class_eval(text, File.basename(test.path), 0)
|
126
|
+
test_case = @driver_class.new("test_#{test.fullname}")
|
127
|
+
test_case.params = test.params
|
128
|
+
test_case
|
129
|
+
end
|
130
|
+
|
131
|
+
def suite_for_directory(dir)
|
132
|
+
list = TestList.new
|
133
|
+
Find.find(dir) do |path|
|
134
|
+
if File.basename(path) =~ /\.test$/
|
135
|
+
list.add :test => path
|
136
|
+
end
|
137
|
+
if File.directory? path
|
138
|
+
next
|
139
|
+
end
|
140
|
+
end
|
141
|
+
suite_for_test_list list
|
142
|
+
end
|
143
|
+
|
144
|
+
def suite_for_file(filename,params=nil)
|
145
|
+
list = TestList.new
|
146
|
+
list.add :test => filename, :params => params
|
147
|
+
suite_for_test_list list
|
148
|
+
end
|
149
|
+
|
150
|
+
def suite_for_list(file_list)
|
151
|
+
list = TestList.new
|
152
|
+
file_list.each do |path|
|
153
|
+
list.add :test => path
|
154
|
+
end
|
155
|
+
suite_for_test_list list
|
156
|
+
end
|
157
|
+
|
158
|
+
def suite_for_test_list(test_list)
|
159
|
+
suite = Test::Unit::TestSuite.new(@driver_class.name)
|
160
|
+
test_list.tests.each do |test|
|
161
|
+
suite << import_test(test)
|
162
|
+
end
|
163
|
+
suite
|
164
|
+
end
|
165
|
+
|
166
|
+
def remove_test_methods
|
167
|
+
methods = @driver_class.public_instance_methods.select { |m|
|
168
|
+
m =~ /^test_/
|
169
|
+
}
|
170
|
+
methods.each do |method|
|
171
|
+
@driver_class.send(:undef_method,method)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class TestList #:nodoc:
|
177
|
+
attr_reader :tests
|
178
|
+
|
179
|
+
def initialize
|
180
|
+
@tests = []
|
181
|
+
end
|
182
|
+
|
183
|
+
def add(args)
|
184
|
+
test = OpenStruct.new
|
185
|
+
test.path = args[:test]
|
186
|
+
test.params = args[:params]
|
187
|
+
test.name = File.basename(test.path).sub(/\.test$/, '')
|
188
|
+
test.fullname = test.name + (args[:name_suffix] ? "_#{args[:name_suffix]}" : '')
|
189
|
+
@tests << test
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# = Description
|
194
|
+
# Launcher is the utility for launching Systir test scripts.
|
195
|
+
#
|
196
|
+
class Launcher
|
197
|
+
#
|
198
|
+
# Creates a new Launcher, the following arguments may be specified in a hash
|
199
|
+
#
|
200
|
+
# :stdout - true or false, whether to send test reporting output to stdout (default true)
|
201
|
+
# :format - :console or :xml, format of test reporting output (default :xml)
|
202
|
+
#
|
203
|
+
# note: output is available via the TestResult returned from the following methods:
|
204
|
+
# * find_and_run_all_tests
|
205
|
+
# * run_test
|
206
|
+
# * run_test_list
|
207
|
+
# * run_suite
|
208
|
+
#
|
209
|
+
def initialize(args={})
|
210
|
+
@stdout = args[:stdout].nil? ? true : args[:stdout]
|
211
|
+
@format = args[:format].nil? ? :console : args[:format]
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# Find and run all the system test scripts in the given directory.
|
216
|
+
# Tests are identified by the .test file extension.
|
217
|
+
#
|
218
|
+
def find_and_run_all_tests(driver_class, dir='.')
|
219
|
+
raise 'dir cannot be nil' if dir.nil?
|
220
|
+
raise 'dir does not exist' unless File.directory?(dir)
|
221
|
+
b = Builder.new(driver_class)
|
222
|
+
execute b.suite_for_directory(dir)
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
# Run a specific test, optionally providing parameters to be available
|
227
|
+
# within the driver instance.
|
228
|
+
#
|
229
|
+
# Systir::Launcher.new.run_test(MyDriver, './tests/foo.test')
|
230
|
+
#
|
231
|
+
# Systir::Launcher.new.run_test(MyDriver, './tests/foo.test', :opt1 => 'thinger', :another => 'bar')
|
232
|
+
#
|
233
|
+
# given parameters are available via the <tt>params</tt> method on the
|
234
|
+
# driver instance which returns the hash passed to run_test.
|
235
|
+
#
|
236
|
+
# returns TestResult
|
237
|
+
#
|
238
|
+
def run_test(driver_class, filename, params=nil)
|
239
|
+
raise 'filename cannot be nil' if filename.nil?
|
240
|
+
raise 'filename does not exist' unless File.exists?(filename)
|
241
|
+
b = Builder.new(driver_class)
|
242
|
+
execute b.suite_for_file(filename,params)
|
243
|
+
end
|
244
|
+
|
245
|
+
#
|
246
|
+
# Run a specific list of tests
|
247
|
+
#
|
248
|
+
# returns TestResult
|
249
|
+
#
|
250
|
+
def run_test_list(driver_class, file_list)
|
251
|
+
raise 'file_list cannot be nil' if file_list.nil?
|
252
|
+
raise 'file_list cannot be empty' if file_list.empty?
|
253
|
+
b = Builder.new(driver_class)
|
254
|
+
execute b.suite_for_list(file_list)
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
# Run a suite of tests defined by a given block.
|
259
|
+
#
|
260
|
+
# launcher.run_suite(MyDriver) do |suite|
|
261
|
+
# suite.add :test => './tests/run_me_twice.test'
|
262
|
+
# suite.add :test => './tests/run_me_twice.test', :name_suffix => 'other_one'
|
263
|
+
# suite.add :test => './tests/specific_parameters.test', :params => {:one => 'mine', :two => 'also mine'}
|
264
|
+
# end
|
265
|
+
#
|
266
|
+
# :test - path to the systir test file
|
267
|
+
# :name_suffix - (optional) string appended to the end of the test name in
|
268
|
+
# this suite run.this option is useful when running multiple
|
269
|
+
# tests from the same file.
|
270
|
+
# :params - (optional) hash of parameters to be set on the driver instance
|
271
|
+
# for the execution of this test
|
272
|
+
#
|
273
|
+
# returns TestResult
|
274
|
+
#
|
275
|
+
def run_suite(driver_class)
|
276
|
+
b = Builder.new(driver_class)
|
277
|
+
suite = TestList.new
|
278
|
+
yield suite
|
279
|
+
execute b.suite_for_test_list(suite)
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# Use console test runner to execute the given suite
|
284
|
+
#
|
285
|
+
def execute(suite)
|
286
|
+
buffer = StringIO.new
|
287
|
+
ios = []
|
288
|
+
ios << STDOUT if @stdout
|
289
|
+
ios << buffer
|
290
|
+
io = MethodMulticaster.new(ios)
|
291
|
+
level = Test::Unit::UI::NORMAL
|
292
|
+
|
293
|
+
runner = case @format
|
294
|
+
when :console
|
295
|
+
Test::Unit::UI::Console::TestRunner
|
296
|
+
when :xml
|
297
|
+
Test::Unit::UI::XML::TestRunner
|
298
|
+
else
|
299
|
+
raise "don't know anything about runner: [#{@runner}]"
|
300
|
+
end
|
301
|
+
|
302
|
+
result = runner.new(suite, level, io).start
|
303
|
+
buffer.rewind
|
304
|
+
result.output = buffer.read
|
305
|
+
result
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class MethodMulticaster #:nodoc:
|
310
|
+
def initialize(targets)
|
311
|
+
@targets = targets
|
312
|
+
end
|
313
|
+
|
314
|
+
def method_missing(method,*args)
|
315
|
+
@targets.each do |target|
|
316
|
+
target.send(method,*args)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
# = DESCRIPTION
|
323
|
+
# Systir::Helper is a module intended for mixing-in to classes defined
|
324
|
+
# to assist a project-specific Systir::LanguageDriver.
|
325
|
+
#
|
326
|
+
#
|
327
|
+
module Helper
|
328
|
+
include Test::Unit::Assertions
|
329
|
+
|
330
|
+
#
|
331
|
+
# Construct a new Helper with a back reference to the language driver.
|
332
|
+
# NOTE: the +driver+ argument is optional if you utilize <code>driver=</code>
|
333
|
+
# or Systir::LanguageDriver.associate_helper
|
334
|
+
#
|
335
|
+
def initialize(driver=nil)
|
336
|
+
@_driver = driver
|
337
|
+
end
|
338
|
+
|
339
|
+
#
|
340
|
+
# Returns a reference to our owning LanguageDriver instance.
|
341
|
+
#
|
342
|
+
def driver
|
343
|
+
unless @_driver
|
344
|
+
raise "Implementation error: helper has no back reference to the language driver!"
|
345
|
+
end
|
346
|
+
return @_driver
|
347
|
+
end
|
348
|
+
|
349
|
+
#
|
350
|
+
# Sets the owning reference to a LanguageDriver.
|
351
|
+
# This method is used by Systir::LanguageDriver#associate_helper.
|
352
|
+
#
|
353
|
+
def driver=(dr)
|
354
|
+
@_driver = dr
|
355
|
+
end
|
356
|
+
|
357
|
+
# == Description
|
358
|
+
# Installs a back-reference from this Driver instance into the specified Helper
|
359
|
+
# and returns a reference to that Helper. Typically thismethod is called
|
360
|
+
# on the same line you return the helper from once it's built.
|
361
|
+
#
|
362
|
+
# == Params
|
363
|
+
# +helper+ :: The Helper instance you're handing control over to
|
364
|
+
#
|
365
|
+
# == Return
|
366
|
+
# The same +helper+ reference that was sent in as a parameter.
|
367
|
+
#
|
368
|
+
# == Details
|
369
|
+
#
|
370
|
+
# Since Helpers are usually built as support for domain-level syntax,
|
371
|
+
# they usually require a direct reference to macro functions built into
|
372
|
+
# the driver. Additionally, the Helper may need to make assertions
|
373
|
+
# defined in the driver, or test/unit itself, and only the Driver may
|
374
|
+
# count assertions; the Helper must use a special internal implementation
|
375
|
+
# of 'add_assertion' in order to increment the test's assertion count.
|
376
|
+
#
|
377
|
+
# Some aliases have been added to aid readability
|
378
|
+
#
|
379
|
+
def associate_helper(helper)
|
380
|
+
unless helper.respond_to? :driver=
|
381
|
+
raise "helper doesn't support 'driver=' method"
|
382
|
+
end
|
383
|
+
helper.driver = self.driver
|
384
|
+
return helper
|
385
|
+
end
|
386
|
+
alias_method :return_helper, :associate_helper
|
387
|
+
alias_method :hand_off_to, :associate_helper
|
388
|
+
|
389
|
+
#
|
390
|
+
# Redirects assertion counting into our owning LanguageDriver.
|
391
|
+
# Assertions module will automatically attempt to store the count
|
392
|
+
# within a Helper otherwise, leading to incorrect results.
|
393
|
+
#
|
394
|
+
private
|
395
|
+
def add_assertion
|
396
|
+
unless driver.respond_to? :collect_assertion
|
397
|
+
raise "Implementation error: driver needs a 'collect_assertion' method"
|
398
|
+
end
|
399
|
+
driver.collect_assertion
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|