minitest-spec-rails-tu-shim 1.9.3

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/COPYING.txt ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
data/LICENSE.txt ADDED
@@ -0,0 +1,3 @@
1
+ * Please read COPYING.txt
2
+ * Redistribution of lib/test source directory from Ruby 1.9.3p392.
3
+ https://github.com/ruby/ruby/tree/v1_9_3_392/lib/test
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # minitest-spec-rails-tu-shim
2
+
3
+ Test::Unit compatability for MiniTest For Ruby 1.8 for use with [minitest-spec-rails](https://github.com/metaskills/minitest-spec-rails).
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile if you
9
+
10
+ gem 'minitest-spec-rails-tu-shim'
11
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/test/unit.rb ADDED
@@ -0,0 +1,640 @@
1
+ # test/unit compatibility layer using minitest.
2
+
3
+ require 'minitest/unit'
4
+ require 'test/unit/assertions'
5
+ require 'test/unit/testcase'
6
+ require 'optparse'
7
+
8
+ module Test
9
+ module Unit
10
+ TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest'
11
+
12
+ module RunCount
13
+ @@run_count = 0
14
+
15
+ def self.have_run?
16
+ @@run_count.nonzero?
17
+ end
18
+
19
+ def run(*)
20
+ @@run_count += 1
21
+ super
22
+ end
23
+
24
+ def run_once
25
+ return if have_run?
26
+ return if $! # don't run if there was an exception
27
+ yield
28
+ end
29
+ module_function :run_once
30
+ end
31
+
32
+ module Options
33
+ def initialize(*, &block)
34
+ @init_hook = block
35
+ @options = nil
36
+ super(&nil)
37
+ end
38
+
39
+ def option_parser
40
+ @option_parser ||= OptionParser.new
41
+ end
42
+
43
+ def process_args(args = [])
44
+ return @options if @options
45
+ orig_args = args.dup
46
+ options = {}
47
+ opts = option_parser
48
+ setup_options(opts, options)
49
+ opts.parse!(args)
50
+ orig_args -= args
51
+ args = @init_hook.call(args, options) if @init_hook
52
+ non_options(args, options)
53
+ @help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " "
54
+ @options = options
55
+ if @options[:parallel]
56
+ @files = args
57
+ @args = orig_args
58
+ end
59
+ options
60
+ end
61
+
62
+ private
63
+ def setup_options(opts, options)
64
+ opts.separator 'minitest options:'
65
+ opts.version = MiniTest::Unit::VERSION
66
+
67
+ opts.on '-h', '--help', 'Display this help.' do
68
+ puts opts
69
+ exit
70
+ end
71
+
72
+ opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
73
+ options[:seed] = m
74
+ end
75
+
76
+ opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
77
+ options[:verbose] = true
78
+ self.verbose = options[:verbose]
79
+ end
80
+
81
+ opts.on '-n', '--name PATTERN', "Filter test names on pattern." do |a|
82
+ options[:filter] = a
83
+ end
84
+
85
+ opts.on '--jobs-status [TYPE]', [:normal, :replace],
86
+ "Show status of jobs every file; Disabled when --jobs isn't specified." do |type|
87
+ options[:job_status] = type || :normal
88
+ end
89
+
90
+ opts.on '-j N', '--jobs N', "Allow run tests with N jobs at once" do |a|
91
+ if /^t/ =~ a
92
+ options[:testing] = true # For testing
93
+ options[:parallel] = a[1..-1].to_i
94
+ else
95
+ options[:parallel] = a.to_i
96
+ end
97
+ end
98
+
99
+ opts.on '--no-retry', "Don't retry running testcase when --jobs specified" do
100
+ options[:no_retry] = true
101
+ end
102
+
103
+ opts.on '--ruby VAL', "Path to ruby; It'll have used at -j option" do |a|
104
+ options[:ruby] = a.split(/ /).reject(&:empty?)
105
+ end
106
+
107
+ opts.on '-q', '--hide-skip', 'Hide skipped tests' do
108
+ options[:hide_skip] = true
109
+ end
110
+ end
111
+
112
+ def non_options(files, options)
113
+ begin
114
+ require "rbconfig"
115
+ rescue LoadError
116
+ warn "#{caller(1)[0]}: warning: Parallel running disabled because can't get path to ruby; run specify with --ruby argument"
117
+ options[:parallel] = nil
118
+ else
119
+ options[:ruby] ||= RbConfig.ruby
120
+ end
121
+
122
+ true
123
+ end
124
+ end
125
+
126
+ module GlobOption
127
+ include Options
128
+
129
+ @@testfile_prefix = "test"
130
+
131
+ def setup_options(parser, options)
132
+ super
133
+ parser.on '-b', '--basedir=DIR', 'Base directory of test suites.' do |dir|
134
+ options[:base_directory] = dir
135
+ end
136
+ parser.on '-x', '--exclude PATTERN', 'Exclude test files on pattern.' do |pattern|
137
+ (options[:reject] ||= []) << pattern
138
+ end
139
+ end
140
+
141
+ def non_options(files, options)
142
+ paths = [options.delete(:base_directory), nil].uniq
143
+ if reject = options.delete(:reject)
144
+ reject_pat = Regexp.union(reject.map {|r| /#{r}/ })
145
+ end
146
+ files.map! {|f|
147
+ f = f.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
148
+ ((paths if /\A\.\.?(?:\z|\/)/ !~ f) || [nil]).any? do |prefix|
149
+ if prefix
150
+ path = f.empty? ? prefix : "#{prefix}/#{f}"
151
+ else
152
+ next if f.empty?
153
+ path = f
154
+ end
155
+ if !(match = Dir["#{path}/**/#{@@testfile_prefix}_*.rb"]).empty?
156
+ if reject
157
+ match.reject! {|n|
158
+ n[(prefix.length+1)..-1] if prefix
159
+ reject_pat =~ n
160
+ }
161
+ end
162
+ break match
163
+ elsif !reject or reject_pat !~ f and File.exist? path
164
+ break path
165
+ end
166
+ end or
167
+ raise ArgumentError, "file not found: #{f}"
168
+ }
169
+ files.flatten!
170
+ super(files, options)
171
+ end
172
+ end
173
+
174
+ module LoadPathOption
175
+ include Options
176
+
177
+ def setup_options(parser, options)
178
+ super
179
+ parser.on '-Idirectory', 'Add library load path' do |dirs|
180
+ dirs.split(':').each { |d| $LOAD_PATH.unshift d }
181
+ end
182
+ end
183
+ end
184
+
185
+ module GCStressOption
186
+ def setup_options(parser, options)
187
+ super
188
+ parser.on '--[no-]gc-stress', 'Set GC.stress as true' do |flag|
189
+ options[:gc_stress] = flag
190
+ end
191
+ end
192
+
193
+ def non_options(files, options)
194
+ if options.delete(:gc_stress)
195
+ MiniTest::Unit::TestCase.class_eval do
196
+ oldrun = instance_method(:run)
197
+ define_method(:run) do |runner|
198
+ begin
199
+ gc_stress, GC.stress = GC.stress, true
200
+ oldrun.bind(self).call(runner)
201
+ ensure
202
+ GC.stress = gc_stress
203
+ end
204
+ end
205
+ end
206
+ end
207
+ super
208
+ end
209
+ end
210
+
211
+ module RequireFiles
212
+ def non_options(files, options)
213
+ return false if !super
214
+ result = false
215
+ files.each {|f|
216
+ d = File.dirname(path = File.expand_path(f))
217
+ unless $:.include? d
218
+ $: << d
219
+ end
220
+ begin
221
+ require path unless options[:parallel]
222
+ result = true
223
+ rescue LoadError
224
+ puts "#{f}: #{$!}"
225
+ end
226
+ }
227
+ result
228
+ end
229
+ end
230
+
231
+ class Runner < MiniTest::Unit
232
+ include Test::Unit::Options
233
+ include Test::Unit::GlobOption
234
+ include Test::Unit::LoadPathOption
235
+ include Test::Unit::GCStressOption
236
+ include Test::Unit::RunCount
237
+
238
+ class Worker
239
+ def self.launch(ruby,args=[])
240
+ io = IO.popen([*ruby,
241
+ "#{File.dirname(__FILE__)}/unit/parallel.rb",
242
+ *args], "rb+")
243
+ new(io, io.pid, :waiting)
244
+ end
245
+
246
+ def initialize(io, pid, status)
247
+ @io = io
248
+ @pid = pid
249
+ @status = status
250
+ @file = nil
251
+ @real_file = nil
252
+ @loadpath = []
253
+ @hooks = {}
254
+ end
255
+
256
+ def puts(*args)
257
+ @io.puts(*args)
258
+ end
259
+
260
+ def run(task,type)
261
+ @file = File.basename(task).gsub(/\.rb/,"")
262
+ @real_file = task
263
+ begin
264
+ puts "loadpath #{[Marshal.dump($:-@loadpath)].pack("m").gsub("\n","")}"
265
+ @loadpath = $:.dup
266
+ puts "run #{task} #{type}"
267
+ @status = :prepare
268
+ rescue Errno::EPIPE
269
+ died
270
+ rescue IOError
271
+ raise unless ["stream closed","closed stream"].include? $!.message
272
+ died
273
+ end
274
+ end
275
+
276
+ def hook(id,&block)
277
+ @hooks[id] ||= []
278
+ @hooks[id] << block
279
+ self
280
+ end
281
+
282
+ def read
283
+ res = (@status == :quit) ? @io.read : @io.gets
284
+ res && res.chomp
285
+ end
286
+
287
+ def close
288
+ @io.close
289
+ self
290
+ end
291
+
292
+ def died(*additional)
293
+ @status = :quit
294
+ @io.close
295
+
296
+ call_hook(:dead,*additional)
297
+ end
298
+
299
+ def to_s
300
+ if @file
301
+ "#{@pid}=#{@file}"
302
+ else
303
+ "#{@pid}:#{@status.to_s.ljust(7)}"
304
+ end
305
+ end
306
+
307
+ attr_reader :io, :pid
308
+ attr_accessor :status, :file, :real_file, :loadpath
309
+
310
+ private
311
+
312
+ def call_hook(id,*additional)
313
+ @hooks[id] ||= []
314
+ @hooks[id].each{|hook| hook[self,additional] }
315
+ self
316
+ end
317
+
318
+ end
319
+
320
+ class << self; undef autorun; end
321
+
322
+ @@stop_auto_run = false
323
+ def self.autorun
324
+ at_exit {
325
+ Test::Unit::RunCount.run_once {
326
+ exit(Test::Unit::Runner.new.run(ARGV) || true)
327
+ } unless @@stop_auto_run
328
+ } unless @@installed_at_exit
329
+ @@installed_at_exit = true
330
+ end
331
+
332
+ def after_worker_down(worker, e=nil, c=false)
333
+ return unless @options[:parallel]
334
+ return if @interrupt
335
+ if e
336
+ b = e.backtrace
337
+ warn "#{b.shift}: #{e.message} (#{e.class})"
338
+ STDERR.print b.map{|s| "\tfrom #{s}"}.join("\n")
339
+ end
340
+ @need_quit = true
341
+ warn ""
342
+ warn "Some worker was crashed. It seems ruby interpreter's bug"
343
+ warn "or, a bug of test/unit/parallel.rb. try again without -j"
344
+ warn "option."
345
+ warn ""
346
+ STDERR.flush
347
+ exit c
348
+ end
349
+
350
+ def jobs_status
351
+ return unless @options[:job_status]
352
+ puts "" unless @options[:verbose]
353
+ status_line = @workers.map(&:to_s).join(" ")
354
+ if @options[:job_status] == :replace and $stdout.tty?
355
+ @terminal_width ||=
356
+ begin
357
+ require 'io/console'
358
+ $stdout.winsize[1]
359
+ rescue LoadError, NoMethodError
360
+ ENV["COLUMNS"].to_i.nonzero? || 80
361
+ end
362
+ @jstr_size ||= 0
363
+ del_jobs_status
364
+ $stdout.flush
365
+ print status_line[0...@terminal_width]
366
+ $stdout.flush
367
+ @jstr_size = [status_line.size, @terminal_width].min
368
+ else
369
+ puts status_line
370
+ end
371
+ end
372
+
373
+ def del_jobs_status
374
+ return unless @options[:job_status] == :replace && @jstr_size.nonzero?
375
+ print "\r"+" "*@jstr_size+"\r"
376
+ end
377
+
378
+ def after_worker_quit(worker)
379
+ return unless @options[:parallel]
380
+ return if @interrupt
381
+ @workers.delete(worker)
382
+ @dead_workers << worker
383
+ @ios = @workers.map(&:io)
384
+ end
385
+
386
+ def _run_parallel suites, type, result
387
+ if @options[:parallel] < 1
388
+ warn "Error: parameter of -j option should be greater than 0."
389
+ return
390
+ end
391
+
392
+ begin
393
+ # Require needed things for parallel running
394
+ require 'thread'
395
+ require 'timeout'
396
+ @tasks = @files.dup # Array of filenames.
397
+ @need_quit = false
398
+ @dead_workers = [] # Array of dead workers.
399
+ @warnings = []
400
+ shutting_down = false
401
+ rep = [] # FIXME: more good naming
402
+
403
+ # Array of workers.
404
+ @workers = @options[:parallel].times.map {
405
+ worker = Worker.launch(@options[:ruby],@args)
406
+ worker.hook(:dead) do |w,info|
407
+ after_worker_quit w
408
+ after_worker_down w, *info unless info.empty?
409
+ end
410
+ worker
411
+ }
412
+
413
+ # Thread: watchdog
414
+ watchdog = Thread.new do
415
+ while stat = Process.wait2
416
+ break if @interrupt # Break when interrupt
417
+ pid, stat = stat
418
+ w = (@workers + @dead_workers).find{|x| pid == x.pid }.dup
419
+ next unless w
420
+ unless w.status == :quit
421
+ # Worker down
422
+ w.died(nil, !stat.signaled? && stat.exitstatus)
423
+ end
424
+ end
425
+ end
426
+
427
+ @workers_hash = Hash[@workers.map {|w| [w.io,w] }] # out-IO => worker
428
+ @ios = @workers.map{|w| w.io } # Array of worker IOs
429
+
430
+ while _io = IO.select(@ios)[0]
431
+ break unless _io.each do |io|
432
+ break if @need_quit
433
+ worker = @workers_hash[io]
434
+ case worker.read
435
+ when /^okay$/
436
+ worker.status = :running
437
+ jobs_status
438
+ when /^ready$/
439
+ worker.status = :ready
440
+ if @tasks.empty?
441
+ break unless @workers.find{|x| x.status == :running }
442
+ else
443
+ worker.run(@tasks.shift, type)
444
+ end
445
+
446
+ jobs_status
447
+ when /^done (.+?)$/
448
+ r = Marshal.load($1.unpack("m")[0])
449
+ result << r[0..1] unless r[0..1] == [nil,nil]
450
+ rep << {file: worker.real_file,
451
+ report: r[2], result: r[3], testcase: r[5]}
452
+ $:.push(*r[4]).uniq!
453
+ when /^p (.+?)$/
454
+ del_jobs_status
455
+ print $1.unpack("m")[0]
456
+ jobs_status if @options[:job_status] == :replace
457
+ when /^after (.+?)$/
458
+ @warnings << Marshal.load($1.unpack("m")[0])
459
+ when /^bye (.+?)$/
460
+ after_worker_down worker, Marshal.load($1.unpack("m")[0])
461
+ when /^bye$/
462
+ if shutting_down
463
+ after_worker_quit worker
464
+ else
465
+ after_worker_down worker
466
+ end
467
+ end
468
+ break if @need_quit
469
+ end
470
+ end
471
+ rescue Interrupt => e
472
+ @interrupt = e
473
+ return result
474
+ ensure
475
+ shutting_down = true
476
+
477
+ watchdog.kill if watchdog
478
+ if @interrupt
479
+ @ios.select!{|x| @workers_hash[x].status == :running }
480
+ while !@ios.empty? && (__io = IO.select(@ios,[],[],10))
481
+ _io = __io[0]
482
+ _io.each do |io|
483
+ worker = @workers_hash[io]
484
+ case worker.read
485
+ when /^done (.+?)$/
486
+ r = Marshal.load($1.unpack("m")[0])
487
+ result << r[0..1] unless r[0..1] == [nil,nil]
488
+ rep << {file: worker.real_file,
489
+ report: r[2], result: r[3], testcase: r[5]}
490
+ $:.push(*r[4]).uniq!
491
+ @ios.delete(io)
492
+ end
493
+ end
494
+ end
495
+ end
496
+ @workers.each do |worker|
497
+ begin
498
+ timeout(1) do
499
+ worker.puts "quit"
500
+ end
501
+ rescue Errno::EPIPE
502
+ rescue Timeout::Error
503
+ end
504
+ worker.close
505
+ end
506
+ begin
507
+ timeout(0.2*@workers.size) do
508
+ Process.waitall
509
+ end
510
+ rescue Timeout::Error
511
+ @workers.each do |worker|
512
+ begin
513
+ Process.kill(:KILL,worker.pid)
514
+ rescue Errno::ESRCH; end
515
+ end
516
+ end
517
+
518
+ if @interrupt || @options[:no_retry] || @need_quit
519
+ rep.each do |r|
520
+ report.push(*r[:report])
521
+ end
522
+ @errors += rep.map{|x| x[:result][0] }.inject(:+)
523
+ @failures += rep.map{|x| x[:result][1] }.inject(:+)
524
+ @skips += rep.map{|x| x[:result][2] }.inject(:+)
525
+ else
526
+ puts ""
527
+ puts "Retrying..."
528
+ puts ""
529
+ rep.each do |r|
530
+ if r[:testcase] && r[:file] && !r[:report].empty?
531
+ require r[:file]
532
+ _run_suite(eval(r[:testcase]),type)
533
+ else
534
+ report.push(*r[:report])
535
+ @errors += r[:result][0]
536
+ @failures += r[:result][1]
537
+ @skips += r[:result][2]
538
+ end
539
+ end
540
+ end
541
+ if @warnings
542
+ warn ""
543
+ ary = []
544
+ @warnings.reject! do |w|
545
+ r = ary.include?(w[1].message)
546
+ ary << w[1].message
547
+ r
548
+ end
549
+ @warnings.each do |w|
550
+ warn "#{w[0]}: #{w[1].message} (#{w[1].class})"
551
+ end
552
+ warn ""
553
+ end
554
+ end
555
+ end
556
+
557
+ def _run_suites suites, type
558
+ @interrupt = nil
559
+ result = []
560
+ if @options[:parallel]
561
+ _run_parallel suites, type, result
562
+ else
563
+ suites.each {|suite|
564
+ begin
565
+ result << _run_suite(suite, type)
566
+ rescue Interrupt => e
567
+ @interrupt = e
568
+ break
569
+ end
570
+ }
571
+ end
572
+ report.reject!{|r| r.start_with? "Skipped:" } if @options[:hide_skip]
573
+ result
574
+ end
575
+
576
+ # Overriding of MiniTest::Unit#puke
577
+ def puke klass, meth, e
578
+ # TODO:
579
+ # this overriding is for minitest feature that skip messages are
580
+ # hidden when not verbose (-v), note this is temporally.
581
+ e = case e
582
+ when MiniTest::Skip then
583
+ @skips += 1
584
+ "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
585
+ when MiniTest::Assertion then
586
+ @failures += 1
587
+ "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
588
+ else
589
+ @errors += 1
590
+ bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
591
+ "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
592
+ end
593
+ @report << e
594
+ e[0, 1]
595
+ end
596
+
597
+ def status(*args)
598
+ result = super
599
+ raise @interrupt if @interrupt
600
+ result
601
+ end
602
+ end
603
+
604
+ class AutoRunner
605
+ class Runner < Test::Unit::Runner
606
+ include Test::Unit::RequireFiles
607
+ end
608
+
609
+ attr_accessor :to_run, :options
610
+
611
+ def initialize(force_standalone = false, default_dir = nil, argv = ARGV)
612
+ @runner = Runner.new do |files, options|
613
+ options[:base_directory] ||= default_dir
614
+ files << default_dir if files.empty? and default_dir
615
+ @to_run = files
616
+ yield self if block_given?
617
+ files
618
+ end
619
+ Runner.runner = @runner
620
+ @options = @runner.option_parser
621
+ @argv = argv
622
+ end
623
+
624
+ def process_args(*args)
625
+ @runner.process_args(*args)
626
+ !@to_run.empty?
627
+ end
628
+
629
+ def run
630
+ @runner.run(@argv) || true
631
+ end
632
+
633
+ def self.run(*args)
634
+ new(*args).run
635
+ end
636
+ end
637
+ end
638
+ end
639
+
640
+ Test::Unit::Runner.autorun
@@ -0,0 +1,324 @@
1
+ require 'minitest/unit'
2
+ require 'pp'
3
+
4
+ module Test
5
+ module Unit
6
+ module Assertions
7
+ include MiniTest::Assertions
8
+
9
+ def mu_pp(obj) #:nodoc:
10
+ obj.pretty_inspect.chomp
11
+ end
12
+
13
+ MINI_DIR = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), "minitest") #:nodoc:
14
+
15
+ UNASSIGNED = Object.new # :nodoc:
16
+
17
+ # :call-seq:
18
+ # assert( test, failure_message = UNASSIGNED )
19
+ #
20
+ #Tests if +test+ is true.
21
+ #
22
+ #+msg+ may be a String or a Proc. If +msg+ is a String, it will be used
23
+ #as the failure message. Otherwise, the result of calling +msg+ will be
24
+ #used as the message if the assertion fails.
25
+ #
26
+ #If no +msg+ is given, a default message will be used.
27
+ #
28
+ # assert(false, "This was expected to be true")
29
+ def assert(test, msg = UNASSIGNED)
30
+ case msg
31
+ when UNASSIGNED
32
+ msg = nil
33
+ when String, Proc
34
+ else
35
+ bt = caller.reject { |s| s.rindex(MINI_DIR, 0) }
36
+ raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt
37
+ end
38
+ super
39
+ end
40
+
41
+ # :call-seq:
42
+ # assert_block( failure_message = nil )
43
+ #
44
+ #Tests the result of the given block. If the block does not return true,
45
+ #the assertion will fail. The optional +failure_message+ argument is the same as in
46
+ #Assertions#assert.
47
+ #
48
+ # assert_block do
49
+ # [1, 2, 3].any? { |num| num < 1 }
50
+ # end
51
+ def assert_block(*msgs)
52
+ assert yield, *msgs
53
+ end
54
+
55
+ # :call-seq:
56
+ # assert_raise( *args, &block )
57
+ #
58
+ #Tests if the given block raises an exception. Acceptable exception
59
+ #types maye be given as optional arguments. If the last argument is a
60
+ #String, it will be used as the error message.
61
+ #
62
+ # assert_raise do #Fails, no Exceptions are raised
63
+ # end
64
+ #
65
+ # assert_raise NameError do
66
+ # puts x #Raises NameError, so assertion succeeds
67
+ # end
68
+ def assert_raise(*args, &b)
69
+ assert_raises(*args, &b)
70
+ end
71
+
72
+ # :call-seq:
73
+ # assert_nothing_raised( *args, &block )
74
+ #
75
+ #If any exceptions are given as arguments, the assertion will
76
+ #fail if one of those exceptions are raised. Otherwise, the test fails
77
+ #if any exceptions are raised.
78
+ #
79
+ #The final argument may be a failure message.
80
+ #
81
+ # assert_nothing_raised RuntimeError do
82
+ # raise Exception #Assertion passes, Exception is not a RuntimeError
83
+ # end
84
+ #
85
+ # assert_nothing_raised do
86
+ # raise Exception #Assertion fails
87
+ # end
88
+ def assert_nothing_raised(*args)
89
+ self._assertions += 1
90
+ if Module === args.last
91
+ msg = nil
92
+ else
93
+ msg = args.pop
94
+ end
95
+ begin
96
+ line = __LINE__; yield
97
+ rescue MiniTest::Skip
98
+ raise
99
+ rescue Exception => e
100
+ bt = e.backtrace
101
+ as = e.instance_of?(MiniTest::Assertion)
102
+ if as
103
+ ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
104
+ bt.reject! {|ln| ans =~ ln}
105
+ end
106
+ if ((args.empty? && !as) ||
107
+ args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
108
+ msg = message(msg) { "Exception raised:\n<#{mu_pp(e)}>" }
109
+ raise MiniTest::Assertion, msg.call, bt
110
+ else
111
+ raise
112
+ end
113
+ end
114
+ nil
115
+ end
116
+
117
+ # :call-seq:
118
+ # assert_nothing_thrown( failure_message = nil, &block )
119
+ #
120
+ #Fails if the given block uses a call to Kernel#throw.
121
+ #
122
+ #An optional failure message may be provided as the final argument.
123
+ #
124
+ # assert_nothing_thrown "Something was thrown!" do
125
+ # throw :problem?
126
+ # end
127
+ def assert_nothing_thrown(msg=nil)
128
+ begin
129
+ yield
130
+ rescue ArgumentError => error
131
+ raise error if /\Auncaught throw (.+)\z/m !~ error.message
132
+ msg = message(msg) { "<#{$1}> was thrown when nothing was expected" }
133
+ flunk(msg)
134
+ end
135
+ assert(true, "Expected nothing to be thrown")
136
+ end
137
+
138
+ # :call-seq:
139
+ # assert_equal( expected, actual, failure_message = nil )
140
+ #
141
+ #Tests if +expected+ is equal to +actual+.
142
+ #
143
+ #An optional failure message may be provided as the final argument.
144
+ def assert_equal(exp, act, msg = nil)
145
+ msg = message(msg) {
146
+ exp_str = mu_pp(exp)
147
+ act_str = mu_pp(act)
148
+ exp_comment = ''
149
+ act_comment = ''
150
+ if exp_str == act_str
151
+ if (exp.is_a?(String) && act.is_a?(String)) ||
152
+ (exp.is_a?(Regexp) && act.is_a?(Regexp))
153
+ exp_comment = " (#{exp.encoding})"
154
+ act_comment = " (#{act.encoding})"
155
+ elsif exp.is_a?(Float) && act.is_a?(Float)
156
+ exp_str = "%\#.#{Float::DIG+2}g" % exp
157
+ act_str = "%\#.#{Float::DIG+2}g" % act
158
+ elsif exp.is_a?(Time) && act.is_a?(Time)
159
+ if exp.subsec * 1000_000_000 == exp.nsec
160
+ exp_comment = " (#{exp.nsec}[ns])"
161
+ else
162
+ exp_comment = " (subsec=#{exp.subsec})"
163
+ end
164
+ if act.subsec * 1000_000_000 == act.nsec
165
+ act_comment = " (#{act.nsec}[ns])"
166
+ else
167
+ act_comment = " (subsec=#{act.subsec})"
168
+ end
169
+ elsif exp.class != act.class
170
+ # a subclass of Range, for example.
171
+ exp_comment = " (#{exp.class})"
172
+ act_comment = " (#{act.class})"
173
+ end
174
+ elsif !Encoding.compatible?(exp_str, act_str)
175
+ if exp.is_a?(String) && act.is_a?(String)
176
+ exp_str = exp.dump
177
+ act_str = act.dump
178
+ exp_comment = " (#{exp.encoding})"
179
+ act_comment = " (#{act.encoding})"
180
+ else
181
+ exp_str = exp_str.dump
182
+ act_str = act_str.dump
183
+ end
184
+ end
185
+ "<#{exp_str}>#{exp_comment} expected but was\n<#{act_str}>#{act_comment}"
186
+ }
187
+ assert(exp == act, msg)
188
+ end
189
+
190
+ # :call-seq:
191
+ # assert_not_nil( expression, failure_message = nil )
192
+ #
193
+ #Tests if +expression+ is not nil.
194
+ #
195
+ #An optional failure message may be provided as the final argument.
196
+ def assert_not_nil(exp, msg=nil)
197
+ msg = message(msg) { "<#{mu_pp(exp)}> expected to not be nil" }
198
+ assert(!exp.nil?, msg)
199
+ end
200
+
201
+ # :call-seq:
202
+ # assert_not_equal( expected, actual, failure_message = nil )
203
+ #
204
+ #Tests if +expected+ is not equal to +actual+.
205
+ #
206
+ #An optional failure message may be provided as the final argument.
207
+ def assert_not_equal(exp, act, msg=nil)
208
+ msg = message(msg) { "<#{mu_pp(exp)}> expected to be != to\n<#{mu_pp(act)}>" }
209
+ assert(exp != act, msg)
210
+ end
211
+
212
+ # :call-seq:
213
+ # assert_no_match( regexp, string, failure_message = nil )
214
+ #
215
+ #Tests if the given Regexp does not match a given String.
216
+ #
217
+ #An optional failure message may be provided as the final argument.
218
+ def assert_no_match(regexp, string, msg=nil)
219
+ assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
220
+ self._assertions -= 1
221
+ msg = message(msg) { "<#{mu_pp(regexp)}> expected to not match\n<#{mu_pp(string)}>" }
222
+ assert(regexp !~ string, msg)
223
+ end
224
+
225
+ # :call-seq:
226
+ # assert_not_same( expected, actual, failure_message = nil )
227
+ #
228
+ #Tests if +expected+ is not the same object as +actual+.
229
+ #This test uses Object#equal? to test equality.
230
+ #
231
+ #An optional failure message may be provided as the final argument.
232
+ #
233
+ # assert_not_same("x", "x") #Succeeds
234
+ def assert_not_same(expected, actual, message="")
235
+ msg = message(msg) { build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__) }
236
+ <?>
237
+ with id <?> expected to not be equal\\? to
238
+ <?>
239
+ with id <?>.
240
+ EOT
241
+ assert(!actual.equal?(expected), msg)
242
+ end
243
+
244
+ # :call-seq:
245
+ # assert_respond_to( object, method, failure_message = nil )
246
+ #
247
+ #Tests if the given Object responds to +method+.
248
+ #
249
+ #An optional failure message may be provided as the final argument.
250
+ #
251
+ # assert_respond_to("hello", :reverse) #Succeeds
252
+ # assert_respond_to("hello", :does_not_exist) #Fails
253
+ def assert_respond_to obj, meth, msg = nil
254
+ #get rid of overcounting
255
+ super if !caller[0].rindex(MINI_DIR, 0) || !obj.respond_to?(meth)
256
+ end
257
+
258
+ # :call-seq:
259
+ # assert_send( +send_array+, failure_message = nil )
260
+ #
261
+ # Passes if the method send returns a true value.
262
+ #
263
+ # +send_array+ is composed of:
264
+ # * A receiver
265
+ # * A method
266
+ # * Arguments to the method
267
+ #
268
+ # Example:
269
+ # assert_send([[1, 2], :member?, 1]) # -> pass
270
+ # assert_send([[1, 2], :member?, 4]) # -> fail
271
+ def assert_send send_ary, m = nil
272
+ recv, msg, *args = send_ary
273
+ m = message(m) {
274
+ if args.empty?
275
+ argsstr = ""
276
+ else
277
+ (argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)')
278
+ end
279
+ "Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return true"
280
+ }
281
+ assert recv.__send__(msg, *args), m
282
+ end
283
+
284
+ # :call-seq:
285
+ # assert_not_send( +send_array+, failure_message = nil )
286
+ #
287
+ # Passes if the method send doesn't return a true value.
288
+ #
289
+ # +send_array+ is composed of:
290
+ # * A receiver
291
+ # * A method
292
+ # * Arguments to the method
293
+ #
294
+ # Example:
295
+ # assert_not_send([[1, 2], :member?, 1]) # -> fail
296
+ # assert_not_send([[1, 2], :member?, 4]) # -> pass
297
+ def assert_not_send send_ary, m = nil
298
+ recv, msg, *args = send_ary
299
+ m = message(m) {
300
+ if args.empty?
301
+ argsstr = ""
302
+ else
303
+ (argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)')
304
+ end
305
+ "Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return false"
306
+ }
307
+ assert !recv.__send__(msg, *args), m
308
+ end
309
+
310
+ ms = instance_methods(true).map {|sym| sym.to_s }
311
+ ms.grep(/\Arefute_/) do |m|
312
+ mname = ('assert_not_' << m.to_s[/.*?_(.*)/, 1])
313
+ alias_method(mname, m) unless ms.include? mname
314
+ end
315
+ alias assert_include assert_includes
316
+ alias assert_not_include assert_not_includes
317
+
318
+ def build_message(head, template=nil, *arguments) #:nodoc:
319
+ template &&= template.chomp
320
+ template.gsub(/\G((?:[^\\]|\\.)*?)(\\)?\?/) { $1 + ($2 ? "?" : mu_pp(arguments.shift)) }
321
+ end
322
+ end
323
+ end
324
+ end
@@ -0,0 +1,161 @@
1
+ require 'test/unit'
2
+
3
+ module Test
4
+ module Unit
5
+ class Worker < Runner
6
+ class << self
7
+ undef autorun
8
+ end
9
+
10
+ alias orig_run_suite _run_suite
11
+ undef _run_suite
12
+ undef _run_suites
13
+ undef run
14
+
15
+ def increment_io(orig)
16
+ *rest, io = 32.times.inject([orig.dup]){|ios, | ios << ios.last.dup }
17
+ rest.each(&:close)
18
+ io
19
+ end
20
+
21
+ def _run_suites(suites, type)
22
+ suites.map do |suite|
23
+ _run_suite(suite, type)
24
+ end
25
+ end
26
+
27
+ def _run_suite(suite, type)
28
+ r = report.dup
29
+ orig_testout = MiniTest::Unit.output
30
+ i,o = IO.pipe
31
+
32
+ MiniTest::Unit.output = o
33
+ orig_stdin, orig_stdout = $stdin, $stdout
34
+
35
+ th = Thread.new do
36
+ begin
37
+ while buf = (self.verbose ? i.gets : i.read(5))
38
+ @stdout.puts "p #{[buf].pack("m").gsub("\n","")}"
39
+ end
40
+ rescue IOError
41
+ rescue Errno::EPIPE
42
+ end
43
+ end
44
+
45
+ e, f, s = @errors, @failures, @skips
46
+
47
+ begin
48
+ result = orig_run_suite(suite, type)
49
+ rescue Interrupt
50
+ @need_exit = true
51
+ result = [nil,nil]
52
+ end
53
+
54
+ MiniTest::Unit.output = orig_testout
55
+ $stdin = orig_stdin
56
+ $stdout = orig_stdout
57
+
58
+ o.close
59
+ begin
60
+ th.join
61
+ rescue IOError
62
+ raise unless ["stream closed","closed stream"].include? $!.message
63
+ end
64
+ i.close
65
+
66
+ result << (report - r)
67
+ result << [@errors-e,@failures-f,@skips-s]
68
+ result << ($: - @old_loadpath)
69
+ result << suite.name
70
+
71
+ begin
72
+ @stdout.puts "done #{[Marshal.dump(result)].pack("m").gsub("\n","")}"
73
+ rescue Errno::EPIPE; end
74
+ return result
75
+ ensure
76
+ MiniTest::Unit.output = orig_stdout
77
+ $stdin = orig_stdin
78
+ $stdout = orig_stdout
79
+ o.close if o && !o.closed?
80
+ i.close if i && !i.closed?
81
+ end
82
+
83
+ def run(args = [])
84
+ process_args args
85
+ @@stop_auto_run = true
86
+ @opts = @options.dup
87
+ @need_exit = false
88
+
89
+ @old_loadpath = []
90
+ begin
91
+ @stdout = increment_io(STDOUT)
92
+ @stdin = increment_io(STDIN)
93
+ @stdout.sync = true
94
+ @stdout.puts "ready"
95
+ while buf = @stdin.gets
96
+ case buf.chomp
97
+ when /^loadpath (.+?)$/
98
+ @old_loadpath = $:.dup
99
+ $:.push(*Marshal.load($1.unpack("m")[0].force_encoding("ASCII-8BIT"))).uniq!
100
+ when /^run (.+?) (.+?)$/
101
+ @stdout.puts "okay"
102
+
103
+ @options = @opts.dup
104
+ suites = MiniTest::Unit::TestCase.test_suites
105
+
106
+ begin
107
+ require $1
108
+ rescue LoadError
109
+ @stdout.puts "after #{[Marshal.dump([$1, $!])].pack("m").gsub("\n","")}"
110
+ @stdout.puts "ready"
111
+ next
112
+ end
113
+ _run_suites MiniTest::Unit::TestCase.test_suites-suites, $2.to_sym
114
+
115
+ if @need_exit
116
+ begin
117
+ @stdout.puts "bye"
118
+ rescue Errno::EPIPE; end
119
+ exit
120
+ else
121
+ @stdout.puts "ready"
122
+ end
123
+ when /^quit$/
124
+ begin
125
+ @stdout.puts "bye"
126
+ rescue Errno::EPIPE; end
127
+ exit
128
+ end
129
+ end
130
+ rescue Errno::EPIPE
131
+ rescue Exception => e
132
+ begin
133
+ @stdout.puts "bye #{[Marshal.dump(e)].pack("m").gsub("\n","")}"
134
+ rescue Errno::EPIPE;end
135
+ exit
136
+ ensure
137
+ @stdin.close
138
+ @stdout.close
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ if $0 == __FILE__
146
+ module Test
147
+ module Unit
148
+ class TestCase < MiniTest::Unit::TestCase
149
+ def on_parallel_worker?
150
+ true
151
+ end
152
+ end
153
+ end
154
+ end
155
+ require 'rubygems'
156
+ class Gem::TestCase < MiniTest::Unit::TestCase
157
+ @@project_dir = File.expand_path('../../../..', __FILE__)
158
+ end
159
+
160
+ Test::Unit::Worker.new.run(ARGV)
161
+ end
@@ -0,0 +1,25 @@
1
+ require 'test/unit/assertions'
2
+
3
+ module Test
4
+ module Unit
5
+ # remove silly TestCase class
6
+ remove_const(:TestCase) if defined?(self::TestCase)
7
+
8
+ class TestCase < MiniTest::Unit::TestCase
9
+ include Assertions
10
+
11
+ def on_parallel_worker?
12
+ false
13
+ end
14
+
15
+ def run runner
16
+ @options = runner.options
17
+ super runner
18
+ end
19
+
20
+ def self.test_order
21
+ :sorted
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "minitest-spec-rails-tu-shim"
3
+ spec.version = '1.9.3'
4
+ spec.authors = ["Nobuyoshi Nakada", "Shota Fukumori", "akr", "unak", "Ryan Davis", "Aaron Patterson", "Yuki Sonoda", "NARUSE, Yui", "Yusuke Endoh", "Eric Hodel", "Kenta Murata"]
5
+ spec.email = ["nobu@ruby-lang.org", "sorah@tubusu.net", "ryand-ruby@zenspider.com", "aaron.patterson@gmail.com", "ugui@yugui.jp", "drbrain@segment7.net", "mrkn+github@mrkn.jp"]
6
+ spec.description = 'Redistribution of lib/test source directory from Ruby 1.9.3p392.'
7
+ spec.summary = spec.description
8
+ spec.homepage = "https://github.com/metaskills/minitest-spec-rails-tu-shim"
9
+ spec.license = "See LICENSE.txt and COPYING.txt"
10
+ spec.files = `git ls-files`.split($/)
11
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
12
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
13
+ spec.require_paths = ["lib"]
14
+ spec.add_development_dependency "bundler", "~> 1.3"
15
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minitest-spec-rails-tu-shim
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.9.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nobuyoshi Nakada
9
+ - Shota Fukumori
10
+ - akr
11
+ - unak
12
+ - Ryan Davis
13
+ - Aaron Patterson
14
+ - Yuki Sonoda
15
+ - NARUSE, Yui
16
+ - Yusuke Endoh
17
+ - Eric Hodel
18
+ - Kenta Murata
19
+ autorequire:
20
+ bindir: bin
21
+ cert_chain: []
22
+ date: 2013-03-19 00:00:00.000000000 Z
23
+ dependencies:
24
+ - !ruby/object:Gem::Dependency
25
+ name: bundler
26
+ requirement: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ version: '1.3'
32
+ type: :development
33
+ prerelease: false
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ description: Redistribution of lib/test source directory from Ruby 1.9.3p392.
41
+ email:
42
+ - nobu@ruby-lang.org
43
+ - sorah@tubusu.net
44
+ - ryand-ruby@zenspider.com
45
+ - aaron.patterson@gmail.com
46
+ - ugui@yugui.jp
47
+ - drbrain@segment7.net
48
+ - mrkn+github@mrkn.jp
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - COPYING.txt
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/test/unit.rb
59
+ - lib/test/unit/assertions.rb
60
+ - lib/test/unit/parallel.rb
61
+ - lib/test/unit/testcase.rb
62
+ - minitest-spec-rails-tu-shim.gemspec
63
+ homepage: https://github.com/metaskills/minitest-spec-rails-tu-shim
64
+ licenses:
65
+ - See LICENSE.txt and COPYING.txt
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.8.25
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Redistribution of lib/test source directory from Ruby 1.9.3p392.
88
+ test_files: []
89
+ has_rdoc: