diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2019-07-15 09:39:22 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2019-07-15 09:40:22 +0900 |
commit | 08b340d2f68daf6bbaba9be77ee7c17150bd7adb (patch) | |
tree | 5a08cc188ba1cd727064f28d6a99628ef2b168ba /tool | |
parent | e8ddbc0239b9dfa32787e93c6942f085e5c42b49 (diff) | |
download | ruby-08b340d2f68daf6bbaba9be77ee7c17150bd7adb.tar.gz |
Separate the assertions of ruby core tests from test/unit/assertions.
Diffstat (limited to 'tool')
-rw-r--r-- | tool/lib/test/unit/assertions.rb | 207 | ||||
-rw-r--r-- | tool/lib/test/unit/core_assertions.rb | 216 |
2 files changed, 218 insertions, 205 deletions
diff --git a/tool/lib/test/unit/assertions.rb b/tool/lib/test/unit/assertions.rb index 169a3dcc7e..0c68a93b02 100644 --- a/tool/lib/test/unit/assertions.rb +++ b/tool/lib/test/unit/assertions.rb @@ -1,15 +1,12 @@ # frozen_string_literal: true require 'minitest/unit' +require 'test/unit/core_assertions' require 'pp' module Test module Unit module Assertions - include MiniTest::Assertions - - def mu_pp(obj) #:nodoc: - obj.pretty_inspect.chomp - end + include Test::Unit::CoreAssertions MINI_DIR = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), "minitest") #:nodoc: @@ -554,80 +551,6 @@ EOT assert !status.signaled?, FailDesc[status, message, out] end - FailDesc = proc do |status, message = "", out = ""| - pid = status.pid - now = Time.now - faildesc = proc do - if signo = status.termsig - signame = Signal.signame(signo) - sigdesc = "signal #{signo}" - end - log = EnvUtil.diagnostic_reports(signame, pid, now) - if signame - sigdesc = "SIG#{signame} (#{sigdesc})" - end - if status.coredump? - sigdesc = "#{sigdesc} (core dumped)" - end - full_message = ''.dup - message = message.call if Proc === message - if message and !message.empty? - full_message << message << "\n" - end - full_message << "pid #{pid}" - full_message << " exit #{status.exitstatus}" if status.exited? - full_message << " killed by #{sigdesc}" if sigdesc - if out and !out.empty? - full_message << "\n" << out.b.gsub(/^/, '| ') - full_message.sub!(/(?<!\n)\z/, "\n") - end - if log - full_message << "Diagnostic reports:\n" << log.b.gsub(/^/, '| ') - end - full_message - end - faildesc - end - - def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, - success: nil, **opt) - args = Array(args).dup - args.insert((Hash === args[0] ? 1 : 0), '--disable=gems') - stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt) - if signo = status.termsig - EnvUtil.diagnostic_reports(Signal.signame(signo), status.pid, Time.now) - end - if block_given? - raise "test_stdout ignored, use block only or without block" if test_stdout != [] - raise "test_stderr ignored, use block only or without block" if test_stderr != [] - yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }, status) - else - all_assertions(message) do |a| - [["stdout", test_stdout, stdout], ["stderr", test_stderr, stderr]].each do |key, exp, act| - a.for(key) do - if exp.is_a?(Regexp) - assert_match(exp, act) - elsif exp.all? {|e| String === e} - assert_equal(exp, act.lines.map {|l| l.chomp }) - else - assert_pattern_list(exp, act) - end - end - end - unless success.nil? - a.for("success?") do - if success - assert_predicate(status, :success?) - else - assert_not_predicate(status, :success?) - end - end - end - end - status - end - end - def assert_ruby_status(args, test_stdin="", message=nil, **opt) out, _, status = EnvUtil.invoke_ruby(args, test_stdin, true, :merge_to_stdout, **opt) desc = FailDesc[status, message, out] @@ -636,57 +559,6 @@ EOT assert(status.success?, desc) end - ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM") - - def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) - unless file and line - loc, = caller_locations(1,1) - file ||= loc.path - line ||= loc.lineno - end - src = <<eom -# -*- coding: #{line += __LINE__; src.encoding}; -*- - require #{__dir__.dump};include Test::Unit::Assertions - END { - puts [Marshal.dump($!)].pack('m'), "assertions=\#{self._assertions}" - } -#{line -= __LINE__; src} - class Test::Unit::Runner - @@stop_auto_run = true - end -eom - args = args.dup - args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"}) - stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, **opt) - abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig)) - assert(!abort, FailDesc[status, nil, stderr]) - self._assertions += stdout[/^assertions=(\d+)/, 1].to_i - begin - res = Marshal.load(stdout.unpack("m")[0]) - rescue => marshal_error - ignore_stderr = nil - end - if res - if bt = res.backtrace - bt.each do |l| - l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} - end - bt.concat(caller) - else - res.set_backtrace(caller) - end - raise res unless SystemExit === res - end - - # really is it succeed? - unless ignore_stderr - # the body of assert_separately must not output anything to detect error - assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr]) - end - assert(status.success?, FailDesc[status, "assert_separately failed", stderr]) - raise marshal_error if marshal_error - end - def assert_warning(pat, msg = nil) result = nil stderr = EnvUtil.with_default_internal(pat.encoding) { @@ -799,10 +671,6 @@ eom assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0") end - def assert_file - AssertFile - end - # pattern_list is an array which contains regexp and :*. # :* means any sequence. # @@ -878,77 +746,6 @@ eom end end - class << (AssertFile = Struct.new(:failure_message).new) - include Assertions - def assert_file_predicate(predicate, *args) - if /\Anot_/ =~ predicate - predicate = $' - neg = " not" - end - result = File.__send__(predicate, *args) - result = !result if neg - mesg = "Expected file ".dup << args.shift.inspect - mesg << "#{neg} to be #{predicate}" - mesg << mu_pp(args).sub(/\A\[(.*)\]\z/m, '(\1)') unless args.empty? - mesg << " #{failure_message}" if failure_message - assert(result, mesg) - end - alias method_missing assert_file_predicate - - def for(message) - clone.tap {|a| a.failure_message = message} - end - end - - class AllFailures - attr_reader :failures - - def initialize - @count = 0 - @failures = {} - end - - def for(key) - @count += 1 - yield - rescue Exception => e - @failures[key] = [@count, e] - end - - def foreach(*keys) - keys.each do |key| - @count += 1 - begin - yield key - rescue Exception => e - @failures[key] = [@count, e] - end - end - end - - def message - i = 0 - total = @count.to_s - fmt = "%#{total.size}d" - @failures.map {|k, (n, v)| - v = v.message - "\n#{i+=1}. [#{fmt%n}/#{total}] Assertion for #{k.inspect}\n#{v.b.gsub(/^/, ' | ').force_encoding(v.encoding)}" - }.join("\n") - end - - def pass? - @failures.empty? - end - end - - def assert_all_assertions(msg = nil) - all = AllFailures.new - yield all - ensure - assert(all.pass?, message(msg) {all.message.chomp(".")}) - end - alias all_assertions assert_all_assertions - def assert_all_assertions_foreach(msg = nil, *keys, &block) all = AllFailures.new all.foreach(*keys, &block) diff --git a/tool/lib/test/unit/core_assertions.rb b/tool/lib/test/unit/core_assertions.rb new file mode 100644 index 0000000000..21be860176 --- /dev/null +++ b/tool/lib/test/unit/core_assertions.rb @@ -0,0 +1,216 @@ +# frozen_string_literal: true + +require_relative '../../envutil' + +module Test + module Unit + module CoreAssertions + include MiniTest::Assertions + + def mu_pp(obj) #:nodoc: + obj.pretty_inspect.chomp + end + + def assert_file + AssertFile + end + + FailDesc = proc do |status, message = "", out = ""| + pid = status.pid + now = Time.now + faildesc = proc do + if signo = status.termsig + signame = Signal.signame(signo) + sigdesc = "signal #{signo}" + end + log = EnvUtil.diagnostic_reports(signame, pid, now) + if signame + sigdesc = "SIG#{signame} (#{sigdesc})" + end + if status.coredump? + sigdesc = "#{sigdesc} (core dumped)" + end + full_message = ''.dup + message = message.call if Proc === message + if message and !message.empty? + full_message << message << "\n" + end + full_message << "pid #{pid}" + full_message << " exit #{status.exitstatus}" if status.exited? + full_message << " killed by #{sigdesc}" if sigdesc + if out and !out.empty? + full_message << "\n" << out.b.gsub(/^/, '| ') + full_message.sub!(/(?<!\n)\z/, "\n") + end + if log + full_message << "Diagnostic reports:\n" << log.b.gsub(/^/, '| ') + end + full_message + end + faildesc + end + + def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, + success: nil, **opt) + args = Array(args).dup + args.insert((Hash === args[0] ? 1 : 0), '--disable=gems') + stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt) + if signo = status.termsig + EnvUtil.diagnostic_reports(Signal.signame(signo), status.pid, Time.now) + end + if block_given? + raise "test_stdout ignored, use block only or without block" if test_stdout != [] + raise "test_stderr ignored, use block only or without block" if test_stderr != [] + yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }, status) + else + all_assertions(message) do |a| + [["stdout", test_stdout, stdout], ["stderr", test_stderr, stderr]].each do |key, exp, act| + a.for(key) do + if exp.is_a?(Regexp) + assert_match(exp, act) + elsif exp.all? {|e| String === e} + assert_equal(exp, act.lines.map {|l| l.chomp }) + else + assert_pattern_list(exp, act) + end + end + end + unless success.nil? + a.for("success?") do + if success + assert_predicate(status, :success?) + else + assert_not_predicate(status, :success?) + end + end + end + end + status + end + end + + ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM") + + def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) + unless file and line + loc, = caller_locations(1,1) + file ||= loc.path + line ||= loc.lineno + end + src = <<eom +# -*- coding: #{line += __LINE__; src.encoding}; -*- + require #{__dir__.dump};include Test::Unit::Assertions + END { + puts [Marshal.dump($!)].pack('m'), "assertions=\#{self._assertions}" + } +#{line -= __LINE__; src} + class Test::Unit::Runner + @@stop_auto_run = true + end +eom + args = args.dup + args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"}) + stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, **opt) + abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig)) + assert(!abort, FailDesc[status, nil, stderr]) + self._assertions += stdout[/^assertions=(\d+)/, 1].to_i + begin + res = Marshal.load(stdout.unpack("m")[0]) + rescue => marshal_error + ignore_stderr = nil + end + if res + if bt = res.backtrace + bt.each do |l| + l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} + end + bt.concat(caller) + else + res.set_backtrace(caller) + end + raise res unless SystemExit === res + end + + # really is it succeed? + unless ignore_stderr + # the body of assert_separately must not output anything to detect error + assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr]) + end + assert(status.success?, FailDesc[status, "assert_separately failed", stderr]) + raise marshal_error if marshal_error + end + + class << (AssertFile = Struct.new(:failure_message).new) + include CoreAssertions + def assert_file_predicate(predicate, *args) + if /\Anot_/ =~ predicate + predicate = $' + neg = " not" + end + result = File.__send__(predicate, *args) + result = !result if neg + mesg = "Expected file ".dup << args.shift.inspect + mesg << "#{neg} to be #{predicate}" + mesg << mu_pp(args).sub(/\A\[(.*)\]\z/m, '(\1)') unless args.empty? + mesg << " #{failure_message}" if failure_message + assert(result, mesg) + end + alias method_missing assert_file_predicate + + def for(message) + clone.tap {|a| a.failure_message = message} + end + end + + class AllFailures + attr_reader :failures + + def initialize + @count = 0 + @failures = {} + end + + def for(key) + @count += 1 + yield + rescue Exception => e + @failures[key] = [@count, e] + end + + def foreach(*keys) + keys.each do |key| + @count += 1 + begin + yield key + rescue Exception => e + @failures[key] = [@count, e] + end + end + end + + def message + i = 0 + total = @count.to_s + fmt = "%#{total.size}d" + @failures.map {|k, (n, v)| + v = v.message + "\n#{i+=1}. [#{fmt%n}/#{total}] Assertion for #{k.inspect}\n#{v.b.gsub(/^/, ' | ').force_encoding(v.encoding)}" + }.join("\n") + end + + def pass? + @failures.empty? + end + end + + def assert_all_assertions(msg = nil) + all = AllFailures.new + yield all + ensure + assert(all.pass?, message(msg) {all.message.chomp(".")}) + end + alias all_assertions assert_all_assertions + + end + end +end |