minilab 1.0.0-mswin32
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/.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
|
+
|