require 'test/unit' module Test module Unit class Worker < Runner class << self undef autorun end alias orig_run_suite _run_suite undef _run_suite undef _run_suites undef run def _run_suites suites, type suites.map do |suite| result = _run_suite(suite, type) end end def _run_suite(suite, type) r = report.dup orig_stdout = MiniTest::Unit.output i,o = IO.pipe MiniTest::Unit.output = o stdout = STDOUT.dup th = Thread.new do begin while buf = (self.verbose ? i.gets : i.read(5)) stdout.puts "p #{[buf].pack("m").gsub("\n","")}" end rescue IOError rescue Errno::EPIPE end end e, f, s = @errors, @failures, @skips result = orig_run_suite(suite, type) MiniTest::Unit.output = orig_stdout o.close begin th.join rescue IOError raise unless ["stream closed","closed stream"].include? $!.message end i.close result << (report - r) result << [@errors-e,@failures-f,@skips-s] result << ($: - @old_loadpath) result << suite.name begin STDOUT.puts "done #{[Marshal.dump(result)].pack("m").gsub("\n","")}" rescue Errno::EPIPE; end return result ensure MiniTest::Unit.output = orig_stdout o.close if o && !o.closed? i.close if i && !i.closed? end def run(args = []) process_args args @@stop_auto_run = true @opts = @options.dup Signal.trap(:INT,"IGNORE") @old_loadpath = [] begin STDOUT.sync = true STDOUT.puts "ready" stdin = STDIN.dup stdout = STDOUT.dup while buf = stdin.gets case buf.chomp when /^loadpath (.+?)$/ @old_loadpath = $:.dup $:.push(*Marshal.load($1.unpack("m")[0].force_encoding("ASCII-8BIT"))).uniq! when /^run (.+?) (.+?)$/ STDOUT.puts "okay" th = Thread.new do while puf = stdin.gets if puf.chomp == "quit" begin stdout.puts "bye" rescue Errno::EPIPE; end exit end end end @options = @opts.dup suites = MiniTest::Unit::TestCase.test_suites begin require $1 rescue LoadError th.kill STDOUT.puts "after #{[Marshal.dump([$1, $!])].pack("m").gsub("\n","")}" STDOUT.puts "ready" next end _run_suites MiniTest::Unit::TestCase.test_suites-suites, $2.to_sym STDIN.reopen(stdin) STDOUT.reopen(stdout) th.kill STDOUT.puts "ready" when /^quit$/ begin STDOUT.puts "bye" rescue Errno::EPIPE; end exit end end rescue Errno::EPIPE rescue Exception => e begin STDOUT.puts "bye #{[Marshal.dump(e)].pack("m").gsub("\n","")}" rescue Errno::EPIPE;end exit ensure stdin.close end end end end end Test::Unit::Worker.new.run(ARGV)