In Files

  • test/unit.rb

Test::Unit::Runner

Public Class Methods

autorun() click to toggle source
 
               # File test/unit.rb, line 363
def self.autorun
  at_exit {
    Test::Unit::RunCount.run_once {
      exit(Test::Unit::Runner.new.run(ARGV) || true)
    } unless @@stop_auto_run
  } unless @@installed_at_exit
  @@installed_at_exit = true
end
            

Public Instance Methods

_prepare_run(suites, type) click to toggle source
 
               # File test/unit.rb, line 676
def _prepare_run(suites, type)
  options[:job_status] ||= :replace if @tty && !@verbose
  case options[:color]
  when :always
    color = true
  when :auto, nil
    color = @options[:job_status] == :replace && /dumb/ !~ ENV["TERM"]
  else
    color = false
  end
  if color
    # dircolors-like style
    colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:]*)/)] : {}
    @passed_color = "\e[#{colors["pass"] || "32"}m"
    @failed_color = "\e[#{colors["fail"] || "31"}m"
    @skipped_color = "\e[#{colors["skip"] || "33"}m"
    @reset_color = "\e[m"
  else
    @passed_color = @failed_color = @skipped_color = @reset_color = ""
  end
  if color or @options[:job_status] == :replace
    @verbose = !options[:parallel]
    @output = StatusLineOutput.new(self)
  end
  if /\A\/(.*)\/\z/ =~ (filter = options[:filter])
    filter = Regexp.new($1)
  end
  type = "#{type}_methods"
  total = if filter
            suites.inject(0) {|n, suite| n + suite.send(type).grep(filter).size}
          else
            suites.inject(0) {|n, suite| n + suite.send(type).size}
          end
  @test_count = 0
  @total_tests = total.to_s(10)
end
            
_print(s) click to toggle source
 
               # File test/unit.rb, line 723
def _print(s); $stdout.print(s); end
            
_run_parallel(suites, type, result) click to toggle source
 
               # File test/unit.rb, line 564
def _run_parallel suites, type, result
  if @options[:parallel] < 1
    warn "Error: parameter of -j option should be greater than 0."
    return
  end

  # Require needed things for parallel running
  require 'thread'
  require 'timeout'
  @tasks = @files.dup # Array of filenames.
  @need_quit = false
  @dead_workers = []  # Array of dead workers.
  @warnings = []
  @total_tests = @tasks.size.to_s(10)
  rep = [] # FIXME: more good naming

  @workers      = [] # Array of workers.
  @workers_hash = {} # out-IO => worker
  @ios          = [] # Array of worker IOs
  begin
    # Thread: watchdog
    watchdog = start_watchdog

    @options[:parallel].times {launch_worker}

    while _io = IO.select(@ios)[0]
      break if _io.any? do |io|
        @need_quit or
          (deal(io, type, result, rep).nil? and
           !@workers.any? {|x| [:running, :prepare].include? x.status})
      end
    end
  rescue Interrupt => ex
    @interrupt = ex
    return result
  ensure
    watchdog.kill if watchdog
    if @interrupt
      @ios.select!{|x| @workers_hash[x].status == :running }
      while !@ios.empty? && (__io = IO.select(@ios,[],[],10))
        __io[0].reject! {|io| deal(io, type, result, rep, true)}
      end
    end

    quit_workers

    unless @interrupt || !@options[:retry] || @need_quit
      @options[:parallel] = false
      suites, rep = rep.partition {|r| r[:testcase] && r[:file] && r[:report].any? {|e| !e[2].is_a?(MiniTest::Skip)}}
      suites.map {|r| r[:file]}.uniq.each {|file| require file}
      suites.map! {|r| eval("::"+r[:testcase])}
      del_status_line or puts
      unless suites.empty?
        puts "Retrying..."
        _run_suites(suites, type)
      end
    end
    unless @options[:retry]
      del_status_line or puts
    end
    unless rep.empty?
      rep.each do |r|
        r[:report].each do |f|
          puke(*f) if f
        end
      end
      if @options[:retry]
        @errors   += rep.map{|x| x[:result][0] }.inject(:+)
        @failures += rep.map{|x| x[:result][1] }.inject(:+)
        @skips    += rep.map{|x| x[:result][2] }.inject(:+)
      end
    end
    unless @warnings.empty?
      warn ""
      @warnings.uniq! {|w| w[1].message}
      @warnings.each do |w|
        warn "#{w[0]}: #{w[1].message} (#{w[1].class})"
      end
      warn ""
    end
  end
end
            
_run_suites(suites, type) click to toggle source
 
               # File test/unit.rb, line 647
def _run_suites suites, type
  _prepare_run(suites, type)
  @interrupt = nil
  result = []
  GC.start
  if @options[:parallel]
    _run_parallel suites, type, result
  else
    suites.each {|suite|
      begin
        result << _run_suite(suite, type)
      rescue Interrupt => e
        @interrupt = e
        break
      end
    }
  end
  report.reject!{|r| r.start_with? "Skipped:" } if @options[:hide_skip]
  report.sort_by!{|r| r.start_with?("Skipped:") ? 0 :                             (r.start_with?("Failure:") ? 1 : 2) }
  result
end
            
add_status(line) click to toggle source
 
               # File test/unit.rb, line 425
def add_status(line)
  unless @options[:job_status] == :replace
    print(line)
    return
  end
  @status_line_size ||= 0
  line = line[0...(terminal_width-@status_line_size)]
  print line
  $stdout.flush
  @status_line_size += line.size
end
            
after_worker_down(worker, e=nil, c=false) click to toggle source
 
               # File test/unit.rb, line 372
def after_worker_down(worker, e=nil, c=false)
  return unless @options[:parallel]
  return if @interrupt
  warn e if e
  @need_quit = true
  warn ""
  warn "Some worker was crashed. It seems ruby interpreter's bug"
  warn "or, a bug of test/unit/parallel.rb. try again without -j"
  warn "option."
  warn ""
  STDERR.flush
  exit c
end
            
after_worker_quit(worker) click to toggle source
 
               # File test/unit.rb, line 449
def after_worker_quit(worker)
  return unless @options[:parallel]
  return if @interrupt
  @workers.delete(worker)
  @dead_workers << worker
  @ios = @workers.map(&:io)
end
            
deal(io, type, result, rep, shutting_down = false) click to toggle source
 
               # File test/unit.rb, line 521
def deal(io, type, result, rep, shutting_down = false)
  worker = @workers_hash[io]
  case worker.read
  when /^okay$/
    worker.status = :running
    jobs_status
  when /^ready(!)?$/
    bang = $1
    worker.status = :ready

    return nil unless task = @tasks.shift
    if @options[:separate] and not bang
      worker.quit
      worker = add_worker
    end
    worker.run(task, type)
    @test_count += 1

    jobs_status
  when /^done (.+?)$/
    r = Marshal.load($1.unpack("m")[0])
    result << r[0..1] unless r[0..1] == [nil,nil]
    rep    << {file: worker.real_file, report: r[2], result: r[3], testcase: r[5]}
    $:.push(*r[4]).uniq!
    return true
  when /^p (.+?)$/
    del_jobs_status
    print $1.unpack("m")[0]
    jobs_status if @options[:job_status] == :replace
  when /^after (.+?)$/
    @warnings << Marshal.load($1.unpack("m")[0])
  when /^bye (.+?)$/
    after_worker_down worker, Marshal.load($1.unpack("m")[0])
  when /^bye$/, nil
    if shutting_down || worker.quit_called
      after_worker_quit worker
    else
      after_worker_down worker
    end
  end
  return false
end
            
del_jobs_status() click to toggle source
 
               # File test/unit.rb, line 444
def del_jobs_status
  return unless @options[:job_status] == :replace && @status_line_size.nonzero?
  del_status_line
end
            
del_status_line() click to toggle source
 
               # File test/unit.rb, line 400
def del_status_line
  @status_line_size ||= 0
  unless @options[:job_status] == :replace
    $stdout.puts
    return
  end
  print "\r"+" "*@status_line_size+"\r"
  $stdout.flush
  @status_line_size = 0
end
            
delete_worker(worker) click to toggle source
 
               # File test/unit.rb, line 473
def delete_worker(worker)
  @workers_hash.delete worker.io
  @workers.delete worker
  @ios.delete worker.io
end
            
failed(s) click to toggle source
 
               # File test/unit.rb, line 726
def failed(s)
  sep = "\n"
  @report_count ||= 0
  report.each do |msg|
    if msg.start_with? "Skipped:"
      if @options[:hide_skip]
        del_status_line
        next
      end
      color = @skipped_color
    else
      color = @failed_color
    end
    msg = msg.split(/$/, 2)
    $stdout.printf("%s%s%3d) %s%s%s\n",
                   sep, color, @report_count += 1,
                   msg[0], @reset_color, msg[1])
    sep = nil
  end
  report.clear
end
            
jobs_status() click to toggle source
 
               # File test/unit.rb, line 437
def jobs_status
  return unless @options[:job_status]
  puts "" unless @options[:verbose] or @options[:job_status] == :replace
  status_line = @workers.map(&:to_s).join(" ")
  update_status(status_line) or (puts; nil)
end
            
launch_worker() click to toggle source
 
               # File test/unit.rb, line 457
def launch_worker
  begin
    worker = Worker.launch(@options[:ruby],@args)
  rescue => e
    abort "ERROR: Failed to launch job process - #{e.class}: #{e.message}"
  end
  worker.hook(:dead) do |w,info|
    after_worker_quit w
    after_worker_down w, *info if !info.empty? && !worker.quit_called
  end
  @workers << worker
  @ios << worker.io
  @workers_hash[worker.io] = worker
  worker
end
            
new_test(s) click to toggle source
 
               # File test/unit.rb, line 713
def new_test(s)
  @test_count += 1
  update_status(s)
end
            
output() click to toggle source
 
               # File test/unit.rb, line 672
def output
  (@output ||= nil) || super
end
            
puke(klass, meth, e) click to toggle source

Overriding of MiniTest::Unit#puke

 
               # File test/unit.rb, line 749
def puke klass, meth, e
  # TODO:
  #   this overriding is for minitest feature that skip messages are
  #   hidden when not verbose (-v), note this is temporally.
  n = report.size
  rep = super
  if MiniTest::Skip === e and /no message given\z/ =~ e.message
    report.slice!(n..-1)
    rep = "."
  end
  rep
end
            
put_status(line) click to toggle source
 
               # File test/unit.rb, line 411
def put_status(line)
  unless @options[:job_status] == :replace
    print(line)
    return
  end
  @status_line_size ||= 0
  del_status_line
  $stdout.flush
  line = line[0...terminal_width]
  print line
  $stdout.flush
  @status_line_size = line.size
end
            
quit_workers() click to toggle source
 
               # File test/unit.rb, line 479
def quit_workers
  return if @workers.empty?
  @workers.reject! do |worker|
    begin
      timeout(1) do
        worker.quit
      end
    rescue Errno::EPIPE
    rescue Timeout::Error
    end
    worker.close
  end

  return if @workers.empty?
  begin
    timeout(0.2 * @workers.size) do
      Process.waitall
    end
  rescue Timeout::Error
    @workers.each do |worker|
      worker.kill
    end
    @worker.clear
  end
end
            
run(*args) click to toggle source
 
               # File test/unit.rb, line 773
def run(*args)
  result = super
  puts "\nruby -v: #{RUBY_DESCRIPTION}"
  result
end
            
start_watchdog() click to toggle source
 
               # File test/unit.rb, line 505
def start_watchdog
  Thread.new do
    while stat = Process.wait2
      break if @interrupt # Break when interrupt
      pid, stat = stat
      w = (@workers + @dead_workers).find{|x| pid == x.pid }
      next unless w
      w = w.dup
      if w.status != :quit && !w.quit_called?
        # Worker down
        w.died(nil, !stat.signaled? && stat.exitstatus)
      end
    end
  end
end
            
status(*args) click to toggle source
 
               # File test/unit.rb, line 767
def status(*args)
  result = super
  raise @interrupt if @interrupt
  result
end
            
succeed() click to toggle source
 
               # File test/unit.rb, line 724
def succeed; del_status_line; end
            
terminal_width() click to toggle source
 
               # File test/unit.rb, line 386
def terminal_width
  unless @terminal_width ||= nil
    begin
      require 'io/console'
      width = $stdout.winsize[1]
    rescue LoadError, NoMethodError, Errno::ENOTTY, Errno::EBADF
      width = ENV["COLUMNS"].to_i.nonzero? || 80
    end
    width -= 1 if /mswin|mingw/ =~ RUBY_PLATFORM
    @terminal_width = width
  end
  @terminal_width
end
            
update_status(s) click to toggle source
 
               # File test/unit.rb, line 718
def update_status(s)
  count = @test_count.to_s(10).rjust(@total_tests.size)
  put_status("#{@passed_color}[#{count}/#{@total_tests}]#{@reset_color} #{s}")
end
            

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus