mattly-minitest 1.4.2.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,530 @@
1
+ ##
2
+ #
3
+ # Totally minimal drop-in replacement for test-unit
4
+ #
5
+ # TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
6
+
7
+ module MiniTest
8
+ class Assertion < Exception; end
9
+ class Skip < Assertion; end
10
+
11
+ file = if RUBY_VERSION =~ /^1\.9/ then # bt's expanded, but __FILE__ isn't :(
12
+ File.expand_path __FILE__
13
+ elsif __FILE__ =~ /^[^\.]/ then # assume both relative
14
+ require 'pathname'
15
+ pwd = Pathname.new Dir.pwd
16
+ pn = Pathname.new File.expand_path(__FILE__)
17
+ pn = File.join(".", pn.relative_path_from(pwd)) unless pn.relative?
18
+ pn.to_s
19
+ else # assume both are expanded
20
+ __FILE__
21
+ end
22
+
23
+ # './lib' in project dir, or '/usr/local/blahblah' if installed
24
+ MINI_DIR = File.dirname(File.dirname(file))
25
+
26
+ def self.filter_backtrace bt
27
+ return ["No backtrace"] unless bt
28
+
29
+ new_bt = []
30
+ bt.each do |line|
31
+ break if line.rindex(MINI_DIR, 0)
32
+ new_bt << line
33
+ end
34
+
35
+ new_bt = bt.reject { |line| line.rindex(MINI_DIR, 0) } if new_bt.empty?
36
+ new_bt = bt.dup if new_bt.empty?
37
+ new_bt
38
+ end
39
+
40
+ module Assertions
41
+ def mu_pp(obj)
42
+ s = obj.inspect
43
+ s = s.force_encoding(Encoding.default_external) if defined? Encoding
44
+ s
45
+ end
46
+
47
+ def _assertions= n
48
+ @_assertions = n
49
+ end
50
+
51
+ def _assertions
52
+ @_assertions ||= 0
53
+ end
54
+
55
+ def assert test, msg = nil
56
+ msg ||= "Failed assertion, no message given."
57
+ self._assertions += 1
58
+ unless test then
59
+ msg = msg.call if Proc === msg
60
+ raise MiniTest::Assertion, msg
61
+ end
62
+ true
63
+ end
64
+
65
+ def assert_block msg = nil
66
+ msg = message(msg) { "Expected block to return true value" }
67
+ assert yield, msg
68
+ end
69
+
70
+ def assert_empty obj, msg = nil
71
+ msg = message(msg) { "Expected #{obj.inspect} to be empty" }
72
+ assert_respond_to obj, :empty?
73
+ assert obj.empty?, msg
74
+ end
75
+
76
+ def assert_equal exp, act, msg = nil
77
+ msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
78
+ assert(exp == act, msg)
79
+ end
80
+
81
+ def assert_in_delta exp, act, delta = 0.001, msg = nil
82
+ n = (exp - act).abs
83
+ msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
84
+ assert delta >= n, msg
85
+ end
86
+
87
+ def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
88
+ assert_in_delta a, b, [a, b].min * epsilon, msg
89
+ end
90
+
91
+ def assert_includes collection, obj, msg = nil
92
+ msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
93
+ flip = (collection.is_a?(String)) || (obj.respond_to? :include?) && ! (collection.respond_to? :include?) # HACK for specs
94
+ obj, collection = collection, obj if flip
95
+ assert_respond_to collection, :include?
96
+ assert collection.include?(obj), msg
97
+ end
98
+
99
+ def assert_instance_of cls, obj, msg = nil
100
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
101
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
102
+ obj, cls = cls, obj if flip
103
+ assert obj.instance_of?(cls), msg
104
+ end
105
+
106
+ def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
107
+ msg = message(msg) {
108
+ "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
109
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
110
+ obj, cls = cls, obj if flip
111
+ assert obj.kind_of?(cls), msg
112
+ end
113
+
114
+ def assert_match exp, act, msg = nil
115
+ msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
116
+ assert_respond_to act, :"=~"
117
+ exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
118
+ assert exp =~ act, msg
119
+ end
120
+
121
+ def assert_nil obj, msg = nil
122
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
123
+ assert obj.nil?, msg
124
+ end
125
+
126
+ def assert_operator o1, op, o2, msg = nil
127
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
128
+ assert o1.__send__(op, o2), msg
129
+ end
130
+
131
+ def assert_raises *exp
132
+ msg = String === exp.last ? exp.pop : nil
133
+ should_raise = false
134
+ begin
135
+ yield
136
+ should_raise = true
137
+ rescue Exception => e
138
+ assert(exp.any? { |ex|
139
+ ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
140
+ }, exception_details(e, "#{mu_pp(exp)} exception expected, not"))
141
+
142
+ return e
143
+ end
144
+
145
+ exp = exp.first if exp.size == 1
146
+ flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
147
+ end
148
+
149
+ def assert_respond_to obj, meth, msg = nil
150
+ msg = message(msg) {
151
+ "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
152
+ }
153
+ flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
154
+ obj, meth = meth, obj if flip
155
+ assert obj.respond_to?(meth), msg
156
+ end
157
+
158
+ def assert_same exp, act, msg = nil
159
+ msg = message(msg) {
160
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
161
+ "Expected %s (0x%x) to be the same as %s (0x%x)" % data
162
+ }
163
+ assert exp.equal?(act), msg
164
+ end
165
+
166
+ def assert_send send_ary, m = nil
167
+ recv, msg, *args = send_ary
168
+ m = message(m) {
169
+ "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
170
+ assert recv.__send__(msg, *args), m
171
+ end
172
+
173
+ def assert_throws sym, msg = nil
174
+ default = "Expected #{mu_pp(sym)} to have been thrown"
175
+ caught = true
176
+ catch(sym) do
177
+ begin
178
+ yield
179
+ rescue ArgumentError => e # 1.9 exception
180
+ default += ", not #{e.message.split(/ /).last}"
181
+ rescue NameError => e # 1.8 exception
182
+ default += ", not #{e.name.inspect}"
183
+ end
184
+ caught = false
185
+ end
186
+
187
+ assert caught, message(msg) { default }
188
+ end
189
+
190
+ def capture_io
191
+ require 'stringio'
192
+
193
+ orig_stdout, orig_stderr = $stdout, $stderr
194
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
195
+ $stdout, $stderr = captured_stdout, captured_stderr
196
+
197
+ yield
198
+
199
+ return captured_stdout.string, captured_stderr.string
200
+ ensure
201
+ $stdout = orig_stdout
202
+ $stderr = orig_stderr
203
+ end
204
+
205
+ def exception_details e, msg
206
+ "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
207
+ end
208
+
209
+ def flunk msg = nil
210
+ msg ||= "Epic Fail!"
211
+ assert false, msg
212
+ end
213
+
214
+ def message msg = nil, &default
215
+ proc {
216
+ if msg then
217
+ msg = msg.to_s unless String === msg
218
+ msg += '.' unless msg.empty?
219
+ msg += "\n#{default.call}."
220
+ msg.strip
221
+ else
222
+ "#{default.call}."
223
+ end
224
+ }
225
+ end
226
+
227
+ # used for counting assertions
228
+ def pass msg = nil
229
+ assert true
230
+ end
231
+
232
+ def refute test, msg = nil
233
+ msg ||= "Failed refutation, no message given"
234
+ not assert(! test, msg)
235
+ end
236
+
237
+ def refute_empty obj, msg = nil
238
+ msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
239
+ assert_respond_to obj, :empty?
240
+ refute obj.empty?, msg
241
+ end
242
+
243
+ def refute_equal exp, act, msg = nil
244
+ msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
245
+ refute exp == act, msg
246
+ end
247
+
248
+ def refute_in_delta exp, act, delta = 0.001, msg = nil
249
+ n = (exp - act).abs
250
+ msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
251
+ refute delta > n, msg
252
+ end
253
+
254
+ def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
255
+ refute_in_delta a, b, a * epsilon, msg
256
+ end
257
+
258
+ def refute_includes collection, obj, msg = nil
259
+ msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
260
+ flip = collection.is_a?(String) || (obj.respond_to? :include?) && ! (collection.respond_to? :include?) # HACK for specs
261
+ obj, collection = collection, obj if flip
262
+ assert_respond_to collection, :include?
263
+ refute collection.include?(obj), msg
264
+ end
265
+
266
+ def refute_instance_of cls, obj, msg = nil
267
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
268
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
269
+ obj, cls = cls, obj if flip
270
+ refute obj.instance_of?(cls), msg
271
+ end
272
+
273
+ def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
274
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
275
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
276
+ obj, cls = cls, obj if flip
277
+ refute obj.kind_of?(cls), msg
278
+ end
279
+
280
+ def refute_match exp, act, msg = nil
281
+ msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" }
282
+ assert_respond_to act, :"=~"
283
+ exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
284
+ refute exp =~ act, msg
285
+ end
286
+
287
+ def refute_nil obj, msg = nil
288
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
289
+ refute obj.nil?, msg
290
+ end
291
+
292
+ def refute_operator o1, op, o2, msg = nil
293
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
294
+ refute o1.__send__(op, o2), msg
295
+ end
296
+
297
+ def refute_respond_to obj, meth, msg = nil
298
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
299
+ flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
300
+ obj, meth = meth, obj if flip
301
+ refute obj.respond_to?(meth), msg
302
+ end
303
+
304
+ def refute_same exp, act, msg = nil
305
+ msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
306
+ refute exp.equal?(act), msg
307
+ end
308
+
309
+ def skip msg = nil, bt = caller
310
+ msg ||= "Skipped, no message given"
311
+ raise MiniTest::Skip, msg, bt
312
+ end
313
+ end
314
+
315
+ class Unit
316
+ VERSION = "1.4.2"
317
+
318
+ attr_accessor :report, :failures, :errors, :skips
319
+ attr_accessor :test_count, :assertion_count
320
+ attr_accessor :start_time
321
+
322
+ @@installed_at_exit ||= false
323
+ @@out = $stdout
324
+
325
+ def self.autorun
326
+ at_exit {
327
+ next if $! # don't run if there was an exception
328
+ exit_code = MiniTest::Unit.new.run(ARGV)
329
+ exit false if exit_code && exit_code != 0
330
+ } unless @@installed_at_exit
331
+ @@installed_at_exit = true
332
+ end
333
+
334
+ def self.output= stream
335
+ @@out = stream
336
+ end
337
+
338
+ def location e
339
+ last_before_assertion = ""
340
+ e.backtrace.reverse_each do |s|
341
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
342
+ last_before_assertion = s
343
+ end
344
+ last_before_assertion.sub(/:in .*$/, '')
345
+ end
346
+
347
+ def puke klass, meth, e
348
+ e = case e
349
+ when MiniTest::Skip then
350
+ @skips += 1
351
+ "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
352
+ when MiniTest::Assertion then
353
+ @failures += 1
354
+ "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
355
+ else
356
+ @errors += 1
357
+ bt = MiniTest::filter_backtrace(e.backtrace).join("\n ")
358
+ "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
359
+ end
360
+ @report << e
361
+ e[0, 1]
362
+ end
363
+
364
+ def initialize
365
+ @report = []
366
+ @errors = @failures = @skips = 0
367
+ @verbose = false
368
+ end
369
+
370
+ ##
371
+ # Top level driver, controls all output and filtering.
372
+
373
+ def run args = []
374
+ @verbose = args.delete('-v')
375
+
376
+ filter = if args.first =~ /^(-n|--name)$/ then
377
+ args.shift
378
+ arg = args.shift
379
+ arg =~ /\/(.*)\// ? Regexp.new($1) : arg
380
+ else
381
+ /./ # anything - ^test_ already filtered by #tests
382
+ end
383
+
384
+ @@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
385
+
386
+ start = Time.now
387
+ run_test_suites filter
388
+
389
+ @@out.puts
390
+ @@out.puts "Finished in #{'%.6f' % (Time.now - start)} seconds."
391
+
392
+ @report.each_with_index do |msg, i|
393
+ @@out.puts "\n%3d) %s" % [i + 1, msg]
394
+ end
395
+
396
+ @@out.puts
397
+
398
+ status
399
+
400
+ return failures + errors if @test_count > 0 # or return nil...
401
+ rescue Interrupt
402
+ abort 'Interrupted'
403
+ end
404
+
405
+ def status io = @@out
406
+ format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
407
+ io.puts format % [test_count, assertion_count, failures, errors, skips]
408
+ end
409
+
410
+ def run_test_suites filter = /./
411
+ @test_count, @assertion_count = 0, 0
412
+ old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
413
+ TestCase.test_suites.each do |suite|
414
+ suite.test_methods.grep(filter).each do |test|
415
+ inst = suite.new test
416
+ inst._assertions = 0
417
+ @@out.print "#{suite}##{test}: " if @verbose
418
+
419
+ @start_time = Time.now
420
+ result = inst.run(self)
421
+
422
+ @@out.print "%.2f s: " % (Time.now - @start_time) if @verbose
423
+ @@out.print result
424
+ @@out.puts if @verbose
425
+ @test_count += 1
426
+ @assertion_count += inst._assertions
427
+ end
428
+ end
429
+ @@out.sync = old_sync if @@out.respond_to? :sync=
430
+ [@test_count, @assertion_count]
431
+ end
432
+
433
+ class TestCase
434
+ attr_reader :__name__
435
+
436
+ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
437
+ SystemExit]
438
+
439
+ SUPPORTS_INFO_SIGNAL = Signal.list['INFO']
440
+
441
+ def run runner
442
+ trap 'INFO' do
443
+ warn '%s#%s %.2fs' % [self.class, self.__name__,
444
+ (Time.now - runner.start_time)]
445
+ runner.status $stderr
446
+ end if SUPPORTS_INFO_SIGNAL
447
+
448
+ result = '.'
449
+ begin
450
+ @passed = nil
451
+ self.setup
452
+ self.__send__ self.__name__
453
+ @passed = true
454
+ rescue *PASSTHROUGH_EXCEPTIONS
455
+ raise
456
+ rescue Exception => e
457
+ @passed = false
458
+ result = runner.puke(self.class, self.__name__, e)
459
+ ensure
460
+ begin
461
+ self.teardown
462
+ rescue *PASSTHROUGH_EXCEPTIONS
463
+ raise
464
+ rescue Exception => e
465
+ result = runner.puke(self.class, self.__name__, e)
466
+ end
467
+ trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL
468
+ end
469
+ result
470
+ end
471
+
472
+ def initialize name
473
+ @__name__ = name
474
+ @passed = nil
475
+ end
476
+
477
+ def self.reset
478
+ @@test_suites = {}
479
+ end
480
+
481
+ reset
482
+
483
+ def self.inherited klass
484
+ @@test_suites[klass] = true
485
+ end
486
+
487
+ def self.test_order
488
+ :random
489
+ end
490
+
491
+ def self.test_suites
492
+ @@test_suites.keys.sort_by { |ts| ts.name }
493
+ end
494
+
495
+ def self.test_methods
496
+ methods = public_instance_methods(true).grep(/^test/).map { |m|
497
+ m.to_s
498
+ }.sort
499
+
500
+ if self.test_order == :random then
501
+ max = methods.size
502
+ methods = methods.sort_by { rand(max) }
503
+ end
504
+
505
+ methods
506
+ end
507
+
508
+ def setup; end
509
+ def teardown; end
510
+
511
+ def passed?
512
+ @passed
513
+ end
514
+
515
+ include MiniTest::Assertions
516
+ end # class TestCase
517
+ end # class Test
518
+ end # module Mini
519
+
520
+ if $DEBUG then
521
+ # this helps me ferret out porting issues
522
+ module Test; end
523
+ module Test::Unit; end
524
+ class Test::Unit::TestCase
525
+ def self.inherited x
526
+ raise "You're running minitest and test/unit in the same process: #{x}"
527
+ end
528
+ end
529
+ end
530
+