[BUG #20655] Add tests to use rb_ensure and call cont.call

This commit is contained in:
Satoshi Tagomori 2024-07-29 11:21:22 +09:00 committed by Yusuke Endoh
parent b3baa11ee9
commit c884db0b5b
Notes: git 2024-07-30 06:31:44 +00:00
4 changed files with 90 additions and 0 deletions

View File

@ -0,0 +1,39 @@
#include "ruby.h"
struct require_data {
VALUE obj;
VALUE fname;
};
static VALUE
call_require(VALUE arg)
{
struct require_data *data = (struct require_data *)arg;
rb_f_require(data->obj, data->fname);
return Qnil;
}
static VALUE
call_ensure(VALUE _)
{
VALUE v = rb_gv_get("$ensure_called");
int called = FIX2INT(v) + 1;
rb_gv_set("$ensure_called", INT2FIX(called));
return Qnil;
}
static VALUE
require_with_ensure(VALUE self, VALUE fname)
{
struct require_data data = {
.obj = self,
.fname = fname
};
return rb_ensure(call_require, (VALUE)&data, call_ensure, Qnil);
}
void
Init_ensure_and_callcc(void)
{
rb_define_method(rb_mKernel, "require_with_ensure", require_with_ensure, 1);
}

View File

@ -0,0 +1,5 @@
# frozen_string_literal: false
require "mkmf"
require_relative "../auto_ext.rb"
auto_ext(inc: true)

10
test/-ext-/required.rb Normal file
View File

@ -0,0 +1,10 @@
require 'continuation'
cont = nil
a = [*1..10].reject do |i|
callcc {|c| cont = c} if !cont and i == 10
false
end
if a.size < 1000
a.unshift(:x)
cont.call
end

View File

@ -0,0 +1,36 @@
# -*- coding: us-ascii -*-
# frozen_string_literal: false
require 'test/unit'
class TestEnsureAndCallcc < Test::Unit::TestCase
require '-test-/ensure_and_callcc'
def test_bug20655_dir_chdir_using_rb_ensure
need_continuation
called = 0
tmp = nil
Dir.chdir('/tmp') do
tmp = Dir.pwd
cont = nil
callcc{|c| cont = c}
assert_equal(tmp, Dir.pwd, "BUG #20655: ensure called and pwd was changed unexpectedly")
called += 1
cont.call if called < 10
end
end
def test_bug20655_extension_using_rb_ensure
need_continuation
$ensure_called = 0
require_with_ensure(File.join(__dir__, 'required'))
assert_equal(1, $ensure_called, "BUG #20655: ensure called unexpectedly in the required script even without exceptions")
end
private
def need_continuation
unless respond_to?(:callcc, true)
EnvUtil.suppress_warning {require 'continuation'}
end
omit 'requires callcc support' unless respond_to?(:callcc, true)
end
end