summaryrefslogtreecommitdiff
path: root/spec/ruby/optional/capi
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/optional/capi')
-rw-r--r--spec/ruby/optional/capi/array_spec.rb48
-rw-r--r--spec/ruby/optional/capi/digest_spec.rb6
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb8
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb20
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/digest_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/exception_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h4
-rw-r--r--spec/ruby/optional/capi/ext/set_spec.c65
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c1
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c4
-rw-r--r--spec/ruby/optional/capi/globals_spec.rb13
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb30
-rw-r--r--spec/ruby/optional/capi/module_spec.rb2
-rw-r--r--spec/ruby/optional/capi/object_spec.rb10
-rw-r--r--spec/ruby/optional/capi/regexp_spec.rb2
-rw-r--r--spec/ruby/optional/capi/set_spec.rb96
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb10
-rw-r--r--spec/ruby/optional/capi/string_spec.rb58
-rw-r--r--spec/ruby/optional/capi/struct_spec.rb74
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb2
24 files changed, 416 insertions, 77 deletions
diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb
index 9c35017e21..7e87859856 100644
--- a/spec/ruby/optional/capi/array_spec.rb
+++ b/spec/ruby/optional/capi/array_spec.rb
@@ -343,37 +343,39 @@ describe "C-API Array function" do
end
end
- describe "rb_iterate" do
- it "calls an callback function as a block passed to an method" do
- s = [1,2,3,4]
- s2 = @s.rb_iterate(s)
+ ruby_version_is ""..."4.0" do
+ describe "rb_iterate" do
+ it "calls an callback function as a block passed to an method" do
+ s = [1,2,3,4]
+ s2 = @s.rb_iterate(s)
- s2.should == s
+ s2.should == s
- # Make sure they're different objects
- s2.equal?(s).should be_false
- end
+ # Make sure they're different objects
+ s2.equal?(s).should be_false
+ end
- it "calls a function with the other function available as a block" do
- h = {a: 1, b: 2}
+ it "calls a function with the other function available as a block" do
+ h = {a: 1, b: 2}
- @s.rb_iterate_each_pair(h).sort.should == [1,2]
- end
+ @s.rb_iterate_each_pair(h).sort.should == [1,2]
+ end
- it "calls a function which can yield into the original block" do
- s2 = []
+ it "calls a function which can yield into the original block" do
+ s2 = []
- o = Object.new
- def o.each
- yield 1
- yield 2
- yield 3
- yield 4
- end
+ o = Object.new
+ def o.each
+ yield 1
+ yield 2
+ yield 3
+ yield 4
+ end
- @s.rb_iterate_then_yield(o) { |x| s2 << x }
+ @s.rb_iterate_then_yield(o) { |x| s2 << x }
- s2.should == [1,2,3,4]
+ s2.should == [1,2,3,4]
+ end
end
end
diff --git a/spec/ruby/optional/capi/digest_spec.rb b/spec/ruby/optional/capi/digest_spec.rb
index c753733906..65c5ecebb1 100644
--- a/spec/ruby/optional/capi/digest_spec.rb
+++ b/spec/ruby/optional/capi/digest_spec.rb
@@ -1,6 +1,10 @@
require_relative 'spec_helper'
-require 'fiddle'
+begin
+ require 'fiddle'
+rescue LoadError
+ return
+end
load_extension('digest')
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index 0c3c98a5c0..c14983c7ea 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -724,14 +724,16 @@ describe "C-API Encoding function" do
end
describe "rb_define_dummy_encoding" do
+ run = 0
+
it "defines the dummy encoding" do
- @s.rb_define_dummy_encoding("FOO")
- enc = Encoding.find("FOO")
+ @s.rb_define_dummy_encoding("FOO#{run += 1}")
+ enc = Encoding.find("FOO#{run}")
enc.should.dummy?
end
it "returns the index of the dummy encoding" do
- index = @s.rb_define_dummy_encoding("BAR")
+ index = @s.rb_define_dummy_encoding("BAR#{run += 1}")
index.should == Encoding.list.size - 1
end
diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb
index 5bb60608b2..5bc8e26c62 100644
--- a/spec/ruby/optional/capi/exception_spec.rb
+++ b/spec/ruby/optional/capi/exception_spec.rb
@@ -100,6 +100,26 @@ describe "C-API Exception function" do
end
end
+ describe "rb_error_frozen_object" do
+ it "raises a FrozenError regardless of the object's frozen state" do
+ # The type of the argument we supply doesn't matter. The choice here is arbitrary and we only change the type
+ # of the argument to ensure the exception messages are set correctly.
+ -> { @s.rb_error_frozen_object(Array.new) }.should raise_error(FrozenError, "can't modify frozen Array: []")
+ -> { @s.rb_error_frozen_object(Array.new.freeze) }.should raise_error(FrozenError, "can't modify frozen Array: []")
+ end
+
+ it "properly handles recursive rb_error_frozen_object calls" do
+ klass = Class.new(Object)
+ object = klass.new
+ s = @s
+ klass.define_method :inspect do
+ s.rb_error_frozen_object(object)
+ end
+
+ -> { @s.rb_error_frozen_object(object) }.should raise_error(FrozenError, "can't modify frozen #{klass}: ...")
+ end
+ end
+
describe "rb_syserr_new" do
it "returns system error with default message when passed message is NULL" do
exception = @s.rb_syserr_new(Errno::ENOENT::Errno, nil)
diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c
index 2347798bb4..628c4df9d7 100644
--- a/spec/ruby/optional/capi/ext/array_spec.c
+++ b/spec/ruby/optional/capi/ext/array_spec.c
@@ -196,6 +196,7 @@ static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) {
return rb_ary_push(new_ary, el);
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -203,6 +204,7 @@ static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
return new_ary;
}
+#endif
static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -216,6 +218,7 @@ static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) {
return rb_ary_push(holder, rb_ary_entry(el, 1));
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE each_pair(VALUE obj) {
return rb_funcall(obj, rb_intern("each_pair"), 0);
}
@@ -227,6 +230,7 @@ static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) {
return new_ary;
}
+#endif
static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) {
VALUE new_ary = rb_ary_new();
@@ -241,10 +245,12 @@ static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) {
return Qnil;
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) {
rb_iterate(rb_each, obj, iter_yield, obj);
return Qnil;
}
+#endif
static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) {
rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj);
@@ -308,9 +314,11 @@ void Init_array_spec(void) {
rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2);
rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2);
rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2);
+#ifndef RUBY_VERSION_IS_4_0
rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1);
rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1);
rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1);
+#endif
rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1);
rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1);
rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1);
diff --git a/spec/ruby/optional/capi/ext/digest_spec.c b/spec/ruby/optional/capi/ext/digest_spec.c
index 9993238cf2..65c8defa20 100644
--- a/spec/ruby/optional/capi/ext/digest_spec.c
+++ b/spec/ruby/optional/capi/ext/digest_spec.c
@@ -135,7 +135,9 @@ VALUE digest_spec_context_size(VALUE self, VALUE meta) {
return SIZET2NUM(algo->ctx_size);
}
+#ifndef PTR2NUM
#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
+#endif
VALUE digest_spec_context(VALUE self, VALUE digest) {
return PTR2NUM(context);
diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c
index 0e8347ab0d..c3b94d7bcd 100644
--- a/spec/ruby/optional/capi/ext/exception_spec.c
+++ b/spec/ruby/optional/capi/ext/exception_spec.c
@@ -36,6 +36,13 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) {
return Qnil;
}
+NORETURN(VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object));
+
+VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object) {
+ rb_error_frozen_object(object);
+ UNREACHABLE_RETURN(Qnil);
+}
+
VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) {
int n = NUM2INT(num);
char *cstr = NULL;
@@ -66,6 +73,7 @@ void Init_exception_spec(void) {
rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1);
rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1);
rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1);
+ rb_define_method(cls, "rb_error_frozen_object", exception_spec_rb_error_frozen_object, 1);
rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2);
rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2);
rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1);
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index ff71a7e589..a8fed21b59 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -117,9 +117,11 @@ VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) {
return rb_eval_string(RSTRING_PTR(str));
}
+#ifndef RUBY_VERSION_IS_4_0
VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) {
return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat));
}
+#endif
VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) {
rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before")));
@@ -403,7 +405,9 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_category_warn_deprecated_with_integer_extra_value", kernel_spec_rb_category_warn_deprecated_with_integer_extra_value, 1);
rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4);
rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1);
+#ifndef RUBY_VERSION_IS_4_0
rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3);
+#endif
rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1);
rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1);
rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2);
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index eab0eb7534..995bc38fcf 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -383,6 +383,16 @@ static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) {
return allocator ? Qtrue : Qfalse;
}
+static VALUE object_spec_redefine_frozen(VALUE self) {
+ // The purpose of this spec is to verify that `frozen?`
+ // and `RB_OBJ_FROZEN` do not mutually recurse infinitely.
+ if (RB_OBJ_FROZEN(self)) {
+ return Qtrue;
+ }
+
+ return Qfalse;
+}
+
void Init_object_spec(void) {
VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject);
rb_define_method(cls, "FL_ABLE", object_spec_FL_ABLE, 1);
@@ -455,6 +465,9 @@ void Init_object_spec(void) {
rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
+
+ cls = rb_define_class("CApiObjectRedefinitionSpecs", rb_cObject);
+ rb_define_method(cls, "frozen?", object_spec_redefine_frozen, 0);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 8aaec36f46..6c4bea5da0 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -35,8 +35,8 @@
(RUBY_API_VERSION_MAJOR == (major) && RUBY_API_VERSION_MINOR < (minor)))
#define RUBY_VERSION_SINCE(major,minor) (!RUBY_VERSION_BEFORE(major, minor))
-#if RUBY_VERSION_SINCE(3, 5)
-#define RUBY_VERSION_IS_3_5
+#if RUBY_VERSION_SINCE(4, 0)
+#define RUBY_VERSION_IS_4_0
#endif
#if RUBY_VERSION_SINCE(3, 4)
diff --git a/spec/ruby/optional/capi/ext/set_spec.c b/spec/ruby/optional/capi/ext/set_spec.c
new file mode 100644
index 0000000000..11a271b361
--- /dev/null
+++ b/spec/ruby/optional/capi/ext/set_spec.c
@@ -0,0 +1,65 @@
+#include "ruby.h"
+#include "rubyspec.h"
+
+#ifdef RUBY_VERSION_IS_4_0
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RBOOL(x) ((x) ? Qtrue : Qfalse)
+
+int yield_element_and_arg(VALUE element, VALUE arg) {
+ return RTEST(rb_yield_values(2, element, arg)) ? ST_CONTINUE : ST_STOP;
+}
+
+VALUE set_spec_rb_set_foreach(VALUE self, VALUE set, VALUE arg) {
+ rb_set_foreach(set, yield_element_and_arg, arg);
+ return Qnil;
+}
+
+VALUE set_spec_rb_set_new(VALUE self) {
+ return rb_set_new();
+}
+
+VALUE set_spec_rb_set_new_capa(VALUE self, VALUE capa) {
+ return rb_set_new_capa(NUM2INT(capa));
+}
+
+VALUE set_spec_rb_set_lookup(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_lookup(set, element));
+}
+
+VALUE set_spec_rb_set_add(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_add(set, element));
+}
+
+VALUE set_spec_rb_set_clear(VALUE self, VALUE set) {
+ return rb_set_clear(set);
+}
+
+VALUE set_spec_rb_set_delete(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_delete(set, element));
+}
+
+VALUE set_spec_rb_set_size(VALUE self, VALUE set) {
+ return SIZET2NUM(rb_set_size(set));
+}
+
+void Init_set_spec(void) {
+ VALUE cls = rb_define_class("CApiSetSpecs", rb_cObject);
+
+ rb_define_method(cls, "rb_set_foreach", set_spec_rb_set_foreach, 2);
+ rb_define_method(cls, "rb_set_new", set_spec_rb_set_new, 0);
+ rb_define_method(cls, "rb_set_new_capa", set_spec_rb_set_new_capa, 1);
+ rb_define_method(cls, "rb_set_lookup", set_spec_rb_set_lookup, 2);
+ rb_define_method(cls, "rb_set_add", set_spec_rb_set_add, 2);
+ rb_define_method(cls, "rb_set_clear", set_spec_rb_set_clear, 1);
+ rb_define_method(cls, "rb_set_delete", set_spec_rb_set_delete, 2);
+ rb_define_method(cls, "rb_set_size", set_spec_rb_set_size, 1);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index b49bb3f267..094013e049 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -440,6 +440,7 @@ static VALUE string_spec_rb_str_free(VALUE self, VALUE str) {
static VALUE string_spec_rb_sprintf1(VALUE self, VALUE str, VALUE repl) {
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl));
}
+
static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE repl2) {
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2));
}
diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c
index 413249e828..756cfca8dd 100644
--- a/spec/ruby/optional/capi/ext/struct_spec.c
+++ b/spec/ruby/optional/capi/ext/struct_spec.c
@@ -62,6 +62,10 @@ static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) {
return rb_struct_size(st);
}
+static VALUE struct_spec_rb_struct_initialize(VALUE self, VALUE st, VALUE values) {
+ return rb_struct_initialize(st, values);
+}
+
#if defined(RUBY_VERSION_IS_3_3)
/* Only allow setting three attributes, should be sufficient for testing. */
static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass,
@@ -90,6 +94,7 @@ void Init_struct_spec(void) {
rb_define_method(cls, "rb_struct_define_under", struct_spec_rb_struct_define_under, 5);
rb_define_method(cls, "rb_struct_new", struct_spec_rb_struct_new, 4);
rb_define_method(cls, "rb_struct_size", struct_spec_rb_struct_size, 1);
+ rb_define_method(cls, "rb_struct_initialize", struct_spec_rb_struct_initialize, 2);
#if defined(RUBY_VERSION_IS_3_3)
rb_define_method(cls, "rb_data_define", struct_spec_rb_data_define, 4);
#endif
diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c
index 6ee111b7b7..ac77e4e813 100644
--- a/spec/ruby/optional/capi/ext/thread_spec.c
+++ b/spec/ruby/optional/capi/ext/thread_spec.c
@@ -166,7 +166,7 @@ static VALUE thread_spec_ruby_native_thread_p_new_thread(VALUE self) {
#endif
}
-#ifdef RUBY_VERSION_IS_3_5
+#ifdef RUBY_VERSION_IS_4_0
static VALUE thread_spec_ruby_thread_has_gvl_p(VALUE self) {
return ruby_thread_has_gvl_p() ? Qtrue : Qfalse;
}
@@ -185,7 +185,7 @@ void Init_thread_spec(void) {
rb_define_method(cls, "rb_thread_create", thread_spec_rb_thread_create, 2);
rb_define_method(cls, "ruby_native_thread_p", thread_spec_ruby_native_thread_p, 0);
rb_define_method(cls, "ruby_native_thread_p_new_thread", thread_spec_ruby_native_thread_p_new_thread, 0);
-#ifdef RUBY_VERSION_IS_3_5
+#ifdef RUBY_VERSION_IS_4_0
rb_define_method(cls, "ruby_thread_has_gvl_p", thread_spec_ruby_thread_has_gvl_p, 0);
#endif
}
diff --git a/spec/ruby/optional/capi/globals_spec.rb b/spec/ruby/optional/capi/globals_spec.rb
index 48677620bc..4657293e15 100644
--- a/spec/ruby/optional/capi/globals_spec.rb
+++ b/spec/ruby/optional/capi/globals_spec.rb
@@ -41,14 +41,19 @@ describe "CApiGlobalSpecs" do
@f.sb_get_global_value.should == "XYZ"
end
+ run = 0
+
it "rb_define_readonly_variable should define a new readonly global variable" do
+ name = "ro_gvar#{run += 1}"
+ eval <<~RUBY
# Check the gvar doesn't exist and ensure rb_gv_get doesn't implicitly declare the gvar,
# otherwise the rb_define_readonly_variable call will conflict.
- suppress_warning { @f.sb_gv_get("ro_gvar") } .should == nil
+ suppress_warning { @f.sb_gv_get("#{name}") }.should == nil
- @f.rb_define_readonly_variable("ro_gvar", 15)
- $ro_gvar.should == 15
- -> { $ro_gvar = 10 }.should raise_error(NameError)
+ @f.rb_define_readonly_variable("#{name}", 15)
+ $#{name}.should == 15
+ -> { $#{name} = 10 }.should raise_error(NameError)
+ RUBY
end
it "rb_define_hooked_variable should define a C hooked global variable" do
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index d915a72c22..6633ee50c1 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -635,22 +635,24 @@ describe "C-API Kernel function" do
end
end
- describe "rb_eval_cmd_kw" do
- it "evaluates a string of ruby code" do
- @s.rb_eval_cmd_kw("1+1", [], 0).should == 2
- end
+ ruby_version_is ""..."4.0" do
+ describe "rb_eval_cmd_kw" do
+ it "evaluates a string of ruby code" do
+ @s.rb_eval_cmd_kw("1+1", [], 0).should == 2
+ end
- it "calls a proc with the supplied arguments" do
- @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8]
- end
+ it "calls a proc with the supplied arguments" do
+ @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8]
+ end
- it "calls a proc with keyword arguments if kw_splat is non zero" do
- a_proc = -> *x, **y {
- res = x.map { |i| i + 1 }
- y.each { |k, v| res << k; res << v }
- res
- }
- @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3]
+ it "calls a proc with keyword arguments if kw_splat is non zero" do
+ a_proc = -> *x, **y {
+ res = x.map { |i| i + 1 }
+ y.each { |k, v| res << k; res << v }
+ res
+ }
+ @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3]
+ end
end
end
diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb
index b7684e566b..af39ec0192 100644
--- a/spec/ruby/optional/capi/module_spec.rb
+++ b/spec/ruby/optional/capi/module_spec.rb
@@ -38,7 +38,7 @@ describe "CApiModule" do
CApiModuleSpecs::C.const_set(:_INVALID, 1)
}.should raise_error(NameError, /wrong constant name/)
- @m.rb_const_set(CApiModuleSpecs::C, :_INVALID, 2)
+ suppress_warning { @m.rb_const_set(CApiModuleSpecs::C, :_INVALID, 2) }
@m.rb_const_get(CApiModuleSpecs::C, :_INVALID).should == 2
# Ruby-level should still not allow access
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index 27faecbb49..8b4d8a9bba 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -691,6 +691,16 @@ describe "CApiObject" do
end
end
+ describe "redefining frozen? works" do
+ it "allows an object to override frozen?" do
+ obj = CApiObjectRedefinitionSpecs.new
+
+ obj.frozen?.should == false
+ obj.freeze
+ obj.frozen?.should == true
+ end
+ end
+
describe "rb_obj_taint" do
end
diff --git a/spec/ruby/optional/capi/regexp_spec.rb b/spec/ruby/optional/capi/regexp_spec.rb
index 4b130ff66a..49ac79f5c4 100644
--- a/spec/ruby/optional/capi/regexp_spec.rb
+++ b/spec/ruby/optional/capi/regexp_spec.rb
@@ -110,7 +110,7 @@ describe "C-API Regexp function" do
end
end
- describe "rb_memicmp" do
+ describe "rb_memcicmp" do
it "returns 0 for identical strings" do
@p.rb_memcicmp('Hello', 'Hello').should == 0
end
diff --git a/spec/ruby/optional/capi/set_spec.rb b/spec/ruby/optional/capi/set_spec.rb
new file mode 100644
index 0000000000..3e35be0505
--- /dev/null
+++ b/spec/ruby/optional/capi/set_spec.rb
@@ -0,0 +1,96 @@
+require_relative 'spec_helper'
+
+ruby_version_is "4.0" do
+ load_extension("set")
+
+ describe "C-API Set function" do
+ before :each do
+ @s = CApiSetSpecs.new
+ end
+
+ describe "rb_set_foreach" do
+ it "calls function with each element and arg" do
+ a = []
+ @s.rb_set_foreach(Set[1, 2], 3) {|*args| a.concat(args) }
+ a.should == [1, 3, 2, 3]
+ end
+
+ it "respects function return value" do
+ a = []
+ @s.rb_set_foreach(Set[1, 2], 3) do |*args|
+ a.concat(args)
+ false
+ end
+ a.should == [1, 3]
+ end
+ end
+
+ describe "rb_set_new" do
+ it "returns a new set" do
+ @s.rb_set_new.should == Set[]
+ end
+ end
+
+ describe "rb_set_new_capa" do
+ it "returns a new set" do
+ @s.rb_set_new_capa(3).should == Set[]
+ end
+ end
+
+ describe "rb_set_lookup" do
+ it "returns whether the element is in the set" do
+ set = Set[1]
+ @s.rb_set_lookup(set, 1).should == true
+ @s.rb_set_lookup(set, 2).should == false
+ end
+ end
+
+ describe "rb_set_add" do
+ it "adds element to set" do
+ set = Set[]
+ @s.rb_set_add(set, 1).should == true
+ set.should == Set[1]
+ @s.rb_set_add(set, 2).should == true
+ set.should == Set[1, 2]
+ end
+
+ it "returns false if element is already in set" do
+ set = Set[1]
+ @s.rb_set_add(set, 1).should == false
+ set.should == Set[1]
+ end
+ end
+
+ describe "rb_set_clear" do
+ it "empties and returns self" do
+ set = Set[1]
+ @s.rb_set_clear(set).should equal(set)
+ set.should == Set[]
+ end
+ end
+
+ describe "rb_set_delete" do
+ it "removes element from set" do
+ set = Set[1, 2]
+ @s.rb_set_delete(set, 1).should == true
+ set.should == Set[2]
+ @s.rb_set_delete(set, 2).should == true
+ set.should == Set[]
+ end
+
+ it "returns false if element is not already in set" do
+ set = Set[2]
+ @s.rb_set_delete(set, 1).should == false
+ set.should == Set[2]
+ end
+ end
+
+ describe "rb_set_size" do
+ it "returns number of elements in set" do
+ @s.rb_set_size(Set[]).should == 0
+ @s.rb_set_size(Set[1]).should == 1
+ @s.rb_set_size(Set[1,2]).should == 2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb
index 1076b206ec..e7abf46e6c 100644
--- a/spec/ruby/optional/capi/spec_helper.rb
+++ b/spec/ruby/optional/capi/spec_helper.rb
@@ -122,13 +122,9 @@ def setup_make
opts = {}
if /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ make_flags
- begin
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- rescue Errno::EBADF
- else
- opts[r] = r
- opts[w] = w
+ [$1, $2].each do |fd|
+ fd = fd.to_i(10)
+ opts[fd] = fd
end
end
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 715f76eaea..72f20ee6a5 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -191,11 +191,19 @@ describe "C-API String function" do
end
it "returns a new String object filled with \\0 bytes" do
- s = @s.rb_str_tmp_new(4)
- s.encoding.should == Encoding::BINARY
- s.bytesize.should == 4
- s.size.should == 4
- s.should == "\x00\x00\x00\x00"
+ lens = [4]
+
+ ruby_version_is "4.0" do
+ lens << 100
+ end
+
+ lens.each do |len|
+ s = @s.rb_str_tmp_new(len)
+ s.encoding.should == Encoding::BINARY
+ s.bytesize.should == len
+ s.size.should == len
+ s.should == "\x00" * len
+ end
end
end
@@ -1045,6 +1053,16 @@ describe "C-API String function" do
@s.rb_sprintf4(true.class).should == s
end
+ it "formats nil using to_s if sign not specified in format" do
+ s = 'Result: .'
+ @s.rb_sprintf3(nil).should == s
+ end
+
+ it "formats nil using inspect if sign specified in format" do
+ s = 'Result: nil.'
+ @s.rb_sprintf4(nil).should == s
+ end
+
it "truncates a string to a supplied precision if that is shorter than the string" do
s = 'Result: Hel.'
@s.rb_sprintf5(0, 3, "Hello").should == s
@@ -1201,28 +1219,50 @@ describe "C-API String function" do
describe "rb_str_locktmp" do
it "raises an error when trying to lock an already locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
-> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
end
it "locks a string so that modifications would raise an error" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
-> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_locktmp(str) }.should raise_error(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_locktmp(str) }.should raise_error(FrozenError)
+ end
+ end
end
describe "rb_str_unlocktmp" do
it "unlocks a locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str)
@s.rb_str_unlocktmp(str).should == str
str.upcase!.should == "TEST"
end
it "raises an error when trying to unlock an already unlocked string" do
- -> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
+ -> { @s.rb_str_unlocktmp(+"test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
+ end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_unlocktmp(str) }.should raise_error(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_unlocktmp(str) }.should raise_error(FrozenError)
+ end
end
end
diff --git a/spec/ruby/optional/capi/struct_spec.rb b/spec/ruby/optional/capi/struct_spec.rb
index 474c397956..cc8d7f932e 100644
--- a/spec/ruby/optional/capi/struct_spec.rb
+++ b/spec/ruby/optional/capi/struct_spec.rb
@@ -208,20 +208,48 @@ describe "C-API Struct function" do
@s.rb_struct_size(@struct).should == 3
end
end
+
+ describe "rb_struct_initialize" do
+ it "sets all members" do
+ @s.rb_struct_initialize(@struct, [1, 2, 3]).should == nil
+ @struct.a.should == 1
+ @struct.b.should == 2
+ @struct.c.should == 3
+ end
+
+ it "does not freeze the Struct instance" do
+ @s.rb_struct_initialize(@struct, [1, 2, 3]).should == nil
+ @struct.should_not.frozen?
+ @s.rb_struct_initialize(@struct, [4, 5, 6]).should == nil
+ @struct.a.should == 4
+ @struct.b.should == 5
+ @struct.c.should == 6
+ end
+
+ it "raises ArgumentError if too many values" do
+ -> { @s.rb_struct_initialize(@struct, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs")
+ end
+
+ it "treats missing values as nil" do
+ @s.rb_struct_initialize(@struct, [1, 2]).should == nil
+ @struct.a.should == 1
+ @struct.b.should == 2
+ @struct.c.should == nil
+ end
+ end
end
ruby_version_is "3.3" do
describe "C-API Data function" do
- before :each do
+ before :all do
@s = CApiStructSpecs.new
+ @klass = @s.rb_data_define(nil, "a", "b", "c")
end
describe "rb_data_define" do
it "returns a subclass of Data class when passed nil as the first argument" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
-
- klass.should.is_a? Class
- klass.superclass.should == Data
+ @klass.should.is_a? Class
+ @klass.superclass.should == Data
end
it "returns a subclass of a class when passed as the first argument" do
@@ -233,8 +261,7 @@ ruby_version_is "3.3" do
end
it "creates readers for the members" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
- obj = klass.new(1, 2, 3)
+ obj = @klass.new(1, 2, 3)
obj.a.should == 1
obj.b.should == 2
@@ -242,8 +269,7 @@ ruby_version_is "3.3" do
end
it "returns the member names as Symbols" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
- obj = klass.new(0, 0, 0)
+ obj = @klass.new(0, 0, 0)
obj.members.should == [:a, :b, :c]
end
@@ -256,5 +282,35 @@ ruby_version_is "3.3" do
-> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)")
end
end
+
+ describe "rb_struct_initialize" do
+ it "sets all members for a Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == 3
+ end
+
+ it "freezes the Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.should.frozen?
+ -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should raise_error(FrozenError)
+ end
+
+ it "raises ArgumentError if too many values" do
+ data = @klass.allocate
+ -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs")
+ end
+
+ it "treats missing values as nil" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == nil
+ end
+ end
end
end
diff --git a/spec/ruby/optional/capi/thread_spec.rb b/spec/ruby/optional/capi/thread_spec.rb
index cd9ae8ff19..117726f0e2 100644
--- a/spec/ruby/optional/capi/thread_spec.rb
+++ b/spec/ruby/optional/capi/thread_spec.rb
@@ -185,7 +185,7 @@ describe "C-API Thread function" do
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
describe "ruby_thread_has_gvl_p" do
it "returns true if the current thread has the GVL" do
@t.ruby_thread_has_gvl_p.should be_true