BanzaiMan-ZenTest 4.2

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.
@@ -0,0 +1,117 @@
1
+ ##
2
+ # ZenTestMapping - mapping method names from impl to test.
3
+ #
4
+ # Method names are mapped bidirectionally in the following way:
5
+ #
6
+ # method test_method
7
+ # method? test_method_eh (too much exposure to Canadians :)
8
+ # method! test_method_bang
9
+ # method= test_method_equals
10
+ # [] test_index
11
+ # * test_times
12
+ # == test_equals2
13
+ # === test_equals3
14
+ #
15
+ # Further, any of the test methods should be able to have arbitrary
16
+ # extensions put on the name to distinguish edge cases:
17
+ #
18
+ # method test_method
19
+ # method test_method_simple
20
+ # method test_method_no_network
21
+ #
22
+ # To allow for unmapped test methods (ie, non-unit tests), name them:
23
+ #
24
+ # test_integration_.*
25
+
26
+ module ZenTestMapping
27
+
28
+ @@orig_method_map = {
29
+ '!' => 'bang',
30
+ '%' => 'percent',
31
+ '&' => 'and',
32
+ '*' => 'times',
33
+ '**' => 'times2',
34
+ '+' => 'plus',
35
+ '-' => 'minus',
36
+ '/' => 'div',
37
+ '<' => 'lt',
38
+ '<=' => 'lte',
39
+ '<=>' => 'spaceship',
40
+ "<\<" => 'lt2',
41
+ '==' => 'equals2',
42
+ '===' => 'equals3',
43
+ '=~' => 'equalstilde',
44
+ '>' => 'gt',
45
+ '>=' => 'ge',
46
+ '>>' => 'gt2',
47
+ '+@' => 'unary_plus',
48
+ '-@' => 'unary_minus',
49
+ '[]' => 'index',
50
+ '[]=' => 'index_equals',
51
+ '^' => 'carat',
52
+ '|' => 'or',
53
+ '~' => 'tilde',
54
+ }
55
+
56
+ @@method_map = @@orig_method_map.merge(@@orig_method_map.invert)
57
+
58
+ @@mapped_re = @@orig_method_map.values.sort_by { |k| k.length }.map {|s|
59
+ Regexp.escape(s)
60
+ }.reverse.join("|")
61
+
62
+ def munge name
63
+ name = name.to_s.dup
64
+
65
+ is_cls_method = name.sub!(/^self\./, '')
66
+
67
+ name = @@method_map[name] if @@method_map.has_key? name
68
+ name = name.sub(/=$/, '_equals')
69
+ name = name.sub(/\?$/, '_eh')
70
+ name = name.sub(/\!$/, '_bang')
71
+
72
+ name = yield name if block_given?
73
+
74
+ name = "class_" + name if is_cls_method
75
+
76
+ name
77
+ end
78
+
79
+ # Generates a test method name from a normal method,
80
+ # taking into account names composed of metacharacters
81
+ # (used for arithmetic, etc
82
+ def normal_to_test name
83
+ "test_#{munge name}"
84
+ end
85
+
86
+ def unmunge name
87
+ name = name.to_s.dup
88
+
89
+ is_cls_method = name.sub!(/^class_/, '')
90
+
91
+ name = name.sub(/_equals(_.*)?$/, '=') unless name =~ /index/
92
+ name = name.sub(/_bang(_.*)?$/, '!')
93
+ name = name.sub(/_eh(_.*)?$/, '?')
94
+ name = name.sub(/^(#{@@mapped_re})(_.*)?$/) {$1}
95
+ name = yield name if block_given?
96
+ name = @@method_map[name] if @@method_map.has_key? name
97
+ name = 'self.' + name if is_cls_method
98
+
99
+ name
100
+ end
101
+
102
+ # Converts a method name beginning with test to its
103
+ # corresponding normal method name, taking into account
104
+ # symbolic names which may have been anglicised by
105
+ # #normal_to_test().
106
+ def test_to_normal(name, klassname=nil)
107
+ unmunge(name.to_s.sub(/^test_/, '')) do |n|
108
+ if defined? @inherited_methods then
109
+ known_methods = (@inherited_methods[klassname] || {}).keys.sort.reverse
110
+ known_methods_re = known_methods.map {|s| Regexp.escape(s) }.join("|")
111
+ n = n.sub(/^(#{known_methods_re})(_.*)?$/) { $1 } unless
112
+ known_methods_re.empty?
113
+ n
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,471 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ $TESTING = true
4
+
5
+ require 'rubygems'
6
+ require 'minitest/autorun'
7
+
8
+ require 'stringio'
9
+ require 'autotest'
10
+
11
+ # NOT TESTED:
12
+ # class_run
13
+ # add_sigint_handler
14
+ # all_good
15
+ # get_to_green
16
+ # reset
17
+ # ruby
18
+ # run
19
+ # run_tests
20
+
21
+ class Autotest
22
+ attr_reader :test_mappings, :exception_list
23
+
24
+ def self.clear_hooks
25
+ HOOKS.clear
26
+ end
27
+ end
28
+
29
+ class TestAutotest < MiniTest::Unit::TestCase
30
+
31
+ def deny test, msg=nil
32
+ if msg then
33
+ assert ! test, msg
34
+ else
35
+ assert ! test
36
+ end
37
+ end unless respond_to? :deny
38
+
39
+ RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) unless defined? RUBY
40
+ OBJECTSPACE_OPT = RUBY_PLATFORM =~ /java/ ? '-X+O' : ''
41
+
42
+ def setup
43
+ @test_class = 'TestBlah'
44
+ @test = 'test/test_blah.rb'
45
+ @other_test = 'test/test_blah_other.rb'
46
+ @impl = 'lib/blah.rb'
47
+ @inner_test = 'test/outer/test_inner.rb'
48
+ @outer_test = 'test/test_outer.rb'
49
+ @inner_test_class = "TestOuter::TestInner"
50
+
51
+ klassname = self.class.name.sub(/^Test/, '')
52
+ klassname.sub!(/^(\w+)(Autotest)$/, '\2::\1') unless klassname == "Autotest"
53
+ @a = klassname.split(/::/).inject(Object) { |k,n| k.const_get(n) }.new
54
+ @a.output = StringIO.new
55
+ @a.last_mtime = Time.at(2)
56
+
57
+ @files = {}
58
+ @files[@impl] = Time.at(1)
59
+ @files[@test] = Time.at(2)
60
+
61
+ @a.find_order = @files.keys.sort
62
+ end
63
+
64
+ def test_add_exception
65
+ current = util_exceptions
66
+ @a.add_exception 'blah'
67
+
68
+ actual = util_exceptions
69
+ expect = current + ["blah"]
70
+
71
+ assert_equal expect, actual
72
+ end
73
+
74
+ def test_add_mapping
75
+ current = util_mappings
76
+ @a.add_mapping(/blah/) do 42 end
77
+
78
+ actual = util_mappings
79
+ expect = current + [/blah/]
80
+
81
+ assert_equal expect, actual
82
+ end
83
+
84
+ def test_add_mapping_front
85
+ current = util_mappings
86
+ @a.add_mapping(/blah/, :front) do 42 end
87
+
88
+ actual = util_mappings
89
+ expect = [/blah/] + current
90
+
91
+ assert_equal expect, actual
92
+ end
93
+
94
+ def test_clear_exceptions
95
+ test_add_exception
96
+ @a.clear_exceptions
97
+
98
+ actual = util_exceptions
99
+ expect = []
100
+
101
+ assert_equal expect, actual
102
+ end
103
+
104
+ def test_clear_mapping
105
+ @a.clear_mappings
106
+
107
+ actual = util_mappings
108
+ expect = []
109
+
110
+ assert_equal expect, actual
111
+ end
112
+
113
+ def test_consolidate_failures_experiment
114
+ @files.clear
115
+ @files[@impl] = Time.at(1)
116
+ @files[@test] = Time.at(2)
117
+
118
+ @a.find_order = @files.keys.sort
119
+
120
+ input = [['test_fail1', @test_class], ['test_fail2', @test_class], ['test_error1', @test_class], ['test_error2', @test_class]]
121
+ result = @a.consolidate_failures input
122
+ expected = { @test => %w( test_fail1 test_fail2 test_error1 test_error2 ) }
123
+ assert_equal expected, result
124
+ end
125
+
126
+ def test_consolidate_failures_green
127
+ result = @a.consolidate_failures([])
128
+ expected = {}
129
+ assert_equal expected, result
130
+ end
131
+
132
+ def test_consolidate_failures_multiple_possibilities
133
+ @files[@other_test] = Time.at(42)
134
+ result = @a.consolidate_failures([['test_unmatched', @test_class]])
135
+ expected = { @test => ['test_unmatched']}
136
+ assert_equal expected, result
137
+ expected = ""
138
+ assert_equal expected, @a.output.string
139
+ end
140
+
141
+ def test_consolidate_failures_nested_classes
142
+ @files.clear
143
+ @files['lib/outer.rb'] = Time.at(5)
144
+ @files['lib/outer/inner.rb'] = Time.at(5)
145
+ @files[@inner_test] = Time.at(5)
146
+ @files[@outer_test] = Time.at(5)
147
+
148
+ @a.find_order = @files.keys.sort
149
+
150
+ result = @a.consolidate_failures([['test_blah1', @inner_test_class]])
151
+ expected = { @inner_test => ['test_blah1'] }
152
+ assert_equal expected, result
153
+ expected = ""
154
+ assert_equal expected, @a.output.string
155
+ end
156
+
157
+ def test_consolidate_failures_no_match
158
+ result = @a.consolidate_failures([['test_blah1', @test_class], ['test_blah2', @test_class], ['test_blah1', 'TestUnknown']])
159
+ expected = {@test => ['test_blah1', 'test_blah2']}
160
+ assert_equal expected, result
161
+ expected = "Unable to map class TestUnknown to a file\n"
162
+ assert_equal expected, @a.output.string
163
+ end
164
+
165
+ def test_consolidate_failures_red
166
+ result = @a.consolidate_failures([['test_blah1', @test_class], ['test_blah2', @test_class]])
167
+ expected = {@test => ['test_blah1', 'test_blah2']}
168
+ assert_equal expected, result
169
+ end
170
+
171
+ def test_exceptions
172
+ @a.clear_exceptions
173
+ test_add_exception
174
+ assert_equal(/blah/, @a.exceptions)
175
+ end
176
+
177
+ def test_exceptions_nil
178
+ @a.clear_exceptions
179
+ assert_nil @a.exceptions
180
+ end
181
+
182
+ # TODO: lots of filename edgecases for find_files_to_test
183
+ def test_find_files_to_test
184
+ @a.last_mtime = Time.at(0)
185
+ assert @a.find_files_to_test(@files)
186
+
187
+ @a.last_mtime = @files.values.sort.last + 1
188
+ deny @a.find_files_to_test(@files)
189
+ end
190
+
191
+ def test_find_files_to_test_dunno
192
+ empty = {}
193
+
194
+ files = { "fooby.rb" => Time.at(42) }
195
+ assert @a.find_files_to_test(files) # we find fooby,
196
+ assert_equal empty, @a.files_to_test # but it isn't something to test
197
+ assert_equal "No tests matched fooby.rb\n", @a.output.string
198
+ end
199
+
200
+ def test_find_files_to_test_lib
201
+ # ensure we add test_blah.rb when blah.rb updates
202
+ util_find_files_to_test(@impl, @test => [])
203
+ end
204
+
205
+ def test_find_files_to_test_no_change
206
+ empty = {}
207
+
208
+ # ensure world is virginal
209
+ assert_equal empty, @a.files_to_test
210
+
211
+ # ensure we do nothing when nothing changes...
212
+ files = { @impl => @files[@impl] } # same time
213
+ deny @a.find_files_to_test(files)
214
+ assert_equal empty, @a.files_to_test
215
+ assert_equal "", @a.output.string
216
+
217
+ files = { @impl => @files[@impl] } # same time
218
+ assert(! @a.find_files_to_test(files))
219
+ assert_equal empty, @a.files_to_test
220
+ assert_equal "", @a.output.string
221
+ end
222
+
223
+ def test_find_files_to_test_test
224
+ # ensure we add test_blah.rb when test_blah.rb itself updates
225
+ util_find_files_to_test(@test, @test => [])
226
+ end
227
+
228
+ def test_reorder_alpha
229
+ @a.order = :alpha
230
+ expected = @files.sort
231
+
232
+ assert_equal expected, @a.reorder(@files)
233
+ end
234
+
235
+ def test_reorder_reverse
236
+ @a.order = :reverse
237
+ expected = @files.sort.reverse
238
+
239
+ assert_equal expected, @a.reorder(@files)
240
+ end
241
+
242
+ def test_reorder_random
243
+ @a.order = :random
244
+
245
+ srand 42
246
+ expected, size = @files.dup, @files.size
247
+ expected = expected.sort_by { rand(size) }
248
+
249
+ srand 42
250
+ result = @a.reorder(@files.dup)
251
+
252
+ assert_equal expected, result
253
+ end
254
+
255
+ def test_reorder_natural
256
+ srand 42
257
+
258
+ @files['lib/untested_blah.rb'] = Time.at(2)
259
+ @a.find_order = @files.keys.sort_by { rand }
260
+
261
+ @a.order = :natural
262
+ expected = @a.find_order.map { |f| [f, @files[f]] }
263
+
264
+ assert_equal expected, @a.reorder(@files)
265
+ end
266
+
267
+ def test_handle_results
268
+ @a.files_to_test.clear
269
+ @files.clear
270
+ @files[@impl] = Time.at(1)
271
+ @files[@test] = Time.at(2)
272
+
273
+ @a.find_order = @files.keys.sort
274
+
275
+ empty = {}
276
+ assert_equal empty, @a.files_to_test, "must start empty"
277
+
278
+ s1 = "Loaded suite -e
279
+ Started
280
+ ............
281
+ Finished in 0.001655 seconds.
282
+
283
+ 12 tests, 18 assertions, 0 failures, 0 errors
284
+ "
285
+
286
+ @a.handle_results(s1)
287
+ assert_equal empty, @a.files_to_test, "must stay empty"
288
+
289
+ s2 = "
290
+ 1) Failure:
291
+ test_fail1(#{@test_class}) [#{@test}:59]:
292
+ 2) Failure:
293
+ test_fail2(#{@test_class}) [#{@test}:60]:
294
+ 3) Error:
295
+ test_error1(#{@test_class}):
296
+ 3) Error:
297
+ test_error2(#{@test_class}):
298
+
299
+ 12 tests, 18 assertions, 2 failures, 2 errors
300
+ "
301
+
302
+ @a.handle_results(s2)
303
+ expected = { @test => %w( test_fail1 test_fail2 test_error1 test_error2 ) }
304
+ assert_equal expected, @a.files_to_test
305
+ assert @a.tainted
306
+
307
+ @a.handle_results(s1)
308
+ assert_equal empty, @a.files_to_test
309
+
310
+ s3 = '
311
+ /opt/bin/ruby -I.:lib:test -rubygems -e "%w[test/unit #{@test}].each { |f| require f }" | unit_diff -u
312
+ -e:1:in `require\': ./#{@test}:23: parse error, unexpected tIDENTIFIER, expecting \'}\' (SyntaxError)
313
+ settings_fields.each {|e| assert_equal e, version.send e.intern}
314
+ ^ from -e:1
315
+ from -e:1:in `each\'
316
+ from -e:1
317
+ '
318
+ @a.files_to_test[@test] = Time.at(42)
319
+ @files[@test] = []
320
+ expected = { @test => Time.at(42) }
321
+ assert_equal expected, @a.files_to_test
322
+ @a.handle_results(s3)
323
+ assert_equal expected, @a.files_to_test
324
+ assert @a.tainted
325
+ @a.tainted = false
326
+
327
+ @a.handle_results(s1)
328
+ assert_equal empty, @a.files_to_test
329
+ deny @a.tainted
330
+ end
331
+
332
+ def test_hook_overlap_returning_false
333
+ util_reset_hooks_returning false
334
+
335
+ @a.hook :blah
336
+
337
+ assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
338
+ assert @a.instance_variable_get(:@blah2), "Hook2 should work on blah"
339
+ assert @a.instance_variable_get(:@blah3), "Hook3 should work on blah"
340
+ end
341
+
342
+ def test_hook_overlap_returning_true
343
+ util_reset_hooks_returning true
344
+
345
+ @a.hook :blah
346
+
347
+ assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
348
+ deny @a.instance_variable_get(:@blah2), "Hook2 should NOT work on blah"
349
+ deny @a.instance_variable_get(:@blah3), "Hook3 should NOT work on blah"
350
+ end
351
+
352
+ def test_hook_response
353
+ Autotest.clear_hooks
354
+ deny @a.hook(:blah)
355
+
356
+ Autotest.add_hook(:blah) { false }
357
+ deny @a.hook(:blah)
358
+
359
+ Autotest.add_hook(:blah) { false }
360
+ deny @a.hook(:blah)
361
+
362
+ Autotest.add_hook(:blah) { true }
363
+ assert @a.hook(:blah)
364
+ end
365
+
366
+ def test_make_test_cmd
367
+ f = {
368
+ @test => [],
369
+ 'test/test_fooby.rb' => [ 'test_something1', 'test_something2' ]
370
+ }
371
+
372
+ expected = [ "#{RUBY} #{OBJECTSPACE_OPT} -I.:lib:test -rubygems -e \"%w[test/unit #{@test}].each { |f| require f }\" | #{RUBY} #{OBJECTSPACE_OPT} -s -S unit_diff -u",
373
+ "#{RUBY} #{OBJECTSPACE_OPT} -I.:lib:test -rubygems test/test_fooby.rb -n \"/^(test_something1|test_something2)$/\" | #{RUBY} #{OBJECTSPACE_OPT} -s -S unit_diff -u" ].join("; ")
374
+
375
+ result = @a.make_test_cmd f
376
+ assert_equal expected, result
377
+ end
378
+
379
+ def test_path_to_classname
380
+ # non-rails
381
+ util_path_to_classname 'TestBlah', 'test/test_blah.rb'
382
+ util_path_to_classname 'TestOuter::TestInner', 'test/outer/test_inner.rb'
383
+ util_path_to_classname 'TestRuby2Ruby', 'test/test_ruby2ruby.rb'
384
+ end
385
+
386
+ def test_remove_exception
387
+ test_add_exception
388
+ current = util_exceptions
389
+ @a.remove_exception 'blah'
390
+
391
+ actual = util_exceptions
392
+ expect = current - ["blah"]
393
+
394
+ assert_equal expect, actual
395
+ end
396
+
397
+ def test_remove_mapping
398
+ current = util_mappings
399
+ @a.remove_mapping(/^lib\/.*\.rb$/)
400
+
401
+ actual = util_mappings
402
+ expect = current - [/^lib\/.*\.rb$/]
403
+
404
+ assert_equal expect, actual
405
+ end
406
+
407
+ def test_test_files_for
408
+ assert_equal [@test], @a.test_files_for(@impl)
409
+ assert_equal [@test], @a.test_files_for(@test)
410
+
411
+ assert_equal [], @a.test_files_for('test/test_unknown.rb')
412
+ assert_equal [], @a.test_files_for('lib/unknown.rb')
413
+ assert_equal [], @a.test_files_for('unknown.rb')
414
+ assert_equal [], @a.test_files_for('test_unknown.rb')
415
+ end
416
+
417
+ def test_testlib
418
+ assert_equal "test/unit", @a.testlib
419
+
420
+ @a.testlib = "MONKEY"
421
+ assert_equal "MONKEY", @a.testlib
422
+
423
+ f = { @test => [], "test/test_fooby.rb" => %w(first second) }
424
+ assert_match @a.testlib, @a.make_test_cmd(f)
425
+ end
426
+
427
+ def util_exceptions
428
+ @a.exception_list.sort_by { |r| r.to_s }
429
+ end
430
+
431
+ def util_find_files_to_test(f, expected)
432
+ t = @a.last_mtime
433
+ files = { f => t + 1 }
434
+
435
+ assert @a.find_files_to_test(files)
436
+ assert_equal expected, @a.files_to_test
437
+ assert_equal t, @a.last_mtime
438
+ assert_equal "", @a.output.string
439
+ end
440
+
441
+ def util_mappings
442
+ @a.test_mappings.map { |k,v| k }
443
+ end
444
+
445
+ def util_path_to_classname(e,i)
446
+ assert_equal e, @a.path_to_classname(i)
447
+ end
448
+
449
+ def util_reset_hooks_returning val
450
+ Autotest.clear_hooks
451
+
452
+ @a.instance_variable_set :@blah1, false
453
+ @a.instance_variable_set :@blah2, false
454
+ @a.instance_variable_set :@blah3, false
455
+
456
+ Autotest.add_hook(:blah) do |at|
457
+ at.instance_variable_set :@blah1, true
458
+ val
459
+ end
460
+
461
+ Autotest.add_hook(:blah) do |at|
462
+ at.instance_variable_set :@blah2, true
463
+ val
464
+ end
465
+
466
+ Autotest.add_hook(:blah) do |at|
467
+ at.instance_variable_set :@blah3, true
468
+ val
469
+ end
470
+ end
471
+ end