diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-09-08 10:00:41 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-09-11 08:48:03 +0900 |
commit | c18e9539373a1e90e36e503a51ce5cebb7372e23 (patch) | |
tree | 207b8f08dba17b7ee6958d3f481c8c51c9b2740f /tool/lib | |
parent | 78ec066347cd5e59957ef6f98d4f40fd00aa667a (diff) |
Move MiniTest::Unit to under Test::Unit::Runner
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4813
Diffstat (limited to 'tool/lib')
-rw-r--r-- | tool/lib/minitest/unit.rb | 397 | ||||
-rw-r--r-- | tool/lib/test/unit.rb | 397 |
2 files changed, 396 insertions, 398 deletions
diff --git a/tool/lib/minitest/unit.rb b/tool/lib/minitest/unit.rb index 6a446d3c11..6c72362c52 100644 --- a/tool/lib/minitest/unit.rb +++ b/tool/lib/minitest/unit.rb @@ -69,401 +69,4 @@ module MiniTest backtrace_filter.filter bt end - class Unit # :nodoc: - VERSION = "4.7.5" # :nodoc: - - attr_accessor :report, :failures, :errors, :skips # :nodoc: - attr_accessor :assertion_count # :nodoc: - attr_writer :test_count # :nodoc: - attr_accessor :start_time # :nodoc: - attr_accessor :help # :nodoc: - attr_accessor :verbose # :nodoc: - attr_writer :options # :nodoc: - - ## - # :attr: - # - # if true, installs an "INFO" signal handler (only available to BSD and - # OS X users) which prints diagnostic information about the test run. - # - # This is auto-detected by default but may be overridden by custom - # runners. - - attr_accessor :info_signal - - ## - # Lazy accessor for options. - - def options - @options ||= {seed: 42} - end - - @@installed_at_exit ||= false - @@out = $stdout - @@after_tests = [] - @@current_repeat_count = 0 - - ## - # A simple hook allowing you to run a block of code after _all_ of - # the tests are done. Eg: - # - # MiniTest::Unit.after_tests { p $debugging_info } - - def self.after_tests &block - @@after_tests << block - end - - ## - # Registers MiniTest::Unit to run tests at process exit - - def self.autorun - at_exit { - # don't run if there was a non-exit exception - next if $! and not $!.kind_of? SystemExit - - # the order here is important. The at_exit handler must be - # installed before anyone else gets a chance to install their - # own, that way we can be assured that our exit will be last - # to run (at_exit stacks). - exit_code = nil - - at_exit { - @@after_tests.reverse_each(&:call) - exit false if exit_code && exit_code != 0 - } - - exit_code = MiniTest::Unit.new.run ARGV - } unless @@installed_at_exit - @@installed_at_exit = true - end - - ## - # Returns the stream to use for output. - - def self.output - @@out - end - - ## - # Sets MiniTest::Unit to write output to +stream+. $stdout is the default - # output - - def self.output= stream - @@out = stream - end - - ## - # Tells MiniTest::Unit to delegate to +runner+, an instance of a - # MiniTest::Unit subclass, when MiniTest::Unit#run is called. - - def self.runner= runner - @@runner = runner - end - - ## - # Returns the MiniTest::Unit subclass instance that will be used - # to run the tests. A MiniTest::Unit instance is the default - # runner. - - def self.runner - @@runner ||= self.new - end - - ## - # Return all plugins' run methods (methods that start with "run_"). - - def self.plugins - @@plugins ||= (["run_tests"] + - public_instance_methods(false). - grep(/^run_/).map { |s| s.to_s }).uniq - end - - ## - # Return the IO for output. - - def output - self.class.output - end - - def puts *a # :nodoc: - output.puts(*a) - end - - def print *a # :nodoc: - output.print(*a) - end - - def test_count # :nodoc: - @test_count ||= 0 - end - - ## - # Runner for a given +type+ (eg, test vs bench). - - def self.current_repeat_count - @@current_repeat_count - end - - def _run_anything type - suites = Test::Unit::TestCase.send "#{type}_suites" - return if suites.empty? - - puts - puts "# Running #{type}s:" - puts - - @test_count, @assertion_count = 0, 0 - test_count = assertion_count = 0 - sync = output.respond_to? :"sync=" # stupid emacs - old_sync, output.sync = output.sync, true if sync - - @@current_repeat_count = 0 - begin - start = Time.now - - results = _run_suites suites, type - - @test_count = results.inject(0) { |sum, (tc, _)| sum + tc } - @assertion_count = results.inject(0) { |sum, (_, ac)| sum + ac } - test_count += @test_count - assertion_count += @assertion_count - t = Time.now - start - @@current_repeat_count += 1 - unless @repeat_count - puts - puts - end - puts "Finished%s %ss in %.6fs, %.4f tests/s, %.4f assertions/s.\n" % - [(@repeat_count ? "(#{@@current_repeat_count}/#{@repeat_count}) " : ""), type, - t, @test_count.fdiv(t), @assertion_count.fdiv(t)] - end while @repeat_count && @@current_repeat_count < @repeat_count && - report.empty? && failures.zero? && errors.zero? - - output.sync = old_sync if sync - - report.each_with_index do |msg, i| - puts "\n%3d) %s" % [i + 1, msg] - end - - puts - @test_count = test_count - @assertion_count = assertion_count - - status - end - - ## - # Runs all the +suites+ for a given +type+. - # - - def _run_suites suites, type - suites.map { |suite| _run_suite suite, type } - end - - ## - # Run a single +suite+ for a given +type+. - - def _run_suite suite, type - header = "#{type}_suite_header" - puts send(header, suite) if respond_to? header - - filter = options[:filter] || '/./' - filter = Regexp.new $1 if filter =~ /\/(.*)\// - - all_test_methods = suite.send "#{type}_methods" - - filtered_test_methods = all_test_methods.find_all { |m| - filter === m || filter === "#{suite}##{m}" - } - - leakchecker = LeakChecker.new - if ENV["LEAK_CHECKER_TRACE_OBJECT_ALLOCATION"] - require "objspace" - trace = true - end - - assertions = filtered_test_methods.map { |method| - inst = suite.new method - inst._assertions = 0 - - print "#{suite}##{method} = " if @verbose - - start_time = Time.now if @verbose - result = - if trace - ObjectSpace.trace_object_allocations {inst.run self} - else - inst.run self - end - - print "%.2f s = " % (Time.now - start_time) if @verbose - print result - puts if @verbose - $stdout.flush - - unless defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # compiler process is wrongly considered as leak - leakchecker.check("#{inst.class}\##{inst.__name__}") - end - - inst._assertions - } - return assertions.size, assertions.inject(0) { |sum, n| sum + n } - end - - ## - # Record the result of a single test. Makes it very easy to gather - # information. Eg: - # - # class StatisticsRecorder < MiniTest::Unit - # def record suite, method, assertions, time, error - # # ... record the results somewhere ... - # end - # end - # - # MiniTest::Unit.runner = StatisticsRecorder.new - # - # NOTE: record might be sent more than once per test. It will be - # sent once with the results from the test itself. If there is a - # failure or error in teardown, it will be sent again with the - # error or failure. - - def record suite, method, assertions, time, error - end - - def location e # :nodoc: - last_before_assertion = "" - - return '<empty>' unless e.backtrace # SystemStackError can return nil. - - e.backtrace.reverse_each do |s| - break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/ - last_before_assertion = s - end - last_before_assertion.sub(/:in .*$/, '') - end - - ## - # Writes status for failed test +meth+ in +klass+ which finished with - # exception +e+ - - def puke klass, meth, e - e = case e - when MiniTest::Skip then - @skips += 1 - return "S" unless @verbose - "Skipped:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n" - when MiniTest::Assertion then - @failures += 1 - "Failure:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n" - else - @errors += 1 - bt = MiniTest::filter_backtrace(e.backtrace).join "\n " - "Error:\n#{klass}##{meth}:\n#{e.class}: #{e.message.b}\n #{bt}\n" - end - @report << e - e[0, 1] - end - - def initialize # :nodoc: - @report = [] - @errors = @failures = @skips = 0 - @verbose = false - @mutex = Thread::Mutex.new - @info_signal = Signal.list['INFO'] - @repeat_count = nil - end - - def synchronize # :nodoc: - if @mutex then - @mutex.synchronize { yield } - else - yield - end - end - - def process_args args = [] # :nodoc: - options = {} - orig_args = args.dup - - OptionParser.new do |opts| - opts.banner = 'minitest options:' - opts.version = MiniTest::Unit::VERSION - - 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.to_i - end - - opts.on '-v', '--verbose', "Verbose. Show progress processing files." do - options[:verbose] = true - end - - opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a| - options[:filter] = a - end - - opts.parse! args - orig_args -= args - end - - unless options[:seed] then - srand - options[:seed] = srand % 0xFFFF - orig_args << "--seed" << options[:seed].to_s - end - - srand options[:seed] - - self.verbose = options[:verbose] - @help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " " - - options - end - - ## - # Begins the full test run. Delegates to +runner+'s #_run method. - - def run args = [] - self.class.runner._run(args) - end - - ## - # Top level driver, controls all output and filtering. - - def _run args = [] - args = process_args args # ARGH!! blame test/unit process_args - self.options.merge! args - - puts "Run options: #{help}" - - self.class.plugins.each do |plugin| - send plugin - break unless report.empty? - end - - return failures + errors if self.test_count > 0 # or return nil... - rescue Interrupt - abort 'Interrupted' - end - - ## - # Runs test suites matching +filter+. - - def run_tests - _run_anything :test - end - - ## - # Writes status to +io+ - - def status io = self.output - format = "%d tests, %d assertions, %d failures, %d errors, %d skips" - io.puts format % [test_count, assertion_count, failures, errors, skips] - end - - end # class Unit end # module MiniTest diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb index 27751d0005..356911150d 100644 --- a/tool/lib/test/unit.rb +++ b/tool/lib/test/unit.rb @@ -17,6 +17,7 @@ module Test # Test::Unit has been left in the standard library to support legacy test # suites. module Unit + VERSION = "4.7.5" # :nodoc: TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest' # :nodoc: module RunCount # :nodoc: all @@ -1158,7 +1159,401 @@ module Test end end - class Runner < MiniTest::Unit # :nodoc: all + class Runner # :nodoc: all + + attr_accessor :report, :failures, :errors, :skips # :nodoc: + attr_accessor :assertion_count # :nodoc: + attr_writer :test_count # :nodoc: + attr_accessor :start_time # :nodoc: + attr_accessor :help # :nodoc: + attr_accessor :verbose # :nodoc: + attr_writer :options # :nodoc: + + ## + # :attr: + # + # if true, installs an "INFO" signal handler (only available to BSD and + # OS X users) which prints diagnostic information about the test run. + # + # This is auto-detected by default but may be overridden by custom + # runners. + + attr_accessor :info_signal + + ## + # Lazy accessor for options. + + def options + @options ||= {seed: 42} + end + + @@installed_at_exit ||= false + @@out = $stdout + @@after_tests = [] + @@current_repeat_count = 0 + + ## + # A simple hook allowing you to run a block of code after _all_ of + # the tests are done. Eg: + # + # MiniTest::Unit.after_tests { p $debugging_info } + + def self.after_tests &block + @@after_tests << block + end + + ## + # Registers MiniTest::Unit to run tests at process exit + + def self.autorun + at_exit { + # don't run if there was a non-exit exception + next if $! and not $!.kind_of? SystemExit + + # the order here is important. The at_exit handler must be + # installed before anyone else gets a chance to install their + # own, that way we can be assured that our exit will be last + # to run (at_exit stacks). + exit_code = nil + + at_exit { + @@after_tests.reverse_each(&:call) + exit false if exit_code && exit_code != 0 + } + + exit_code = MiniTest::Unit.new.run ARGV + } unless @@installed_at_exit + @@installed_at_exit = true + end + + ## + # Returns the stream to use for output. + + def self.output + @@out + end + + ## + # Sets MiniTest::Unit to write output to +stream+. $stdout is the default + # output + + def self.output= stream + @@out = stream + end + + ## + # Tells MiniTest::Unit to delegate to +runner+, an instance of a + # MiniTest::Unit subclass, when MiniTest::Unit#run is called. + + def self.runner= runner + @@runner = runner + end + + ## + # Returns the MiniTest::Unit subclass instance that will be used + # to run the tests. A MiniTest::Unit instance is the default + # runner. + + def self.runner + @@runner ||= self.new + end + + ## + # Return all plugins' run methods (methods that start with "run_"). + + def self.plugins + @@plugins ||= (["run_tests"] + + public_instance_methods(false). + grep(/^run_/).map { |s| s.to_s }).uniq + end + + ## + # Return the IO for output. + + def output + self.class.output + end + + def puts *a # :nodoc: + output.puts(*a) + end + + def print *a # :nodoc: + output.print(*a) + end + + def test_count # :nodoc: + @test_count ||= 0 + end + + ## + # Runner for a given +type+ (eg, test vs bench). + + def self.current_repeat_count + @@current_repeat_count + end + + def _run_anything type + suites = Test::Unit::TestCase.send "#{type}_suites" + return if suites.empty? + + puts + puts "# Running #{type}s:" + puts + + @test_count, @assertion_count = 0, 0 + test_count = assertion_count = 0 + sync = output.respond_to? :"sync=" # stupid emacs + old_sync, output.sync = output.sync, true if sync + + @@current_repeat_count = 0 + begin + start = Time.now + + results = _run_suites suites, type + + @test_count = results.inject(0) { |sum, (tc, _)| sum + tc } + @assertion_count = results.inject(0) { |sum, (_, ac)| sum + ac } + test_count += @test_count + assertion_count += @assertion_count + t = Time.now - start + @@current_repeat_count += 1 + unless @repeat_count + puts + puts + end + puts "Finished%s %ss in %.6fs, %.4f tests/s, %.4f assertions/s.\n" % + [(@repeat_count ? "(#{@@current_repeat_count}/#{@repeat_count}) " : ""), type, + t, @test_count.fdiv(t), @assertion_count.fdiv(t)] + end while @repeat_count && @@current_repeat_count < @repeat_count && + report.empty? && failures.zero? && errors.zero? + + output.sync = old_sync if sync + + report.each_with_index do |msg, i| + puts "\n%3d) %s" % [i + 1, msg] + end + + puts + @test_count = test_count + @assertion_count = assertion_count + + status + end + + ## + # Runs all the +suites+ for a given +type+. + # + + def _run_suites suites, type + suites.map { |suite| _run_suite suite, type } + end + + ## + # Run a single +suite+ for a given +type+. + + def _run_suite suite, type + header = "#{type}_suite_header" + puts send(header, suite) if respond_to? header + + filter = options[:filter] || '/./' + filter = Regexp.new $1 if filter =~ /\/(.*)\// + + all_test_methods = suite.send "#{type}_methods" + + filtered_test_methods = all_test_methods.find_all { |m| + filter === m || filter === "#{suite}##{m}" + } + + leakchecker = LeakChecker.new + if ENV["LEAK_CHECKER_TRACE_OBJECT_ALLOCATION"] + require "objspace" + trace = true + end + + assertions = filtered_test_methods.map { |method| + inst = suite.new method + inst._assertions = 0 + + print "#{suite}##{method} = " if @verbose + + start_time = Time.now if @verbose + result = + if trace + ObjectSpace.trace_object_allocations {inst.run self} + else + inst.run self + end + + print "%.2f s = " % (Time.now - start_time) if @verbose + print result + puts if @verbose + $stdout.flush + + unless defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # compiler process is wrongly considered as leak + leakchecker.check("#{inst.class}\##{inst.__name__}") + end + + inst._assertions + } + return assertions.size, assertions.inject(0) { |sum, n| sum + n } + end + + ## + # Record the result of a single test. Makes it very easy to gather + # information. Eg: + # + # class StatisticsRecorder < MiniTest::Unit + # def record suite, method, assertions, time, error + # # ... record the results somewhere ... + # end + # end + # + # MiniTest::Unit.runner = StatisticsRecorder.new + # + # NOTE: record might be sent more than once per test. It will be + # sent once with the results from the test itself. If there is a + # failure or error in teardown, it will be sent again with the + # error or failure. + + def record suite, method, assertions, time, error + end + + def location e # :nodoc: + last_before_assertion = "" + + return '<empty>' unless e.backtrace # SystemStackError can return nil. + + e.backtrace.reverse_each do |s| + break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/ + last_before_assertion = s + end + last_before_assertion.sub(/:in .*$/, '') + end + + ## + # Writes status for failed test +meth+ in +klass+ which finished with + # exception +e+ + + def puke klass, meth, e + e = case e + when MiniTest::Skip then + @skips += 1 + return "S" unless @verbose + "Skipped:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n" + when MiniTest::Assertion then + @failures += 1 + "Failure:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n" + else + @errors += 1 + bt = MiniTest::filter_backtrace(e.backtrace).join "\n " + "Error:\n#{klass}##{meth}:\n#{e.class}: #{e.message.b}\n #{bt}\n" + end + @report << e + e[0, 1] + end + + def initialize # :nodoc: + @report = [] + @errors = @failures = @skips = 0 + @verbose = false + @mutex = Thread::Mutex.new + @info_signal = Signal.list['INFO'] + @repeat_count = nil + end + + def synchronize # :nodoc: + if @mutex then + @mutex.synchronize { yield } + else + yield + end + end + + def process_args args = [] # :nodoc: + options = {} + orig_args = args.dup + + OptionParser.new do |opts| + opts.banner = 'minitest options:' + opts.version = MiniTest::Unit::VERSION + + 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.to_i + end + + opts.on '-v', '--verbose', "Verbose. Show progress processing files." do + options[:verbose] = true + end + + opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a| + options[:filter] = a + end + + opts.parse! args + orig_args -= args + end + + unless options[:seed] then + srand + options[:seed] = srand % 0xFFFF + orig_args << "--seed" << options[:seed].to_s + end + + srand options[:seed] + + self.verbose = options[:verbose] + @help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " " + + options + end + + ## + # Begins the full test run. Delegates to +runner+'s #_run method. + + def run args = [] + self.class.runner._run(args) + end + + ## + # Top level driver, controls all output and filtering. + + def _run args = [] + args = process_args args # ARGH!! blame test/unit process_args + self.options.merge! args + + puts "Run options: #{help}" + + self.class.plugins.each do |plugin| + send plugin + break unless report.empty? + end + + return failures + errors if self.test_count > 0 # or return nil... + rescue Interrupt + abort 'Interrupted' + end + + ## + # Runs test suites matching +filter+. + + def run_tests + _run_anything :test + end + + ## + # Writes status to +io+ + + def status io = self.output + format = "%d tests, %d assertions, %d failures, %d errors, %d skips" + io.puts format % [test_count, assertion_count, failures, errors, skips] + end + include Test::Unit::Options include Test::Unit::StatusLine include Test::Unit::Parallel |