# 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!(/(? 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