From 11ea26ebccd7add1bff18335e3d62ba5a3c27947 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 20 Aug 2026 10:48:33 +0900 Subject: [PATCH 1/5] Add tests --- .github/workflows/ci.yml | 57 ++++++++++++++++++++++++++++++++++++ Rakefile | 8 +++++ test/test_core_assertions.rb | 46 +++++++++++++++++++++++++++++ test/test_envutil.rb | 30 +++++++++++++++++++ test/test_find_executable.rb | 26 ++++++++++++++++ test/test_memory_status.rb | 23 +++++++++++++++ 6 files changed, 190 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 test/test_core_assertions.rb create mode 100644 test/test_envutil.rb create mode 100644 test/test_find_executable.rb create mode 100644 test/test_memory_status.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..30afca6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI + +on: +- push +- pull_request + +jobs: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 2.3 + + host: + needs: ruby-versions + name: ${{ matrix.os }} ${{ matrix.ruby }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: + - ubuntu-latest + - macos-latest + - windows-latest + include: + - { os: macos-15-intel, ruby: 2.3 } + - { os: macos-15-intel, ruby: 2.4 } + - { os: macos-15-intel, ruby: 2.5 } + - { os: windows-latest, ruby: mingw } + - { os: windows-latest, ruby: mswin } + exclude: + - { os: macos-latest, ruby: 2.3 } + - { os: macos-latest, ruby: 2.4 } + - { os: macos-latest, ruby: 2.5 } + - { os: windows-latest, ruby: head } + + steps: + - uses: actions/checkout@v7 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - run: bundle exec rake test + + - run: bundle exec rake build + + - uses: actions/upload-artifact@v7 + if: >- + matrix.os == 'ubuntu-latest' && + (matrix.ruby == needs.ruby-versions.outputs.latest) + with: + name: gem + path: pkg/ diff --git a/Rakefile b/Rakefile index 82376c5..c8e7c0b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,14 @@ # frozen_string_literal: true require "bundler/gem_tasks" +require "rake/testtask" + +Rake::TestTask.new do |test| + test.libs << "lib" + test.pattern = "test/**/test_*.rb" +end + +task default: :test task :sync_tool do require 'fileutils' diff --git a/test/test_core_assertions.rb b/test/test_core_assertions.rb new file mode 100644 index 0000000..8293c81 --- /dev/null +++ b/test/test_core_assertions.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "test/unit" +require "core_assertions" + +class TestCoreAssertions < Test::Unit::TestCase + include Test::Unit::CoreAssertions + + def test_backtrace_filter_handles_missing_backtrace + assert_equal(["No backtrace"], Test.filter_backtrace(nil)) + end + + def test_backtrace_filter_removes_internal_entries + backtrace = [ + "/tmp/example.rb:1:in `run'", + "/tmp/lib/test/unit.rb:2:in `assert'", + ] + + assert_equal([backtrace.first], Test.filter_backtrace(backtrace)) + end + + def test_message_adds_sentence_endings + object = Object.new + object.extend(Test::Unit::Assertions) + + message = object.message("details") { "default" } + + assert_equal("details.\ndefault.", message.call) + end + + def test_assert_separately_runs_assertions_in_child_ruby + assert_separately([], <<~RUBY) + assert_equal(4, 2 + 2) + RUBY + end + + def test_assert_separately_propagates_child_failure + error = assert_raise(Test::Unit::AssertionFailedError) do + assert_separately([], <<~RUBY) + assert_equal(:expected, :actual) + RUBY + end + + assert_match(/expected/, error.message) + end +end diff --git a/test/test_envutil.rb b/test/test_envutil.rb new file mode 100644 index 0000000..806df6a --- /dev/null +++ b/test/test_envutil.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "test/unit" +require "envutil" + +class TestEnvUtil < Test::Unit::TestCase + def test_rubybin_points_to_a_ruby_executable + assert(File.executable?(EnvUtil.rubybin)) + end + + def test_apply_timeout_scale + original_scale = EnvUtil.timeout_scale + EnvUtil.timeout_scale = 2.5 + + assert_equal(5.0, EnvUtil.apply_timeout_scale(2)) + ensure + EnvUtil.timeout_scale = original_scale + end + + def test_invoke_ruby_captures_output_and_status + stdout, stderr, status = EnvUtil.invoke_ruby( + ["-e", "STDOUT.print('out'); STDERR.print('err')"], + "", true, true + ) + + assert_equal("out", stdout) + assert_equal("err", stderr) + assert_predicate(status, :success?) + end +end diff --git a/test/test_find_executable.rb b/test/test_find_executable.rb new file mode 100644 index 0000000..277279a --- /dev/null +++ b/test/test_find_executable.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "test/unit" +require "rbconfig" +require "find_executable" + +class TestFindExecutable < Test::Unit::TestCase + def test_find_executable_returns_command_and_arguments + ruby = RbConfig.ruby + command = File.basename(ruby, RbConfig::CONFIG["EXEEXT"]) + original_path = ENV["PATH"] + ENV["PATH"] = File.dirname(ruby) + + found = EnvUtil.find_executable(command, "--version") do |output| + output.start_with?("ruby ") + end + + assert_equal([ruby, "--version"], found) + ensure + ENV["PATH"] = original_path + end + + def test_find_executable_returns_nil_for_unknown_command + assert_nil(EnvUtil.find_executable("test-unit-ruby-core-missing") { true }) + end +end diff --git a/test/test_memory_status.rb b/test/test_memory_status.rb new file mode 100644 index 0000000..53830e9 --- /dev/null +++ b/test/test_memory_status.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "test/unit" +require "memory_status" + +class TestMemoryStatus < Test::Unit::TestCase + def setup + omit("memory status is unsupported") unless defined?(Memory::Status) + end + + def test_status_reports_numeric_values + status = Memory::Status.new + + assert(status.members.any? { |member| status[member].to_i > 0 }) + assert_match(/\A\{[^}]+:\d+(?:,[^}]+:\d+)*\}\z/, status.to_s) + end + + def test_parse_round_trips_status + status = Memory::Status.new + + assert_equal(status, Memory::Status.parse(status.to_s)) + end +end From 434734d9bbc76d14235a0d10d8b6dde98edbba5d Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 20 Aug 2026 10:49:16 +0900 Subject: [PATCH 2/5] Fix errors on ruby 2.6 or earliers --- lib/core_assertions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core_assertions.rb b/lib/core_assertions.rb index 2d26792..475d768 100644 --- a/lib/core_assertions.rb +++ b/lib/core_assertions.rb @@ -327,8 +327,8 @@ def separated_runner(token, out = nil) at_exit { assertions = assertions_ivar_get.call(:@_assertions) out_write.call <<~OUT - - #{array_pack.bind_call([marshal_dump.call($!)], 'm0')} + + #{array_pack.bind([marshal_dump.call($!)]).call('m0')} OUT } From 11c19e865bf64908b302a8d218feed1d54916bc5 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 20 Aug 2026 12:17:41 +0900 Subject: [PATCH 3/5] Use `Regexp#=~` for ruby 2.3 `Regexp#match?` was introduced at ruby 2.4. --- lib/core_assertions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core_assertions.rb b/lib/core_assertions.rb index 475d768..befe2b2 100644 --- a/lib/core_assertions.rb +++ b/lib/core_assertions.rb @@ -18,11 +18,11 @@ def filter bt unless $DEBUG then bt.each do |line| - break if pattern.match?(line) + break if pattern =~ line new_bt << line end - new_bt = bt.reject { |line| pattern.match?(line) } if new_bt.empty? + new_bt = bt.reject { |line| pattern =~ line } if new_bt.empty? new_bt = bt.dup if new_bt.empty? else new_bt = bt.dup From cf868e0247699a8ce87179b21c9d0cf69b183210 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 10 Nov 2025 15:59:18 +0900 Subject: [PATCH 4/5] assert_separately: Suppress experimental warnings test-unit depends on power_assert that the recent versions require ruby 3.1 or later. While test-unit rescues syntax error at loading power_assert for old ruby versions, warnings for experimental features are not suppressed, and `assert_separately` fails because stderr is not empty, by default. Since adding `required_ruby_version` to power_assert causes the installation with old rubygems to fail, we just ignore warnings for experimental features totally. ruby/ruby@0ca3eed109c42711ac66d65637724045c280def3 --- lib/core_assertions.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core_assertions.rb b/lib/core_assertions.rb index befe2b2..30b25dd 100644 --- a/lib/core_assertions.rb +++ b/lib/core_assertions.rb @@ -364,6 +364,8 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o args = args.dup args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"}) args << "--debug" if RUBY_ENGINE == 'jruby' # warning: tracing (e.g. set_trace_func) will not capture all events without --debug flag + # power_assert 3 requires ruby 3.1 or later + args << "-W:no-experimental" if RUBY_VERSION < "3.1." stdout, stderr, status = EnvUtil.invoke_ruby(args, src, capture_stdout, true, **opt) if sanitizers&.lsan_enabled? From c53dddaa9ca6341b6a7417381a06d3f048997a2a Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 20 Aug 2026 14:27:08 +0900 Subject: [PATCH 5/5] Fix for rubies older than 2.7 --- lib/core_assertions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core_assertions.rb b/lib/core_assertions.rb index 30b25dd..cd6cd1d 100644 --- a/lib/core_assertions.rb +++ b/lib/core_assertions.rb @@ -365,7 +365,7 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"}) args << "--debug" if RUBY_ENGINE == 'jruby' # warning: tracing (e.g. set_trace_func) will not capture all events without --debug flag # power_assert 3 requires ruby 3.1 or later - args << "-W:no-experimental" if RUBY_VERSION < "3.1." + args << "-W:no-experimental" if ("2.7."..."3.1.").cover?(RUBY_VERSION) stdout, stderr, status = EnvUtil.invoke_ruby(args, src, capture_stdout, true, **opt) if sanitizers&.lsan_enabled?