ruby-changes:33893
From: sorah <ko1@a...>
Date: Sat, 17 May 2014 17:01:25 +0900 (JST)
Subject: [ruby-changes:33893] sorah:r45974 (trunk): * lib/test: Removed because ruby's test cases now independent to
sorah 2014-05-17 17:01:15 +0900 (Sat, 17 May 2014) New Revision: 45974 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=45974 Log: * lib/test: Removed because ruby's test cases now independent to lib/test by r45970. [Feature #9711] [ruby-core:62620] I'm still considering about the future of lib/minitest, lib/test. (bundling gems?) Removed files: trunk/lib/test/unit/assertions.rb trunk/lib/test/unit/parallel.rb trunk/lib/test/unit/test-unit.gemspec trunk/lib/test/unit/testcase.rb trunk/lib/test/unit.rb Modified files: trunk/ChangeLog Index: ChangeLog =================================================================== --- ChangeLog (revision 45973) +++ ChangeLog (revision 45974) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat May 17 16:57:33 2014 Shota Fukumori <her@s...> + + * lib/test: Removed because ruby's test cases now independent to + lib/test by r45970. [Feature #9711] [ruby-core:62620] + + I'm still considering about the future of lib/minitest, lib/test. + (bundling gems?) + Sat May 17 15:06:40 2014 SHIBATA Hiroshi <shibata.hiroshi@g...> * test/runner.rb: remove dependency test-unit and minitest Index: lib/test/unit.rb =================================================================== --- lib/test/unit.rb (revision 45973) +++ lib/test/unit.rb (revision 45974) @@ -1,880 +0,0 @@ https://github.com/ruby/ruby/blob/trunk/lib/test/unit.rb#L0 -begin - gem 'minitest', '< 5.0.0' if defined? Gem -rescue Gem::LoadError -end -require 'minitest/unit' -require 'test/unit/assertions' -require 'test/unit/testcase' -require 'optparse' - -# See Test::Unit -module Test - ## - # Test::Unit is an implementation of the xUnit testing framework for Ruby. - # - # If you are writing new test code, please use MiniTest instead of Test::Unit. - # - # Test::Unit has been left in the standard library to support legacy test - # suites. - module Unit - TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest' # :nodoc: - - module RunCount # :nodoc: all - @@run_count = 0 - - def self.have_run? - @@run_count.nonzero? - end - - def run(*) - @@run_count += 1 - super - end - - def run_once - return if have_run? - return if $! # don't run if there was an exception - yield - end - module_function :run_once - end - - module Options # :nodoc: all - def initialize(*, &block) - @init_hook = block - @options = nil - super(&nil) - end - - def option_parser - @option_parser ||= OptionParser.new - end - - def process_args(args = []) - return @options if @options - orig_args = args.dup - options = {} - opts = option_parser - setup_options(opts, options) - opts.parse!(args) - orig_args -= args - args = @init_hook.call(args, options) if @init_hook - non_options(args, options) - @help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " " - @options = options - if @options[:parallel] - @files = args - @args = orig_args - end - options - end - - private - def setup_options(opts, options) - opts.separator 'minitest options:' - opts.version = MiniTest::Unit::VERSION - - options[:retry] = true - options[:job_status] = nil - - opts.on '-h', '--help', 'Display this help.' do - puts opts - exit - end - - opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m| - options[:seed] = m - end - - opts.on '-v', '--verbose', "Verbose. Show progress processing files." do - options[:verbose] = true - self.verbose = options[:verbose] - end - - opts.on '-n', '--name PATTERN', "Filter test names on pattern." do |a| - options[:filter] = a - end - - opts.on '--jobs-status [TYPE]', [:normal, :replace], - "Show status of jobs every file; Disabled when --jobs isn't specified." do |type| - options[:job_status] = type || :normal - end - - opts.on '-j N', '--jobs N', "Allow run tests with N jobs at once" do |a| - if /^t/ =~ a - options[:testing] = true # For testing - options[:parallel] = a[1..-1].to_i - else - options[:parallel] = a.to_i - end - end - - opts.on '--separate', "Restart job process after one testcase has done" do - options[:parallel] ||= 1 - options[:separate] = true - end - - opts.on '--retry', "Retry running testcase when --jobs specified" do - options[:retry] = true - end - - opts.on '--no-retry', "Disable --retry" do - options[:retry] = false - end - - opts.on '--ruby VAL', "Path to ruby; It'll have used at -j option" do |a| - options[:ruby] = a.split(/ /).reject(&:empty?) - end - - opts.on '-q', '--hide-skip', 'Hide skipped tests' do - options[:hide_skip] = true - end - - opts.on '--show-skip', 'Show skipped tests' do - options[:hide_skip] = false - end - - opts.on '--color[=WHEN]', - [:always, :never, :auto], - "colorize the output. WHEN defaults to 'always'", "or can be 'never' or 'auto'." do |c| - options[:color] = c || :always - end - - opts.on '--tty[=WHEN]', - [:yes, :no], - "force to output tty control. WHEN defaults to 'yes'", "or can be 'no'." do |c| - @tty = c != :no - end - end - - def non_options(files, options) - begin - require "rbconfig" - rescue LoadError - warn "#{caller(1)[0]}: warning: Parallel running disabled because can't get path to ruby; run specify with --ruby argument" - options[:parallel] = nil - else - options[:ruby] ||= [RbConfig.ruby] - end - - true - end - end - - module GlobOption # :nodoc: all - @@testfile_prefix = "test" - - def setup_options(parser, options) - super - parser.on '-b', '--basedir=DIR', 'Base directory of test suites.' do |dir| - options[:base_directory] = dir - end - parser.on '-x', '--exclude PATTERN', 'Exclude test files on pattern.' do |pattern| - (options[:reject] ||= []) << pattern - end - end - - def non_options(files, options) - paths = [options.delete(:base_directory), nil].uniq - if reject = options.delete(:reject) - reject_pat = Regexp.union(reject.map {|r| /#{r}/ }) - end - files.map! {|f| - f = f.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR - ((paths if /\A\.\.?(?:\z|\/)/ !~ f) || [nil]).any? do |prefix| - if prefix - path = f.empty? ? prefix : "#{prefix}/#{f}" - else - next if f.empty? - path = f - end - if !(match = Dir["#{path}/**/#{@@testfile_prefix}_*.rb"]).empty? - if reject - match.reject! {|n| - n[(prefix.length+1)..-1] if prefix - reject_pat =~ n - } - end - break match - elsif !reject or reject_pat !~ f and File.exist? path - break path - end - end or - raise ArgumentError, "file not found: #{f}" - } - files.flatten! - super(files, options) - end - end - - module LoadPathOption # :nodoc: all - def setup_options(parser, options) - super - parser.on '-Idirectory', 'Add library load path' do |dirs| - dirs.split(':').each { |d| $LOAD_PATH.unshift d } - end - end - end - - module GCStressOption # :nodoc: all - def setup_options(parser, options) - super - parser.on '--[no-]gc-stress', 'Set GC.stress as true' do |flag| - options[:gc_stress] = flag - end - end - - def non_options(files, options) - if options.delete(:gc_stress) - MiniTest::Unit::TestCase.class_eval do - oldrun = instance_method(:run) - define_method(:run) do |runner| - begin - gc_stress, GC.stress = GC.stress, true - oldrun.bind(self).call(runner) - ensure - GC.stress = gc_stress - end - end - end - end - super - end - end - - module RequireFiles # :nodoc: all - def non_options(files, options) - return false if !super - result = false - files.each {|f| - d = File.dirname(path = File.realpath(f)) - unless $:.include? d - $: << d - end - begin - require path unless options[:parallel] - result = true - rescue LoadError - puts "#{f}: #{$!}" - end - } - result - end - end - - class Runner < MiniTest::Unit # :nodoc: all - include Test::Unit::Options - include Test::Unit::GlobOption - include Test::Unit::LoadPathOption - include Test::Unit::GCStressOption - include Test::Unit::RunCount - - class Worker - def self.launch(ruby,args=[]) - io = IO.popen([*ruby, - "#{File.dirname(__FILE__)}/unit/parallel.rb", - *args], "rb+") - new(io, io.pid, :waiting) - end - - attr_reader :quit_called - - def initialize(io, pid, status) - @io = io - @pid = pid - @status = status - @file = nil - @real_file = nil - @loadpath = [] - @hooks = {} - @quit_called = false - end - - def puts(*args) - @io.puts(*args) - end - - def run(task,type) - @file = File.basename(task, ".rb") - @real_file = task - begin - puts "loadpath #{[Marshal.dump($:-@loadpath)].pack("m0")}" - @loadpath = $:.dup - puts "run #{task} #{type}" - @status = :prepare - rescue Errno::EPIPE - died - rescue IOError - raise unless ["stream closed","closed stream"].include? $!.message - died - end - end - - def hook(id,&block) - @hooks[id] ||= [] - @hooks[id] << block - self - end - - def read - res = (@status == :quit) ? @io.read : @io.gets - res && res.chomp - end - - def close - @io.close unless @io.closed? - self - rescue IOError - end - - def quit - return if @io.closed? - @quit_called = true - @io.puts "quit" - @io.close - end - - def kill - Process.kill(:KILL, @pid) - rescue Errno::ESRCH - end - - def died(*additional) - @status = :quit - @io.close - - call_hook(:dead,*additional) - end - - def to_s - if @file - "#{@pid}=#{@file}" - else - "#{@pid}:#{@status.to_s.ljust(7)}" - end - end - - attr_reader :io, :pid - attr_accessor :status, :file, :real_file, :loadpath - - private - - def call_hook(id,*additional) - @hooks[id] ||= [] - @hooks[id].each{|hook| hook[self,additional] } - self - end - - end - - class << self; undef autorun; end - - @@stop_auto_run = false - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - def del_jobs_status - return unless @options[:job_status] == :replace && @status_line_size.nonzero? - del_status_line - end - - def after_worker_quit(worker) - return unless @options[:parallel] - return if @interrupt - @workers.delete(worker) - @dead_workers << worker - @ios = @workers.map(&:io) - end - - 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 - - def delete_worker(worker) - @workers_hash.delete worker.io - @workers.delete worker - @ios.delete worker.io - end - - 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 - - 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 - - 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 - - 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 - - def _run (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/