From 00db7dd1f1730ded2d493fd11d31f63807534393 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 19 Jul 2026 12:34:27 -0400 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Fix=20JRuby=20local=20backtrace=20t?= =?UTF-8?q?est=20assertions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bug was fixed in jruby-head, but that may not be in current releases: * JRuby Issue: jruby/jruby#9528 * Fixed by: jruby/jruby#9528 With that issue fixed, these tests don't need to be marked pending! 😄 BUT, JRuby _does_ still have some incongruity between `caller(1)` and `raise rescue $!.backtrace[1..]`. Some ruby block stack frames in `caller` are replaced by java stack frames in `Exception#backtrace`. For example: ```diff --- Kernel#caller +++ Exception#backtrace /home/nick/.local/share/rubies/jruby-dev/lib/ruby/gems/shared/gems/test-unit-3.7.8/lib/test/unit/testcase.rb:632:in 'block in run' - /home/nick/.local/share/rubies/jruby-dev/lib/ruby/gems/shared/gems/test-unit-3.7.8/lib/test/unit/testcase.rb:631:in 'catch' + org/jruby/RubyKernel.java:1604:in 'catch' + org/jruby/RubyKernel.java:1599:in 'catch' /home/nick/.local/share/rubies/jruby-dev/lib/ruby/gems/shared/gems/test-unit-3.7.8/lib/test/unit/testcase.rb:631:in 'run' ``` The workaround is relatively simple: use a locally generated exception to generate the stack frames for comparison. --- test/lib/helper.rb | 17 +++++++++++++++-- test/net/imap/test_imap_tls.rb | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test/lib/helper.rb b/test/lib/helper.rb index fe11727d..e52a1e19 100644 --- a/test/lib/helper.rb +++ b/test/lib/helper.rb @@ -224,11 +224,24 @@ def assert_local_raise(expected, message = nil) else assert_raise(expected, &block) end - stack = caller - assert_equal stack, error.backtrace&.last(stack.size) + assert_local_backtrace error error end + # Asserts that +error+ was raised in the same thread as +caller+ _and_ was + # called from the same level as +caller+. The caller's own frame is ignored, + # as are all extra frames in +error+, but the remaining frames much match. + # + # NOTE: `stack = caller(2)` is different from `$!.backtrace[2..]` in JRuby. + # Rather than use `caller`, this raises a local exception to use its backtrace + # for the comparison. + def assert_local_backtrace(error) + local_stack = raise "generating local backtrace" rescue $!.backtrace[2..] + error_stack = error.backtrace&.last(local_stack.size) + assert_equal local_stack, error_stack + error_stack + end + # Combines +assert_local_raise+ with an assertion that the exception's cause # is in the receiver thread. # diff --git a/test/net/imap/test_imap_tls.rb b/test/net/imap/test_imap_tls.rb index 052c114e..0fbceed8 100644 --- a/test/net/imap/test_imap_tls.rb +++ b/test/net/imap/test_imap_tls.rb @@ -110,7 +110,7 @@ def test_starttls_unknown_ca imap end assert_kind_of(OpenSSL::SSL::SSLError, ex) - assert_equal (stack = caller), ex.backtrace&.last(stack.size) + assert_local_backtrace ex assert_equal false, imap.tls_verified? assert_equal({}, imap.ssl_ctx_params) assert_equal(nil, imap.ssl_ctx.ca_file)