SlimTest 4.6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,527 @@
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
+
28
+ def self.reset_options
29
+ @@options = {}
30
+ end
31
+ end
32
+
33
+ class TestAutotest < MiniTest::Unit::TestCase
34
+
35
+ alias :deny :refute
36
+
37
+ RUBY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) unless defined? RUBY
38
+
39
+ def setup
40
+ @test_class = 'TestBlah'
41
+ @test = 'test/test_blah.rb'
42
+ @other_test = 'test/test_blah_other.rb'
43
+ @impl = 'lib/blah.rb'
44
+ @inner_test = 'test/outer/test_inner.rb'
45
+ @outer_test = 'test/test_outer.rb'
46
+ @inner_test_class = "TestOuter::TestInner"
47
+
48
+ klassname = self.class.name.sub(/^Test/, '')
49
+ klassname.sub!(/^(\w+)(Autotest)$/, '\2::\1') unless klassname == "Autotest"
50
+ @a = klassname.split(/::/).inject(Object) { |k,n| k.const_get(n) }.new
51
+ @a.output = StringIO.new
52
+ @a.last_mtime = Time.at(2)
53
+
54
+ @files = {}
55
+ @files[@impl] = Time.at(1)
56
+ @files[@test] = Time.at(2)
57
+
58
+ @a.find_order = @files.keys.sort
59
+ end
60
+
61
+ def test_add_exception
62
+ current = util_exceptions
63
+ @a.add_exception 'blah'
64
+
65
+ actual = util_exceptions
66
+ expect = current + ["blah"]
67
+
68
+ assert_equal expect, actual
69
+ end
70
+
71
+ def test_add_mapping
72
+ current = util_mappings
73
+ @a.add_mapping(/blah/) do 42 end
74
+
75
+ actual = util_mappings
76
+ expect = current + [/blah/]
77
+
78
+ assert_equal expect, actual
79
+ end
80
+
81
+ def test_add_mapping_front
82
+ current = util_mappings
83
+ @a.add_mapping(/blah/, :front) do 42 end
84
+
85
+ actual = util_mappings
86
+ expect = [/blah/] + current
87
+
88
+ assert_equal expect, actual
89
+ end
90
+
91
+ def test_clear_exceptions
92
+ test_add_exception
93
+ @a.clear_exceptions
94
+
95
+ actual = util_exceptions
96
+ expect = []
97
+
98
+ assert_equal expect, actual
99
+ end
100
+
101
+ def test_clear_mapping
102
+ @a.clear_mappings
103
+
104
+ actual = util_mappings
105
+ expect = []
106
+
107
+ assert_equal expect, actual
108
+ end
109
+
110
+ def test_consolidate_failures_experiment
111
+ @files.clear
112
+ @files[@impl] = Time.at(1)
113
+ @files[@test] = Time.at(2)
114
+
115
+ @a.find_order = @files.keys.sort
116
+
117
+ input = [['test_fail1', @test_class],
118
+ ['test_fail2', @test_class],
119
+ ['test_error1', @test_class],
120
+ ['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
+ exp = { "tests" => 12, "assertions" => 18, "failures" => 0, "errors" => 0 }
290
+ assert_equal exp, @a.latest_results
291
+
292
+ # when colours are in the error message
293
+ color_error = "
294
+ 1) \e[31mFailure:\e[0m
295
+ test_fail1(#{@test_class}) [#{@test}:59]:
296
+ 2) \e[31mFailure:\e[0m
297
+ test_fail2(#{@test_class}) [#{@test}:60]:
298
+ 3) \e[31mError:\e[0m
299
+ test_error1(#{@test_class}):
300
+ 3) \e[31mError:\e[0m
301
+ test_error2(#{@test_class}):
302
+
303
+ 12 tests, 18 assertions, 2 failures, 2 errors
304
+ "
305
+ @a.handle_results(color_error)
306
+ assert @a.tainted
307
+
308
+
309
+ s2 = "
310
+ 1) Failure:
311
+ test_fail1(#{@test_class}) [#{@test}:59]:
312
+ 2) Failure:
313
+ test_fail2(#{@test_class}) [#{@test}:60]:
314
+ 3) Error:
315
+ test_error1(#{@test_class}):
316
+ 3) Error:
317
+ test_error2(#{@test_class}):
318
+
319
+ 12 tests, 18 assertions, 2 failures, 2 errors
320
+ "
321
+
322
+ @a.handle_results(s2)
323
+ expected = { @test => %w( test_fail1 test_fail2 test_error1 test_error2 ) }
324
+ assert_equal expected, @a.files_to_test
325
+ assert @a.tainted
326
+ exp = { "tests" => 12, "assertions" => 18, "failures" => 2, "errors" => 2 }
327
+ assert_equal exp, @a.latest_results
328
+
329
+ @a.handle_results(s1)
330
+ assert_equal empty, @a.files_to_test
331
+
332
+ s3 = '
333
+ /opt/bin/ruby -I.:lib:test -rubygems -e "%w[test/unit #{@test}].each { |f| require f }" | unit_diff -u
334
+ -e:1:in `require\': ./#{@test}:23: parse error, unexpected tIDENTIFIER, expecting \'}\' (SyntaxError)
335
+ settings_fields.each {|e| assert_equal e, version.send e.intern}
336
+ ^ from -e:1
337
+ from -e:1:in `each\'
338
+ from -e:1
339
+ '
340
+ @a.files_to_test[@test] = Time.at(42)
341
+ @files[@test] = []
342
+ expected = { @test => Time.at(42) }
343
+ assert_equal expected, @a.files_to_test
344
+ @a.handle_results(s3)
345
+ assert_equal expected, @a.files_to_test
346
+ assert @a.tainted
347
+ @a.tainted = false
348
+
349
+ @a.handle_results(s1)
350
+ assert_equal empty, @a.files_to_test
351
+ deny @a.tainted
352
+ end
353
+
354
+ def test_hook_overlap_returning_false
355
+ util_reset_hooks_returning false
356
+
357
+ @a.hook :blah
358
+
359
+ assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
360
+ assert @a.instance_variable_get(:@blah2), "Hook2 should work on blah"
361
+ assert @a.instance_variable_get(:@blah3), "Hook3 should work on blah"
362
+ end
363
+
364
+ def test_hook_overlap_returning_true
365
+ util_reset_hooks_returning true
366
+
367
+ @a.hook :blah
368
+
369
+ assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
370
+ deny @a.instance_variable_get(:@blah2), "Hook2 should NOT work on blah"
371
+ deny @a.instance_variable_get(:@blah3), "Hook3 should NOT work on blah"
372
+ end
373
+
374
+ def test_hook_response
375
+ Autotest.clear_hooks
376
+ deny @a.hook(:blah)
377
+
378
+ Autotest.add_hook(:blah) { false }
379
+ deny @a.hook(:blah)
380
+
381
+ Autotest.add_hook(:blah) { false }
382
+ deny @a.hook(:blah)
383
+
384
+ Autotest.add_hook(:blah) { true }
385
+ assert @a.hook(:blah)
386
+ end
387
+
388
+ def test_make_test_cmd
389
+ f = {
390
+ @test => [],
391
+ 'test/test_fooby.rb' => [ 'test_something1', 'test_something2' ]
392
+ }
393
+
394
+ pre = "#{RUBY} -I.:lib:test -rubygems"
395
+ req = ".each { |f| require f }\""
396
+
397
+ expected =
398
+ [ "#{pre} -e \"%w[test/unit #{@test}]#{req}",
399
+ "#{pre} test/test_fooby.rb -n \"/^(test_something1|test_something2)$/\""
400
+ ].join("; ")
401
+
402
+ result = @a.make_test_cmd f
403
+ assert_equal expected, result
404
+ end
405
+
406
+ def test_make_test_cmd_unit_diff
407
+ @a.unit_diff = "unit_diff -u"
408
+ f = {
409
+ @test => [],
410
+ 'test/test_fooby.rb' => [ 'test_something1', 'test_something2' ]
411
+ }
412
+
413
+ pre = "#{RUBY} -I.:lib:test -rubygems"
414
+ req = ".each { |f| require f }\""
415
+ post = "| unit_diff -u"
416
+
417
+ expected = [ "#{pre} -e \"%w[test/unit #{@test}]#{req} #{post}",
418
+ "#{pre} test/test_fooby.rb -n \"/^(test_something1|test_something2)$/\" #{post}" ].join("; ")
419
+
420
+ result = @a.make_test_cmd f
421
+ assert_equal expected, result
422
+ end
423
+
424
+ def test_path_to_classname
425
+ # non-rails
426
+ util_path_to_classname 'TestBlah', 'test/test_blah.rb'
427
+ util_path_to_classname 'TestOuter::TestInner', 'test/outer/test_inner.rb'
428
+ util_path_to_classname 'TestRuby2Ruby', 'test/test_ruby2ruby.rb'
429
+ end
430
+
431
+ def test_remove_exception
432
+ test_add_exception
433
+ current = util_exceptions
434
+ @a.remove_exception 'blah'
435
+
436
+ actual = util_exceptions
437
+ expect = current - ["blah"]
438
+
439
+ assert_equal expect, actual
440
+ end
441
+
442
+ def test_remove_mapping
443
+ current = util_mappings
444
+ @a.remove_mapping(/^lib\/.*\.rb$/)
445
+
446
+ actual = util_mappings
447
+ expect = current - [/^lib\/.*\.rb$/]
448
+
449
+ assert_equal expect, actual
450
+ end
451
+
452
+ def test_test_files_for
453
+ assert_equal [@test], @a.test_files_for(@impl)
454
+ assert_equal [@test], @a.test_files_for(@test)
455
+
456
+ assert_equal [], @a.test_files_for('test/test_unknown.rb')
457
+ assert_equal [], @a.test_files_for('lib/unknown.rb')
458
+ assert_equal [], @a.test_files_for('unknown.rb')
459
+ assert_equal [], @a.test_files_for('test_unknown.rb')
460
+ end
461
+
462
+ def test_testlib
463
+ assert_equal "test/unit", @a.testlib
464
+
465
+ @a.testlib = "MONKEY"
466
+ assert_equal "MONKEY", @a.testlib
467
+
468
+ f = { @test => [], "test/test_fooby.rb" => %w(first second) }
469
+ assert_match @a.testlib, @a.make_test_cmd(f)
470
+ end
471
+
472
+ def test_runner_accepts_rc_options
473
+ begin
474
+ Autotest.parse_options(['--rc', 'autotest_rc'])
475
+ Autotest.new
476
+ rescue
477
+ deny $!, "It should not throw #{$!.message}"
478
+ ensure
479
+ Autotest.reset_options
480
+ end
481
+ end
482
+
483
+ def util_exceptions
484
+ @a.exception_list.sort_by { |r| r.to_s }
485
+ end
486
+
487
+ def util_find_files_to_test(f, expected)
488
+ t = @a.last_mtime
489
+ files = { f => t + 1 }
490
+
491
+ assert @a.find_files_to_test(files)
492
+ assert_equal expected, @a.files_to_test
493
+ assert_equal t, @a.last_mtime
494
+ assert_equal "", @a.output.string
495
+ end
496
+
497
+ def util_mappings
498
+ @a.test_mappings.map { |k,v| k }
499
+ end
500
+
501
+ def util_path_to_classname(e,i)
502
+ assert_equal e, @a.path_to_classname(i)
503
+ end
504
+
505
+ def util_reset_hooks_returning val
506
+ Autotest.clear_hooks
507
+
508
+ @a.instance_variable_set :@blah1, false
509
+ @a.instance_variable_set :@blah2, false
510
+ @a.instance_variable_set :@blah3, false
511
+
512
+ Autotest.add_hook(:blah) do |at|
513
+ at.instance_variable_set :@blah1, true
514
+ val
515
+ end
516
+
517
+ Autotest.add_hook(:blah) do |at|
518
+ at.instance_variable_set :@blah2, true
519
+ val
520
+ end
521
+
522
+ Autotest.add_hook(:blah) do |at|
523
+ at.instance_variable_set :@blah3, true
524
+ val
525
+ end
526
+ end
527
+ end