[前][次][番号順一覧][スレッド一覧]

ruby-changes:66221

From: Hiroshi <ko1@a...>
Date: Mon, 17 May 2021 11:21:07 +0900 (JST)
Subject: [ruby-changes:66221] df86a13cc1 (master): [ruby/psych] Import test assertions from ruby/ruby

https://git.ruby-lang.org/ruby.git/commit/?id=df86a13cc1

From df86a13cc150f573b1078779667a1573747d3dbd Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@r...>
Date: Mon, 10 May 2021 18:10:13 +0900
Subject: [ruby/psych] Import test assertions from ruby/ruby

https://github.com/ruby/psych/commit/01dda86681
---
 test/lib/core_assertions.rb | 764 ++++++++++++++++++++++++++++++++++++++++++++
 test/lib/envutil.rb         | 367 +++++++++++++++++++++
 test/lib/find_executable.rb |  22 ++
 test/lib/helper.rb          |  14 +
 4 files changed, 1167 insertions(+)
 create mode 100644 test/lib/core_assertions.rb
 create mode 100644 test/lib/envutil.rb
 create mode 100644 test/lib/find_executable.rb
 create mode 100644 test/lib/helper.rb

diff --git a/test/lib/core_assertions.rb b/test/lib/core_assertions.rb
new file mode 100644
index 0000000..ff78c2b
--- /dev/null
+++ b/test/lib/core_assertions.rb
@@ -0,0 +1,764 @@ https://github.com/ruby/ruby/blob/trunk/test/lib/core_assertions.rb#L1
+# frozen_string_literal: true
+
+module Test
+  module Unit
+    module Assertions
+      def _assertions= n # :nodoc:
+        @_assertions = n
+      end
+
+      def _assertions # :nodoc:
+        @_assertions ||= 0
+      end
+
+      ##
+      # Returns a proc that will output +msg+ along with the default message.
+
+      def message msg = nil, ending = nil, &default
+        proc {
+          msg = msg.call.chomp(".") if Proc === msg
+          custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
+          "#{custom_message}#{default.call}#{ending || "."}"
+        }
+      end
+    end
+
+    module CoreAssertions
+      if defined?(MiniTest)
+        require_relative '../../envutil'
+        # for ruby core testing
+        include MiniTest::Assertions
+
+        # Compatibility hack for assert_raise
+        Test::Unit::AssertionFailedError = MiniTest::Assertion
+      else
+        module MiniTest
+          class Assertion < Exception; end
+          class Skip < Assertion; end
+        end
+
+        require 'pp'
+        require_relative 'envutil'
+        include Test::Unit::Assertions
+      end
+
+      def mu_pp(obj) #:nodoc:
+        obj.pretty_inspect.chomp
+      end
+
+      def assert_file
+        AssertFile
+      end
+
+      FailDesc = proc do |status, message = "", out = ""|
+        now = Time.now
+        proc do
+          EnvUtil.failure_description(status, now, message, out)
+        end
+      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)
+        desc = FailDesc[status, message, stderr]
+        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(desc) 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
+
+      if defined?(RubyVM::InstructionSequence)
+        def syntax_check(code, fname, line)
+          code = code.dup.force_encoding(Encoding::UTF_8)
+          RubyVM::InstructionSequence.compile(code, fname, fname, line)
+          :ok
+        ensure
+          raise if SyntaxError === $!
+        end
+      else
+        def syntax_check(code, fname, line)
+          code = code.b
+          code.sub!(/\A(?:\xef\xbb\xbf)?(\s*\#.*$)*(\n)?/n) {
+            "#$&#{"\n" if $1 && !$2}BEGIN{throw tag, :ok}\n"
+          }
+          code = code.force_encoding(Encoding::UTF_8)
+          catch {|tag| eval(code, binding, fname, line - 1)}
+        end
+      end
+
+      def assert_no_memory_leak(args, prepare, code, message=nil, limit: 2.0, rss: false, **opt)
+        # TODO: consider choosing some appropriate limit for MJIT and stop skipping this once it does not randomly fail
+        pend 'assert_no_memory_leak may consider MJIT memory usage as leak' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled?
+
+        require_relative '../../memory_status'
+        raise MiniTest::Skip, "unsupported platform" unless defined?(Memory::Status)
+
+        token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m"
+        token_dump = token.dump
+        token_re = Regexp.quote(token)
+        envs = args.shift if Array === args and Hash === args.first
+        args = [
+          "--disable=gems",
+          "-r", File.expand_path("../../../memory_status", __FILE__),
+          *args,
+          "-v", "-",
+        ]
+        if defined? Memory::NO_MEMORY_LEAK_ENVS then
+          envs ||= {}
+          newenvs = envs.merge(Memory::NO_MEMORY_LEAK_ENVS) { |_, _, _| break }
+          envs = newenvs if newenvs
+        end
+        args.unshift(envs) if envs
+        cmd = [
+          'END {STDERR.puts '"#{token_dump}"'"FINAL=#{Memory::Status.new}"}',
+          prepare,
+          'STDERR.puts('"#{token_dump}"'"START=#{$initial_status = Memory::Status.new}")',
+          '$initial_size = $initial_status.size',
+          code,
+          'GC.start',
+        ].join("\n")
+        _, err, status = EnvUtil.invoke_ruby(args, cmd, true, true, **opt)
+        before = err.sub!(/^#{token_re}START=(\{.*\})\n/, '') && Memory::Status.parse($1)
+        after = err.sub!(/^#{token_re}FINAL=(\{.*\})\n/, '') && Memory::Status.parse($1)
+        assert(status.success?, FailDesc[status, message, err])
+        ([:size, (rss && :rss)] & after.members).each do |n|
+          b = before[n]
+          a = after[n]
+          next unless a > 0 and b > 0
+          assert_operator(a.fdiv(b), :<, limit, message(message) {"#{n}: #{b} => #{a}"})
+        end
+      rescue LoadError
+        pend
+      end
+
+      # :call-seq:
+      #   assert_nothing_raised( *args, &block )
+      #
+      #If any exceptions are given as arguments, the assertion will
+      #fail if one of those exceptions are raised. Otherwise, the test fails
+      #if any exceptions are raised.
+      #
+      #The final argument may be a failure message.
+      #
+      #    assert_nothing_raised RuntimeError do
+      #      raise Exception #Assertion passes, Exception is not a RuntimeError
+      #    end
+      #
+      #    assert_nothing_raised do
+      #      raise Exception #Assertion fails
+      #    end
+      def assert_nothing_raised(*args)
+        self._assertions += 1
+        if Module === args.last
+          msg = nil
+        else
+          msg = args.pop
+        end
+        begin
+          line = __LINE__; yield
+        rescue MiniTest::Skip
+          raise
+        rescue Exception => e
+          bt = e.backtrace
+          as = e.instance_of?(MiniTest::Assertion)
+          if as
+            ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
+            bt.reject! {|ln| ans =~ ln}
+          end
+          if ((args.empty? && !as) ||
+              args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
+            msg = message(msg) {
+              "Exception raised:\n<#{mu_pp(e)}>\n" +
+              "Backtrace:\n" +
+              e.backtrace.map{|frame| "  #{frame}"}.join("\n")
+            }
+            raise MiniTest::Assertion, msg.call, bt
+          else
+            raise
+          end
+        end
+      end
+
+      def prepare_syntax_check(code, fname = nil, mesg = nil, verbose: nil)
+        fname ||= caller_locations(2, 1)[0]
+        mesg ||= fname.to_s
+        verbose, $VERBOSE = $VERBOSE, verbose
+        case
+        when Array === fname
+          fname, line = *fname
+        when defined?(fname.path) && defined?(fname.lineno)
+          fname, line = fname.path, fname.lineno
+        else
+          line = 1
+        end
+        yield(code, fname, line, message(mesg) {
+                if code.end_with?("\n")
+                  "```\n#{code}```\n"
+                else
+                  "```\n#{code}\n```\n""no-newline"
+                end
+              })
+      ensure
+        $VERBOSE = verbose
+      end
+
+      def assert_valid_syntax(code, *args, **opt)
+        prepare_syntax_check(code, *args, **opt) do |src, fname, line, mesg|
+          yield if defined?(yield)
+          assert_nothing_raised(SyntaxError, mesg) do
+            assert_equal(:ok, syntax_check(src, fname, line), mesg)
+          end
+        end
+      end
+
+      def assert_normal_exit(testsrc, message = '', child_env: nil, **opt)
+        assert_valid_syntax(testsrc, caller_locations(1, 1)[0])
+        if child_env
+          child_env = [child_env]
+        else
+          child_env = []
+        end
+        out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, **opt)
+        assert !status.signaled?, FailDesc[status, message, out]
+      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]
+    (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]