From a0f5ff4c3cd05f8717be2bf1d79f0817f288d398 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 28 Feb 2020 19:07:17 +0100 Subject: [PATCH] Update to ruby/spec@41bf282 --- spec/ruby/CONTRIBUTING.md | 54 ++++++++++-- spec/ruby/README.md | 3 +- spec/ruby/command_line/dash_l_spec.rb | 33 +++++++ spec/ruby/core/array/shared/slice.rb | 13 ++- spec/ruby/core/binding/eval_spec.rb | 6 ++ spec/ruby/core/binding/fixtures/classes.rb | 14 +++ spec/ruby/core/file/realpath_spec.rb | 6 ++ spec/ruby/core/file/stat_spec.rb | 9 ++ spec/ruby/core/integer/lte_spec.rb | 5 ++ .../ruby/core/kernel/caller_locations_spec.rb | 8 ++ spec/ruby/core/kernel/caller_spec.rb | 8 ++ spec/ruby/core/kernel/eval_spec.rb | 40 +++++++++ spec/ruby/core/module/name_spec.rb | 6 ++ spec/ruby/core/module/shared/class_eval.rb | 44 ++++++++++ spec/ruby/core/nil/match_spec.rb | 4 + spec/ruby/core/string/shared/slice.rb | 20 +++++ spec/ruby/core/struct/new_spec.rb | 2 +- .../core/thread/backtrace_locations_spec.rb | 23 +++-- spec/ruby/core/thread/backtrace_spec.rb | 34 ++++++++ spec/ruby/core/time/ceil_spec.rb | 7 +- spec/ruby/core/time/floor_spec.rb | 7 +- spec/ruby/language/delegation_spec.rb | 41 +++++++++ spec/ruby/language/fixtures/delegation.rb | 11 +++ spec/ruby/language/pattern_matching_spec.rb | 85 +++++++++++++++++++ spec/ruby/language/variables_spec.rb | 10 +++ spec/ruby/library/cgi/escapeHTML_spec.rb | 4 + spec/ruby/library/stringio/binmode_spec.rb | 14 +++ spec/ruby/library/stringio/inspect_spec.rb | 19 +++++ .../library/yaml/add_builtin_type_spec.rb | 2 - .../ruby/library/yaml/add_domain_type_spec.rb | 2 - .../library/yaml/add_private_type_spec.rb | 2 - spec/ruby/library/yaml/add_ruby_type_spec.rb | 2 - .../ruby/library/yaml/detect_implicit_spec.rb | 2 - spec/ruby/library/yaml/each_node_spec.rb | 2 - spec/ruby/library/yaml/emitter_spec.rb | 2 - spec/ruby/library/yaml/generic_parser_spec.rb | 2 - spec/ruby/library/yaml/object_maker_spec.rb | 2 - .../ruby/library/yaml/parse_documents_spec.rb | 2 - spec/ruby/library/yaml/parser_spec.rb | 2 - spec/ruby/library/yaml/quick_emit_spec.rb | 2 - .../ruby/library/yaml/read_type_class_spec.rb | 2 - spec/ruby/library/yaml/transfer_spec.rb | 2 - spec/ruby/library/yaml/try_implicit_spec.rb | 2 - spec/ruby/optional/capi/README | 9 +- spec/ruby/optional/capi/array_spec.rb | 10 +++ spec/ruby/optional/capi/ext/array_spec.c | 6 ++ spec/ruby/optional/capi/ext/bignum_spec.c | 4 +- spec/ruby/optional/capi/ext/boolean_spec.c | 2 +- .../capi/ext/class_id_under_autoload_spec.c | 8 ++ spec/ruby/optional/capi/ext/class_spec.c | 2 +- .../capi/ext/class_under_autoload_spec.c | 8 ++ spec/ruby/optional/capi/ext/data_spec.c | 8 +- spec/ruby/optional/capi/ext/gc_spec.c | 6 +- spec/ruby/optional/capi/ext/globals_spec.c | 8 +- spec/ruby/optional/capi/ext/integer_spec.c | 2 +- spec/ruby/optional/capi/ext/io_spec.c | 6 +- spec/ruby/optional/capi/ext/kernel_spec.c | 6 +- spec/ruby/optional/capi/ext/language_spec.c | 34 ++++++++ .../capi/ext/module_under_autoload_spec.c | 8 ++ spec/ruby/optional/capi/ext/numeric_spec.c | 5 ++ spec/ruby/optional/capi/ext/object_spec.c | 2 +- spec/ruby/optional/capi/ext/proc_spec.c | 5 ++ spec/ruby/optional/capi/ext/rubyspec.h | 26 ++++++ spec/ruby/optional/capi/ext/string_spec.c | 26 +++++- spec/ruby/optional/capi/ext/symbol_spec.c | 5 ++ spec/ruby/optional/capi/ext/thread_spec.c | 4 +- spec/ruby/optional/capi/ext/typed_data_spec.c | 51 +++++------ spec/ruby/optional/capi/ext/util_spec.c | 4 +- spec/ruby/optional/capi/kernel_spec.rb | 48 ++++++----- spec/ruby/optional/capi/language_spec.rb | 31 +++++++ spec/ruby/optional/capi/numeric_spec.rb | 28 ++++++ spec/ruby/optional/capi/proc_spec.rb | 19 +++++ spec/ruby/optional/capi/spec_helper.rb | 25 ++++-- spec/ruby/optional/capi/string_spec.rb | 18 ++++ spec/ruby/optional/capi/symbol_spec.rb | 10 +++ 75 files changed, 851 insertions(+), 143 deletions(-) create mode 100644 spec/ruby/command_line/dash_l_spec.rb create mode 100644 spec/ruby/language/delegation_spec.rb create mode 100644 spec/ruby/language/fixtures/delegation.rb create mode 100644 spec/ruby/library/stringio/inspect_spec.rb delete mode 100644 spec/ruby/library/yaml/add_builtin_type_spec.rb delete mode 100644 spec/ruby/library/yaml/add_domain_type_spec.rb delete mode 100644 spec/ruby/library/yaml/add_private_type_spec.rb delete mode 100644 spec/ruby/library/yaml/add_ruby_type_spec.rb delete mode 100644 spec/ruby/library/yaml/detect_implicit_spec.rb delete mode 100644 spec/ruby/library/yaml/each_node_spec.rb delete mode 100644 spec/ruby/library/yaml/emitter_spec.rb delete mode 100644 spec/ruby/library/yaml/generic_parser_spec.rb delete mode 100644 spec/ruby/library/yaml/object_maker_spec.rb delete mode 100644 spec/ruby/library/yaml/parse_documents_spec.rb delete mode 100644 spec/ruby/library/yaml/parser_spec.rb delete mode 100644 spec/ruby/library/yaml/quick_emit_spec.rb delete mode 100644 spec/ruby/library/yaml/read_type_class_spec.rb delete mode 100644 spec/ruby/library/yaml/transfer_spec.rb delete mode 100644 spec/ruby/library/yaml/try_implicit_spec.rb create mode 100644 spec/ruby/optional/capi/ext/language_spec.c create mode 100644 spec/ruby/optional/capi/language_spec.rb diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index 1ec6f0ff4b..d0924867fa 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -53,6 +53,8 @@ which indicates the file was generated but the method unspecified. Here is a list of frequently-used matchers, which should be enough for most specs. There are a few extra specific matchers used in the couple specs that need it. +#### Comparison matchers + ```ruby (1 + 2).should == 3 # Calls #== (1 + 2).should_not == 5 @@ -66,7 +68,11 @@ File.should equal(File) # Calls #equal? (tests identity) 4.should > 3 "Hello".should =~ /l{2}/ # Calls #=~ (Regexp match) +``` +#### Predicate matchers + +```ruby [].should be_empty # Calls #empty? [1,2,3].should include(2) # Calls #include? @@ -82,8 +88,13 @@ Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric) 3.14.should respond_to(:to_i) # Calls #respond_to? Fixnum.should have_instance_method(:+) Array.should have_method(:new) -# Also have_constant, have_private_instance_method, have_singleton_method, etc +``` +Also `have_constant`, `have_private_instance_method`, `have_singleton_method`, etc. + +#### Exception matchers + +```ruby -> { raise "oops" }.should raise_error(RuntimeError, /oops/) @@ -95,11 +106,20 @@ Array.should have_method(:new) e.message.should include("oops") e.cause.should == nil } +``` -# To avoid! Instead, use an expectation testing what the code in the lambda does. -# If an exception is raised, it will fail the example anyway. +##### should_not raise_error + +**To avoid!** Instead, use an expectation testing what the code in the lambda does. +If an exception is raised, it will fail the example anyway. + +```ruby -> { ... }.should_not raise_error +``` +#### Warning matcher + +```ruby -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/) # Expect a warning @@ -110,6 +130,8 @@ Array.should have_method(:new) Different guards are available as defined by mspec. Here is a list of the most commonly-used guards: +#### Version guards + ```ruby ruby_version_is ""..."2.4" do # Specs for RUBY_VERSION < 2.4 @@ -118,7 +140,11 @@ end ruby_version_is "2.4" do # Specs for RUBY_VERSION >= 2.4 end +``` +#### Platform guards + +```ruby platform_is :windows do # Specs only valid on Windows end @@ -140,18 +166,25 @@ end big_endian do # Big-endian platform end +``` -# In case there is a bug in MRI but the expected behavior is obvious -# First file a bug at https://bugs.ruby-lang.org/ -# It is better to use a ruby_version_is guard if there was a release with the fix +#### Guard for bug + +In case there is a bug in MRI but the expected behavior is obvious. +First, file a bug at https://bugs.ruby-lang.org/. +It is better to use a `ruby_version_is` guard if there was a release with the fix. + +```ruby ruby_bug '#13669', ''...'2.5' do it "works like this" do # Specify the expected behavior here, not the bug end end +``` +#### Combining guards -# Combining guards +```ruby guard -> { platform_is :windows and ruby_version_is ""..."2.5" } do # Windows and RUBY_VERSION < 2.5 end @@ -159,8 +192,11 @@ end guard_not -> { platform_is :windows and ruby_version_is ""..."2.5" } do # The opposite end +``` -# Custom guard +#### Custom guard + +```ruby max_uint = (1 << 32) - 1 guard -> { max_uint <= fixnum_max } do end @@ -168,6 +204,8 @@ end Custom guards are better than a simple `if` as they allow [mspec commands](https://github.com/ruby/mspec/issues/30#issuecomment-312487779) to work properly. +#### Implementation-specific behaviors + In general, the usage of guards should be minimized as possible. There are no guards to define implementation-specific behavior because diff --git a/spec/ruby/README.md b/spec/ruby/README.md index b34e6681b1..e6c7153c3d 100644 --- a/spec/ruby/README.md +++ b/spec/ruby/README.md @@ -1,7 +1,6 @@ # The Ruby Spec Suite -[![Actions Build Status](https://github.com/ruby/spec/workflows/CI/badge.svg?branch=master)](https://github.com/ruby/spec/actions) -[![Windows Actions Build Status](https://github.com/ruby/spec/workflows/Windows/badge.svg?branch=master)](https://github.com/ruby/spec/actions) +[![Actions Build Status](https://github.com/ruby/spec/workflows/CI/badge.svg)](https://github.com/ruby/spec/actions) [![Gitter](https://badges.gitter.im/ruby/spec.svg)](https://gitter.im/ruby/spec) The Ruby Spec Suite, abbreviated `ruby/spec`, is a test suite for the behavior of the Ruby programming language. diff --git a/spec/ruby/command_line/dash_l_spec.rb b/spec/ruby/command_line/dash_l_spec.rb new file mode 100644 index 0000000000..51d924edc1 --- /dev/null +++ b/spec/ruby/command_line/dash_l_spec.rb @@ -0,0 +1,33 @@ +require_relative '../spec_helper' + +describe "The -l command line option" do + before :each do + @names = fixture __FILE__, "full_names.txt" + end + + it "chomps lines with default separator" do + ruby_exe('puts $_.end_with?("\n")', options: "-n -l", escape: true, + args: " < #{@names}").should == + "false\nfalse\nfalse\n" + end + + ruby_version_is "2.5" do + it "chomps last line based on $/" do + ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", escape: true, + args: " < #{@names}").should == + "alice j\nbob field\njames grey\n" + end + end + + it "sets $\\ to the value of $/" do + ruby_exe("puts $\\ == $/", options: "-W0 -n -l", escape: true, + args: " < #{@names}").should == + "true\ntrue\ntrue\n" + end + + it "sets $-l" do + ruby_exe("puts $-l", options: "-n -l", escape: true, + args: " < #{@names}").should == + "true\ntrue\ntrue\n" + end +end diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index 1e7fdf934a..d6b4547b2b 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -461,7 +461,7 @@ describe :array_slice, shared: true do it "raises a RangeError when the start index is out of range of Fixnum" do array = [1, 2, 3, 4, 5, 6] obj = mock('large value') - obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + obj.should_receive(:to_int).and_return(bignum_value) -> { array.send(@method, obj) }.should raise_error(RangeError) obj = 8e19 @@ -471,10 +471,19 @@ describe :array_slice, shared: true do it "raises a RangeError when the length is out of range of Fixnum" do array = [1, 2, 3, 4, 5, 6] obj = mock('large value') - obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + obj.should_receive(:to_int).and_return(bignum_value) -> { array.send(@method, 1, obj) }.should raise_error(RangeError) obj = 8e19 -> { array.send(@method, 1, obj) }.should raise_error(RangeError) end + + it "raises a type error if a range is passed with a length" do + ->{ [1, 2, 3].send(@method, 1..2, 1) }.should raise_error(TypeError) + end + + it "raises a RangeError if passed a range with a bound that is too large" do + -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError) + -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError) + end end diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb index 84096f8a91..224bce4c33 100644 --- a/spec/ruby/core/binding/eval_spec.rb +++ b/spec/ruby/core/binding/eval_spec.rb @@ -131,4 +131,10 @@ describe "Binding#eval" do bind, meth = obj.get_binding_with_send_and_method bind.eval("__method__").should == meth end + + it "reflects refinements activated in the binding scope" do + bind = BindingSpecs::Refined.refined_binding + + bind.eval("'bar'.foo").should == "foo" + end end diff --git a/spec/ruby/core/binding/fixtures/classes.rb b/spec/ruby/core/binding/fixtures/classes.rb index 43e32cacf6..b5f3ce9008 100644 --- a/spec/ruby/core/binding/fixtures/classes.rb +++ b/spec/ruby/core/binding/fixtures/classes.rb @@ -49,4 +49,18 @@ module BindingSpecs end end end + + module AddFooToString + refine(String) do + def foo + "foo" + end + end + end + class Refined + using AddFooToString + def self.refined_binding + binding + end + end end diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb index 0c5d19287a..bd27e09da6 100644 --- a/spec/ruby/core/file/realpath_spec.rb +++ b/spec/ruby/core/file/realpath_spec.rb @@ -67,6 +67,12 @@ platform_is_not :windows do it "raises Errno::ENOENT if the symlink points to an absent file" do -> { File.realpath(@fake_link) }.should raise_error(Errno::ENOENT) end + + it "converts the argument with #to_path" do + path = mock("path") + path.should_receive(:to_path).and_return(__FILE__) + File.realpath(path).should == File.realpath(__FILE__ ) + end end end diff --git a/spec/ruby/core/file/stat_spec.rb b/spec/ruby/core/file/stat_spec.rb index 31f9dc58af..76b0becbf0 100644 --- a/spec/ruby/core/file/stat_spec.rb +++ b/spec/ruby/core/file/stat_spec.rb @@ -41,5 +41,14 @@ platform_is_not :windows do st.file?.should == true st.symlink?.should == false end + + it "returns an error when given missing non-ASCII path" do + missing_path = "/missingfilepath\xE3E4".force_encoding("ASCII-8BIT") + -> { + File.stat(missing_path) + }.should raise_error(Errno::ENOENT) { |e| + e.message.should include(missing_path) + } + end end end diff --git a/spec/ruby/core/integer/lte_spec.rb b/spec/ruby/core/integer/lte_spec.rb index 3d843a5dd9..40a89f094a 100644 --- a/spec/ruby/core/integer/lte_spec.rb +++ b/spec/ruby/core/integer/lte_spec.rb @@ -46,6 +46,11 @@ describe "Integer#<=" do (@bignum <= (@bignum + 0.5)).should == false end + it "returns true for bignums compare to a bigger float" do + (18446744073709551616 <= 1.8446744073709552e+19).should == true + (@bignum <= (@bignum + 9999.0)).should == true + end + it "raises an ArgumentError when given a non-Integer" do -> { @bignum <= "4" }.should raise_error(ArgumentError) -> { @bignum <= mock('str') }.should raise_error(ArgumentError) diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb index 8f9429845d..cb344e16a0 100644 --- a/spec/ruby/core/kernel/caller_locations_spec.rb +++ b/spec/ruby/core/kernel/caller_locations_spec.rb @@ -28,6 +28,14 @@ describe 'Kernel#caller_locations' do locations1[2..4].map(&:to_s).should == locations2.map(&:to_s) end + ruby_version_is "2.6" do + it "works with endless ranges" do + locations1 = caller_locations(0) + locations2 = caller_locations(eval("(2..)")) + locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) + end + end + it "can be called with a range whose end is negative" do locations1 = caller_locations(0) locations2 = caller_locations(2..-1) diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb index 8469319c94..e943e36dc2 100644 --- a/spec/ruby/core/kernel/caller_spec.rb +++ b/spec/ruby/core/kernel/caller_spec.rb @@ -43,4 +43,12 @@ describe 'Kernel#caller' do "#{path}:2:in `block in
'\n" ] end + + ruby_version_is "2.6" do + it "works with endless ranges" do + locations1 = KernelSpecs::CallerTest.locations(0) + locations2 = KernelSpecs::CallerTest.locations(eval("(2..)")) + locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) + end + end end diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 09ccb9dc62..783009ac01 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -373,4 +373,44 @@ CODE EvalSpecs.send :remove_const, :Vπstring_not_frozen end end + + it "activates refinements from the eval scope" do + refinery = Module.new do + refine EvalSpecs::A do + def foo + "bar" + end + end + end + + result = nil + + Module.new do + using refinery + + result = eval "EvalSpecs::A.new.foo" + end + + result.should == "bar" + end + + it "activates refinements from the binding" do + refinery = Module.new do + refine EvalSpecs::A do + def foo + "bar" + end + end + end + + b = nil + m = Module.new do + using refinery + b = binding + end + + result = eval "EvalSpecs::A.new.foo", b + + result.should == "bar" + end end diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index 36a91f5be5..9a4730313f 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -18,6 +18,12 @@ describe "Module#name" do m::N.name.should =~ /\A#::N\z/ end + it "returns nil for a singleton class" do + Module.new.singleton_class.name.should be_nil + String.singleton_class.name.should be_nil + Object.new.singleton_class.name.should be_nil + end + it "changes when the module is reachable through a constant path" do m = Module.new module m::N; end diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb index 08f8ff7597..224078ae54 100644 --- a/spec/ruby/core/module/shared/class_eval.rb +++ b/spec/ruby/core/module/shared/class_eval.rb @@ -112,4 +112,48 @@ describe :module_class_eval, shared: true do a.attribute.should == "A" b.attribute.should == "B" end + + it "activates refinements from the eval scope" do + refinery = Module.new do + refine ModuleSpecs::NamedClass do + def foo + "bar" + end + end + end + + mid = @method + result = nil + + Class.new do + using refinery + + result = send(mid, "ModuleSpecs::NamedClass.new.foo") + end + + result.should == "bar" + end + + it "activates refinements from the eval scope with block" do + refinery = Module.new do + refine ModuleSpecs::NamedClass do + def foo + "bar" + end + end + end + + mid = @method + result = nil + + Class.new do + using refinery + + result = send(mid) do + ModuleSpecs::NamedClass.new.foo + end + end + + result.should == "bar" + end end diff --git a/spec/ruby/core/nil/match_spec.rb b/spec/ruby/core/nil/match_spec.rb index 3f69312bfe..27646e9749 100644 --- a/spec/ruby/core/nil/match_spec.rb +++ b/spec/ruby/core/nil/match_spec.rb @@ -15,5 +15,9 @@ ruby_version_is "2.6" do (o =~ true).should be_nil end end + + it "should not warn" do + -> { nil =~ /a/ }.should_not complain(verbose: true) + end end end diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb index b192005369..1c438bc48d 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -121,6 +121,8 @@ describe :string_slice_index_length, shared: true do "x".send(@method, -2,0).should == nil "x".send(@method, -2,1).should == nil + + "x".send(@method, fixnum_max, 1).should == nil end it "returns nil if the length is negative" do @@ -293,6 +295,24 @@ describe :string_slice_range, shared: true do "hello world".send(@method, 6..5).send(@method, -1..-1).should == nil "hello world".send(@method, 6..5).send(@method, 1..1).should == nil end + + it "raises a type error if a range is passed with a length" do + ->{ "hello".send(@method, 1..2, 1) }.should raise_error(TypeError) + end + + it "raises a RangeError if one of the bound is too big" do + -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError) + -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError) + end + + ruby_version_is "2.6" do + it "works with endless ranges" do + "hello there".send(@method, eval("(2..)")).should == "llo there" + "hello there".send(@method, eval("(2...)")).should == "llo there" + "hello there".send(@method, eval("(-4..)")).should == "here" + "hello there".send(@method, eval("(-4...)")).should == "here" + end + end end describe :string_slice_regexp, shared: true do diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb index 564c49af01..071aa38d25 100644 --- a/spec/ruby/core/struct/new_spec.rb +++ b/spec/ruby/core/struct/new_spec.rb @@ -15,7 +15,7 @@ describe "Struct.new" do second = nil -> { second = Struct.new('Person', :hair, :sex) - }.should complain(/redefining constant/) + }.should complain(/constant/) second.should == Struct::Person first.members.should_not == second.members diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb index 211858899c..ead4be2d8c 100644 --- a/spec/ruby/core/thread/backtrace_locations_spec.rb +++ b/spec/ruby/core/thread/backtrace_locations_spec.rb @@ -22,28 +22,33 @@ describe "Thread#backtrace_locations" do it "can be called with a number of locations to omit" do locations1 = Thread.current.backtrace_locations locations2 = Thread.current.backtrace_locations(2) - locations1[2..-1].length.should == locations2.length - locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s) + locations2.length.should == locations1[2..-1].length + locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) end it "can be called with a maximum number of locations to return as second parameter" do locations1 = Thread.current.backtrace_locations locations2 = Thread.current.backtrace_locations(2, 3) - locations1[2..4].map(&:to_s).should == locations2.map(&:to_s) + locations2.map(&:to_s).should == locations1[2..4].map(&:to_s) end it "can be called with a range" do locations1 = Thread.current.backtrace_locations locations2 = Thread.current.backtrace_locations(2..4) - locations1[2..4].map(&:to_s).should == locations2.map(&:to_s) + locations2.map(&:to_s).should == locations1[2..4].map(&:to_s) end it "can be called with a range whose end is negative" do - locations1 = Thread.current.backtrace_locations - locations2 = Thread.current.backtrace_locations(2..-1) - locations3 = Thread.current.backtrace_locations(2..-2) - locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s) - locations1[2..-2].map(&:to_s).should == locations3.map(&:to_s) + Thread.current.backtrace_locations(2..-1).map(&:to_s).should == Thread.current.backtrace_locations[2..-1].map(&:to_s) + Thread.current.backtrace_locations(2..-2).map(&:to_s).should == Thread.current.backtrace_locations[2..-2].map(&:to_s) + end + + ruby_version_is "2.6" do + it "can be called with an endless range" do + locations1 = Thread.current.backtrace_locations(0) + locations2 = Thread.current.backtrace_locations(eval("(2..)")) + locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) + end end it "returns nil if omitting more locations than available" do diff --git a/spec/ruby/core/thread/backtrace_spec.rb b/spec/ruby/core/thread/backtrace_spec.rb index 84ed574d5c..9001b1b7eb 100644 --- a/spec/ruby/core/thread/backtrace_spec.rb +++ b/spec/ruby/core/thread/backtrace_spec.rb @@ -32,4 +32,38 @@ describe "Thread#backtrace" do t.join backtrace.should be_kind_of(Array) end + + it "can be called with a number of locations to omit" do + locations1 = Thread.current.backtrace + locations2 = Thread.current.backtrace(2) + locations1[2..-1].length.should == locations2.length + locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s) + end + + it "can be called with a maximum number of locations to return as second parameter" do + locations1 = Thread.current.backtrace + locations2 = Thread.current.backtrace(2, 3) + locations1[2..4].map(&:to_s).should == locations2.map(&:to_s) + end + + it "can be called with a range" do + locations1 = Thread.current.backtrace + locations2 = Thread.current.backtrace(2..4) + locations1[2..4].map(&:to_s).should == locations2.map(&:to_s) + end + + it "can be called with a range whose end is negative" do + Thread.current.backtrace(2..-1).should == Thread.current.backtrace[2..-1] + Thread.current.backtrace(2..-2).should == Thread.current.backtrace[2..-2] + end + + it "returns nil if omitting more locations than available" do + Thread.current.backtrace(100).should == nil + Thread.current.backtrace(100..-1).should == nil + end + + it "returns [] if omitting exactly the number of locations available" do + omit = Thread.current.backtrace.length + Thread.current.backtrace(omit).should == [] + end end diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb index 29dcec5d72..86029554db 100644 --- a/spec/ruby/core/time/ceil_spec.rb +++ b/spec/ruby/core/time/ceil_spec.rb @@ -36,10 +36,11 @@ ruby_version_is "2.7" do it "copies own timezone to the returning value" do @time.zone.should == @time.ceil.zone - with_timezone "JST-9" do - time = Time.at 0, 1 - time.zone.should == time.ceil.zone + time = with_timezone "JST-9" do + Time.at 0, 1 end + + time.zone.should == time.ceil.zone end end end diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb index 763ed1ba51..a19585b787 100644 --- a/spec/ruby/core/time/floor_spec.rb +++ b/spec/ruby/core/time/floor_spec.rb @@ -28,10 +28,11 @@ ruby_version_is "2.7" do it "copies own timezone to the returning value" do @time.zone.should == @time.floor.zone - with_timezone "JST-9" do - time = Time.at 0, 1 - time.zone.should == time.floor.zone + time = with_timezone "JST-9" do + Time.at 0, 1 end + + time.zone.should == time.floor.zone end end end diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb new file mode 100644 index 0000000000..4063ad457e --- /dev/null +++ b/spec/ruby/language/delegation_spec.rb @@ -0,0 +1,41 @@ +require_relative '../spec_helper' +require_relative 'fixtures/delegation' + +ruby_version_is "2.7" do + describe "delegation with def(...)" do + it "delegates rest and kwargs" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate(...) + target(...) + end + RUBY + + a.new.delegate(1, b: 2).should == [[1], {b: 2}] + end + + it "delegates block" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate_block(...) + target_block(...) + end + RUBY + + a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]] + end + + it "parses as open endless Range when brackets are ommitted" do + a = Class.new(DelegationSpecs::Target) + suppress_warning do + a.class_eval(<<-RUBY) + def delegate(...) + target ... + end + RUBY + end + + a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true) + end + end +end diff --git a/spec/ruby/language/fixtures/delegation.rb b/spec/ruby/language/fixtures/delegation.rb new file mode 100644 index 0000000000..527d928390 --- /dev/null +++ b/spec/ruby/language/fixtures/delegation.rb @@ -0,0 +1,11 @@ +module DelegationSpecs + class Target + def target(*args, **kwargs) + [args, kwargs] + end + + def target_block(*args, **kwargs) + yield [kwargs, args] + end + end +end diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb index 6a6de506ff..f84d84c241 100644 --- a/spec/ruby/language/pattern_matching_spec.rb +++ b/spec/ruby/language/pattern_matching_spec.rb @@ -402,6 +402,17 @@ ruby_version_is "2.7" do RUBY }.should raise_error(SyntaxError, /illegal variable in alternative pattern/) end + + it "support undescore prefixed variables in alternation" do + eval(<<~RUBY).should == true + case [0, 1] + in [1, _] + false + in [0, 0] | [0, _a] + true + end + RUBY + end end describe "AS pattern" do @@ -962,5 +973,79 @@ ruby_version_is "2.7" do RUBY end end + + describe "refinements" do + it "are used for #deconstruct" do + refinery = Module.new do + refine Array do + def deconstruct + [0] + end + end + end + + result = nil + Module.new do + using refinery + + result = eval(<<~RUBY) + case [] + in [0] + true + end + RUBY + end + + result.should == true + end + + it "are used for #deconstruct_keys" do + refinery = Module.new do + refine Hash do + def deconstruct_keys(_) + {a: 0} + end + end + end + + result = nil + Module.new do + using refinery + + result = eval(<<~RUBY) + case {} + in a: 0 + true + end + RUBY + end + + result.should == true + end + + it "are used for #=== in constant pattern" do + refinery = Module.new do + refine Array.singleton_class do + def ===(obj) + obj.is_a?(Hash) + end + end + end + + result = nil + Module.new do + using refinery + + result = eval(<<~RUBY) + case {} + in Array + true + end + RUBY + end + + result.should == true + end + end end end diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb index 868603eb88..7c2c7889f1 100644 --- a/spec/ruby/language/variables_spec.rb +++ b/spec/ruby/language/variables_spec.rb @@ -354,6 +354,16 @@ describe "Multiple assignment" do a.should be_an_instance_of(Array) end + it "unfreezes the array returned from calling 'to_a' on the splatted value" do + obj = Object.new + def obj.to_a + [1,2].freeze + end + res = *obj + res.should == [1,2] + res.frozen?.should == false + end + it "consumes values for an anonymous splat" do a = 1 (* = *a).should == [1] diff --git a/spec/ruby/library/cgi/escapeHTML_spec.rb b/spec/ruby/library/cgi/escapeHTML_spec.rb index dcbfebe720..421aac5d4a 100644 --- a/spec/ruby/library/cgi/escapeHTML_spec.rb +++ b/spec/ruby/library/cgi/escapeHTML_spec.rb @@ -6,6 +6,10 @@ describe "CGI.escapeHTML" do CGI.escapeHTML(%[& < > " ']).should == '& < > " '' end + it "escapes invalid encoding" do + CGI.escapeHTML(%[<\xA4??>]).should == "<\xA4??>" + end + it "does not escape any other characters" do chars = " !\#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" CGI.escapeHTML(chars).should == chars diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb index 5d9a8c41df..83178787f3 100644 --- a/spec/ruby/library/stringio/binmode_spec.rb +++ b/spec/ruby/library/stringio/binmode_spec.rb @@ -6,4 +6,18 @@ describe "StringIO#binmode" do io = StringIO.new("example") io.binmode.should equal(io) end + + it "changes external encoding to BINARY" do + io = StringIO.new + io.external_encoding.should == Encoding.find('locale') + io.binmode + io.external_encoding.should == Encoding::BINARY + end + + it "does not set internal encoding" do + io = StringIO.new + io.internal_encoding.should == nil + io.binmode + io.internal_encoding.should == nil + end end diff --git a/spec/ruby/library/stringio/inspect_spec.rb b/spec/ruby/library/stringio/inspect_spec.rb new file mode 100644 index 0000000000..7c02f8d360 --- /dev/null +++ b/spec/ruby/library/stringio/inspect_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../spec_helper' +require "stringio" + +describe "StringIO#inspect" do + it "returns the same as #to_s" do + io = StringIO.new("example") + io.inspect.should == io.to_s + end + + it "does not include the contents" do + io = StringIO.new("contents") + io.inspect.should_not include("contents") + end + + it "uses the regular Object#inspect without any instance variable" do + io = StringIO.new("example") + io.inspect.should =~ /\A#\z/ + end +end diff --git a/spec/ruby/library/yaml/add_builtin_type_spec.rb b/spec/ruby/library/yaml/add_builtin_type_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/add_builtin_type_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/add_domain_type_spec.rb b/spec/ruby/library/yaml/add_domain_type_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/add_domain_type_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/add_private_type_spec.rb b/spec/ruby/library/yaml/add_private_type_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/add_private_type_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/add_ruby_type_spec.rb b/spec/ruby/library/yaml/add_ruby_type_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/add_ruby_type_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/detect_implicit_spec.rb b/spec/ruby/library/yaml/detect_implicit_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/detect_implicit_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/each_node_spec.rb b/spec/ruby/library/yaml/each_node_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/each_node_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/emitter_spec.rb b/spec/ruby/library/yaml/emitter_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/emitter_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/generic_parser_spec.rb b/spec/ruby/library/yaml/generic_parser_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/generic_parser_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/object_maker_spec.rb b/spec/ruby/library/yaml/object_maker_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/object_maker_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/parse_documents_spec.rb b/spec/ruby/library/yaml/parse_documents_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/parse_documents_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/parser_spec.rb b/spec/ruby/library/yaml/parser_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/parser_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/quick_emit_spec.rb b/spec/ruby/library/yaml/quick_emit_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/quick_emit_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/read_type_class_spec.rb b/spec/ruby/library/yaml/read_type_class_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/read_type_class_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/transfer_spec.rb b/spec/ruby/library/yaml/transfer_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/transfer_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/library/yaml/try_implicit_spec.rb b/spec/ruby/library/yaml/try_implicit_spec.rb deleted file mode 100644 index 44c820940f..0000000000 --- a/spec/ruby/library/yaml/try_implicit_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' diff --git a/spec/ruby/optional/capi/README b/spec/ruby/optional/capi/README index 57b0c51f01..069ca3c106 100644 --- a/spec/ruby/optional/capi/README +++ b/spec/ruby/optional/capi/README @@ -8,9 +8,6 @@ specs: optional/capi/array_spec.rb 2. Put the C file containing the C functions for array_spec.rb in optional/capi/ext/array_spec.c -3. Add a '#define HAVE_RB_ARY_NEW 1' to rubyspec.h -4. Name the C extension class 'CApiArraySpecs'. -5. Name the C functions 'array_spec_rb_ary_new'. -6. Wrap the code in the optional/capi/ext/array_spec.c in - '#ifdef HAVE_RB_ARY_NEW' -7. Attach the C function to the class using the name 'rb_ary_new' +3. Name the C extension class 'CApiArraySpecs'. +4. Name the C functions 'array_spec_rb_ary_new'. +5. Attach the C function to the class using the name 'rb_ary_new' diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb index cf65bc19b6..6bb20e5921 100644 --- a/spec/ruby/optional/capi/array_spec.rb +++ b/spec/ruby/optional/capi/array_spec.rb @@ -272,6 +272,16 @@ describe "C-API Array function" do end end + describe "RARRAY_ASET" do + # This macro does NOT do any bounds checking! + it "writes an element in the array" do + ary = [1, 2, 3] + @s.RARRAY_ASET(ary, 0, 0) + @s.RARRAY_ASET(ary, 2, 42) + ary.should == [0, 2, 42] + end + end + describe "rb_assoc_new" do it "returns an array containing the two elements" do @s.rb_assoc_new(1, 2).should == [1, 2] diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c index 454cf03303..afd6aeef15 100644 --- a/spec/ruby/optional/capi/ext/array_spec.c +++ b/spec/ruby/optional/capi/ext/array_spec.c @@ -54,6 +54,11 @@ static VALUE array_spec_RARRAY_AREF(VALUE self, VALUE array, VALUE index) { return RARRAY_AREF(array, FIX2INT(index)); } +static VALUE array_spec_RARRAY_ASET(VALUE self, VALUE array, VALUE index, VALUE value) { + RARRAY_ASET(array, FIX2INT(index), value); + return value; +} + static VALUE array_spec_rb_ary_aref(int argc, VALUE *argv, VALUE self) { VALUE ary, args; rb_scan_args(argc, argv, "1*", &ary, &args); @@ -244,6 +249,7 @@ void Init_array_spec(void) { rb_define_method(cls, "RARRAY_PTR_assign", array_spec_RARRAY_PTR_assign, 2); rb_define_method(cls, "RARRAY_PTR_memcpy", array_spec_RARRAY_PTR_memcpy, 2); rb_define_method(cls, "RARRAY_AREF", array_spec_RARRAY_AREF, 2); + rb_define_method(cls, "RARRAY_ASET", array_spec_RARRAY_ASET, 3); rb_define_method(cls, "rb_ary_aref", array_spec_rb_ary_aref, -1); rb_define_method(cls, "rb_ary_clear", array_spec_rb_ary_clear, 1); rb_define_method(cls, "rb_ary_delete", array_spec_rb_ary_delete, 2); diff --git a/spec/ruby/optional/capi/ext/bignum_spec.c b/spec/ruby/optional/capi/ext/bignum_spec.c index 14a51f5099..a950d8b16f 100644 --- a/spec/ruby/optional/capi/ext/bignum_spec.c +++ b/spec/ruby/optional/capi/ext/bignum_spec.c @@ -65,7 +65,7 @@ static VALUE bignum_spec_rb_big_pack_array(VALUE self, VALUE val, VALUE len) { long long_len = NUM2LONG(len); VALUE ary = rb_ary_new_capa(long_len); - unsigned long *buf = malloc(long_len * SIZEOF_LONG); + unsigned long *buf = (unsigned long*) malloc(long_len * SIZEOF_LONG); /* The array should be filled with recognisable junk so we can check it is all cleared properly. */ @@ -102,5 +102,5 @@ void Init_bignum_spec(void) { } #ifdef __cplusplus -extern "C" { +} #endif diff --git a/spec/ruby/optional/capi/ext/boolean_spec.c b/spec/ruby/optional/capi/ext/boolean_spec.c index 7bb6fe569d..081cffa103 100644 --- a/spec/ruby/optional/capi/ext/boolean_spec.c +++ b/spec/ruby/optional/capi/ext/boolean_spec.c @@ -29,5 +29,5 @@ void Init_boolean_spec(void) { } #ifdef __cplusplus -extern "C" { +} #endif diff --git a/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c b/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c index 64393a9397..cc5550f041 100644 --- a/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c +++ b/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c @@ -1,5 +1,13 @@ #include "ruby.h" +#ifdef __cplusplus +extern "C" { +#endif + void Init_class_id_under_autoload_spec(void) { rb_define_class_id_under(rb_cObject, rb_intern("ClassIdUnderAutoload"), rb_cObject); } + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c index 6e5c02e657..e62b9efe2e 100644 --- a/spec/ruby/optional/capi/ext/class_spec.c +++ b/spec/ruby/optional/capi/ext/class_spec.c @@ -45,7 +45,7 @@ static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE nargs, VALUE args, VALUE klass) { int c_nargs = FIX2INT(nargs); - VALUE *c_args = alloca(sizeof(VALUE) * c_nargs); + VALUE *c_args = (VALUE*)alloca(sizeof(VALUE) * c_nargs); int i; for (i = 0; i < c_nargs; i++) diff --git a/spec/ruby/optional/capi/ext/class_under_autoload_spec.c b/spec/ruby/optional/capi/ext/class_under_autoload_spec.c index 120dec7327..e0b1f249c0 100644 --- a/spec/ruby/optional/capi/ext/class_under_autoload_spec.c +++ b/spec/ruby/optional/capi/ext/class_under_autoload_spec.c @@ -1,5 +1,13 @@ #include "ruby.h" +#ifdef __cplusplus +extern "C" { +#endif + void Init_class_under_autoload_spec(void) { rb_define_class_under(rb_cObject, "ClassUnderAutoload", rb_cObject); } + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/data_spec.c b/spec/ruby/optional/capi/ext/data_spec.c index a41666f655..109bded1d1 100644 --- a/spec/ruby/optional/capi/ext/data_spec.c +++ b/spec/ruby/optional/capi/ext/data_spec.c @@ -19,7 +19,7 @@ void sample_wrapped_struct_mark(void* st) { } VALUE sdaf_alloc_func(VALUE klass) { - struct sample_wrapped_struct* bar = malloc(sizeof(struct sample_wrapped_struct)); + struct sample_wrapped_struct* bar = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); bar->foo = 42; return Data_Wrap_Struct(klass, &sample_wrapped_struct_mark, &sample_wrapped_struct_free, bar); } @@ -32,7 +32,7 @@ VALUE sdaf_get_struct(VALUE self) { } VALUE sws_wrap_struct(VALUE self, VALUE val) { - struct sample_wrapped_struct* bar = malloc(sizeof(struct sample_wrapped_struct)); + struct sample_wrapped_struct* bar = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); bar->foo = FIX2INT(val); return Data_Wrap_Struct(rb_cObject, &sample_wrapped_struct_mark, &sample_wrapped_struct_free, bar); } @@ -58,9 +58,9 @@ VALUE sws_get_struct_data_ptr(VALUE self, VALUE obj) { VALUE sws_change_struct(VALUE self, VALUE obj, VALUE new_val) { struct sample_wrapped_struct *old_struct, *new_struct; - new_struct = malloc(sizeof(struct sample_wrapped_struct)); + new_struct = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); new_struct->foo = FIX2INT(new_val); - old_struct = RDATA(obj)->data; + old_struct = (struct sample_wrapped_struct*) RDATA(obj)->data; free(old_struct); RDATA(obj)->data = new_struct; return Qnil; diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c index 983b021df9..4611617c18 100644 --- a/spec/ruby/optional/capi/ext/gc_spec.c +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -16,15 +16,15 @@ static VALUE registered_reference_address(VALUE self) { return registered_reference_value; } -static VALUE gc_spec_rb_gc_enable() { +static VALUE gc_spec_rb_gc_enable(VALUE self) { return rb_gc_enable(); } -static VALUE gc_spec_rb_gc_disable() { +static VALUE gc_spec_rb_gc_disable(VALUE self) { return rb_gc_disable(); } -static VALUE gc_spec_rb_gc() { +static VALUE gc_spec_rb_gc(VALUE self) { rb_gc(); return Qnil; } diff --git a/spec/ruby/optional/capi/ext/globals_spec.c b/spec/ruby/optional/capi/ext/globals_spec.c index f70622f66c..75860d3774 100644 --- a/spec/ruby/optional/capi/ext/globals_spec.c +++ b/spec/ruby/optional/capi/ext/globals_spec.c @@ -7,12 +7,16 @@ extern "C" { VALUE g_hooked_var; +VALUE var_2x_getter(ID id, VALUE *data) { + return *data; +} + void var_2x_setter(VALUE val, ID id, VALUE *var) { - *var = INT2NUM(NUM2INT(val) * 2); + *var = INT2NUM(NUM2INT(val) * 2); } static VALUE sb_define_hooked_variable(VALUE self, VALUE var_name) { - rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, 0, var_2x_setter); + rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, var_2x_getter, var_2x_setter); return Qnil; } diff --git a/spec/ruby/optional/capi/ext/integer_spec.c b/spec/ruby/optional/capi/ext/integer_spec.c index 7e9e8b26bd..124591e231 100644 --- a/spec/ruby/optional/capi/ext/integer_spec.c +++ b/spec/ruby/optional/capi/ext/integer_spec.c @@ -30,5 +30,5 @@ void Init_integer_spec(void) { } #ifdef __cplusplus -extern "C" { +} #endif diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c index 45f57810db..59613c110f 100644 --- a/spec/ruby/optional/capi/ext/io_spec.c +++ b/spec/ruby/optional/capi/ext/io_spec.c @@ -43,7 +43,7 @@ VALUE io_spec_rb_io_addstr(VALUE self, VALUE io, VALUE str) { VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { @@ -55,7 +55,7 @@ VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) { VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { @@ -67,7 +67,7 @@ VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) { VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index c5bb4a1d9a..13d9598125 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -68,7 +68,7 @@ VALUE rb_block_call_extra_data(VALUE self, VALUE object) { } VALUE kernel_spec_rb_block_call_no_func(VALUE self, VALUE ary) { - return rb_block_call(ary, rb_intern("map"), 0, NULL, NULL, Qnil); + return rb_block_call(ary, rb_intern("map"), 0, NULL, (rb_block_call_func_t)NULL, Qnil); } @@ -153,6 +153,10 @@ VALUE kernel_spec_rb_rescue(VALUE self, VALUE main_proc, VALUE arg, rb_ary_push(main_array, main_proc); rb_ary_push(main_array, arg); + if (raise_proc == Qnil) { + return rb_rescue(kernel_spec_call_proc, main_array, NULL, arg2); + } + raise_array = rb_ary_new(); rb_ary_push(raise_array, raise_proc); rb_ary_push(raise_array, arg2); diff --git a/spec/ruby/optional/capi/ext/language_spec.c b/spec/ruby/optional/capi/ext/language_spec.c new file mode 100644 index 0000000000..5aeac63f53 --- /dev/null +++ b/spec/ruby/optional/capi/ext/language_spec.c @@ -0,0 +1,34 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE language_spec_switch(VALUE self, VALUE value) { + if (value == ID2SYM(rb_intern("undef"))) { + value = Qundef; + } + + switch (value) { + case Qtrue: + return ID2SYM(rb_intern("true")); + case Qfalse: + return ID2SYM(rb_intern("false")); + case Qnil: + return ID2SYM(rb_intern("nil")); + case Qundef: + return ID2SYM(rb_intern("undef")); + default: + return ID2SYM(rb_intern("default")); + } +} + +void Init_language_spec(void) { + VALUE cls = rb_define_class("CApiLanguageSpecs", rb_cObject); + rb_define_method(cls, "switch", language_spec_switch, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/module_under_autoload_spec.c b/spec/ruby/optional/capi/ext/module_under_autoload_spec.c index c8f19a287b..b19466e555 100644 --- a/spec/ruby/optional/capi/ext/module_under_autoload_spec.c +++ b/spec/ruby/optional/capi/ext/module_under_autoload_spec.c @@ -1,7 +1,15 @@ #include "ruby.h" +#ifdef __cplusplus +extern "C" { +#endif + void Init_module_under_autoload_spec(void) { VALUE specs = rb_const_get(rb_cObject, rb_intern("CApiModuleSpecs")); rb_define_module_under(specs, "ModuleUnderAutoload"); rb_define_module_under(specs, "RubyUnderAutoload"); } + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/numeric_spec.c b/spec/ruby/optional/capi/ext/numeric_spec.c index 556c71a587..33f3a18c00 100644 --- a/spec/ruby/optional/capi/ext/numeric_spec.c +++ b/spec/ruby/optional/capi/ext/numeric_spec.c @@ -61,6 +61,10 @@ static VALUE numeric_spec_NUM2LONG(VALUE self, VALUE num) { return LONG2NUM(NUM2LONG(num)); } +static VALUE numeric_spec_NUM2SHORT(VALUE self, VALUE num) { + return LONG2NUM(NUM2SHORT(num)); +} + static VALUE numeric_spec_NUM2UINT(VALUE self, VALUE num) { return ULONG2NUM(NUM2UINT(num)); } @@ -109,6 +113,7 @@ void Init_numeric_spec(void) { rb_define_method(cls, "NUM2DBL", numeric_spec_NUM2DBL, 1); rb_define_method(cls, "NUM2INT", numeric_spec_NUM2INT, 1); rb_define_method(cls, "NUM2LONG", numeric_spec_NUM2LONG, 1); + rb_define_method(cls, "NUM2SHORT", numeric_spec_NUM2SHORT, 1); rb_define_method(cls, "INT2NUM", numeric_spec_INT2NUM, 1); rb_define_method(cls, "NUM2UINT", numeric_spec_NUM2UINT, 1); rb_define_method(cls, "NUM2ULONG", numeric_spec_NUM2ULONG, 1); diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c index 2151e37e5c..c95e1b553f 100644 --- a/spec/ruby/optional/capi/ext/object_spec.c +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -102,7 +102,7 @@ static VALUE so_rb_obj_dup(VALUE self, VALUE klass) { static VALUE so_rb_obj_call_init(VALUE self, VALUE object, VALUE nargs, VALUE args) { int c_nargs = FIX2INT(nargs); - VALUE *c_args = alloca(sizeof(VALUE) * c_nargs); + VALUE *c_args = (VALUE*) alloca(sizeof(VALUE) * c_nargs); int i; for (i = 0; i < c_nargs; i++) diff --git a/spec/ruby/optional/capi/ext/proc_spec.c b/spec/ruby/optional/capi/ext/proc_spec.c index 18fd1997ee..e0bd8b1bbc 100644 --- a/spec/ruby/optional/capi/ext/proc_spec.c +++ b/spec/ruby/optional/capi/ext/proc_spec.c @@ -23,6 +23,10 @@ VALUE proc_spec_rb_proc_call(VALUE self, VALUE prc, VALUE args) { return rb_proc_call(prc, args); } +VALUE proc_spec_rb_obj_is_proc(VALUE self, VALUE prc) { + return rb_obj_is_proc(prc); +} + /* This helper is not strictly necessary but reflects the code in wxRuby that * originally exposed issues with this Proc.new behavior. */ @@ -61,6 +65,7 @@ void Init_proc_spec(void) { rb_define_method(cls, "rb_proc_arity", proc_spec_rb_proc_arity, 1); rb_define_method(cls, "rb_proc_call", proc_spec_rb_proc_call, 2); rb_define_method(cls, "rb_Proc_new", proc_spec_rb_Proc_new, 1); + rb_define_method(cls, "rb_obj_is_proc", proc_spec_rb_obj_is_proc, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h index 78e298fddb..cce3af22f2 100644 --- a/spec/ruby/optional/capi/ext/rubyspec.h +++ b/spec/ruby/optional/capi/ext/rubyspec.h @@ -23,6 +23,10 @@ (RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR < (minor)) || \ (RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR == (minor) && RUBY_VERSION_TEENY < (teeny))) +#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 7) +#define RUBY_VERSION_IS_2_7 +#endif + #if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 6) #define RUBY_VERSION_IS_2_6 #endif @@ -31,4 +35,26 @@ #define RUBY_VERSION_IS_2_4 #endif +#if defined(__cplusplus) && !defined(RUBY_VERSION_IS_2_7) +/* Ruby < 2.7 needs this to let these function with callbacks and compile in C++ code */ +#define rb_define_method(mod, name, func, argc) rb_define_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_protected_method(mod, name, func, argc) rb_define_protected_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_private_method(mod, name, func, argc) rb_define_private_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_singleton_method(mod, name, func, argc) rb_define_singleton_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_module_function(mod, name, func, argc) rb_define_module_function(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_global_function(name, func, argc) rb_define_global_function(name, RUBY_METHOD_FUNC(func), argc) +#define rb_iterate(function, arg1, block, arg2) rb_iterate(function, arg1, RUBY_METHOD_FUNC(block), arg2) +#define rb_hash_foreach(hash, func, farg) rb_hash_foreach(hash, (int (*)(...))func, farg) +#define st_foreach(tab, func, arg) st_foreach(tab, (int (*)(...))func, arg) +#define rb_block_call(object, name, args_count, args, block_call_func, data) rb_block_call(object, name, args_count, args, RUBY_METHOD_FUNC(block_call_func), data) +#define rb_ensure(b_proc, data1, e_proc, data2) rb_ensure(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) +#define rb_rescue(b_proc, data1, e_proc, data2) rb_rescue(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) +#define rb_rescue2(b_proc, data1, e_proc, data2, ...) rb_rescue2(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2, __VA_ARGS__) +#define rb_catch(tag, func, data) rb_catch(tag, RUBY_METHOD_FUNC(func), data) +#define rb_catch_obj(tag, func, data) rb_catch_obj(tag, RUBY_METHOD_FUNC(func), data) +#define rb_proc_new(fn, arg) rb_proc_new(RUBY_METHOD_FUNC(fn), arg) +#define rb_thread_create(fn, arg) rb_thread_create(RUBY_METHOD_FUNC(fn), arg) +#define rb_define_hooked_variable(name, var, getter, setter) rb_define_hooked_variable(name, var, RUBY_METHOD_FUNC(getter), (void (*)(...))setter) +#endif + #endif diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index a44e437bba..97f6b031ef 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -284,6 +284,26 @@ VALUE string_spec_RSTRING_PTR_iterate(VALUE self, VALUE str) { return Qnil; } +VALUE string_spec_RSTRING_PTR_iterate_uint32(VALUE self, VALUE str) { + int i; + uint32_t* ptr; + int l = RSTRING_LEN(str) / sizeof(uint32_t); + + ptr = (uint32_t *)RSTRING_PTR(str); + for(i = 0; i < l; i++) { + rb_yield(UINT2NUM(ptr[i])); + } + return Qnil; +} + +VALUE string_spec_RSTRING_PTR_short_memcpy(VALUE self, VALUE str) { + // Short memcpy operations may be optimised by the compiler to a single write. + if (RSTRING_LEN(str) >= 8) { + memcpy(RSTRING_PTR(str), "Infinity", 8); + } + return str; +} + VALUE string_spec_RSTRING_PTR_assign(VALUE self, VALUE str, VALUE chr) { int i; char c; @@ -362,11 +382,11 @@ static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE r } static VALUE string_spec_rb_sprintf3(VALUE self, VALUE str) { - return rb_sprintf("Result: %"PRIsVALUE".", str); + return rb_sprintf("Result: %" PRIsVALUE ".", str); } static VALUE string_spec_rb_sprintf4(VALUE self, VALUE str) { - return rb_sprintf("Result: %+"PRIsVALUE".", str); + return rb_sprintf("Result: %+" PRIsVALUE ".", str); } static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...) { @@ -477,6 +497,8 @@ void Init_string_spec(void) { rb_define_method(cls, "RSTRING_LEN", string_spec_RSTRING_LEN, 1); rb_define_method(cls, "RSTRING_LENINT", string_spec_RSTRING_LENINT, 1); rb_define_method(cls, "RSTRING_PTR_iterate", string_spec_RSTRING_PTR_iterate, 1); + rb_define_method(cls, "RSTRING_PTR_iterate_uint32", string_spec_RSTRING_PTR_iterate_uint32, 1); + rb_define_method(cls, "RSTRING_PTR_short_memcpy", string_spec_RSTRING_PTR_short_memcpy, 1); rb_define_method(cls, "RSTRING_PTR_assign", string_spec_RSTRING_PTR_assign, 2); rb_define_method(cls, "RSTRING_PTR_set", string_spec_RSTRING_PTR_set, 3); rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2); diff --git a/spec/ruby/optional/capi/ext/symbol_spec.c b/spec/ruby/optional/capi/ext/symbol_spec.c index 27732ae58f..d2ca62d81e 100644 --- a/spec/ruby/optional/capi/ext/symbol_spec.c +++ b/spec/ruby/optional/capi/ext/symbol_spec.c @@ -7,6 +7,10 @@ extern "C" { #endif +VALUE symbol_spec_SYMBOL_P(VALUE self, VALUE obj) { + return SYMBOL_P(obj) ? Qtrue : Qfalse; +} + VALUE symbol_spec_rb_intern(VALUE self, VALUE string) { return ID2SYM(rb_intern(RSTRING_PTR(string))); } @@ -73,6 +77,7 @@ VALUE symbol_spec_rb_sym2str(VALUE self, VALUE sym) { void Init_symbol_spec(void) { VALUE cls = rb_define_class("CApiSymbolSpecs", rb_cObject); + rb_define_method(cls, "SYMBOL_P", symbol_spec_SYMBOL_P, 1); rb_define_method(cls, "rb_intern", symbol_spec_rb_intern, 1); rb_define_method(cls, "rb_intern2", symbol_spec_rb_intern2, 2); rb_define_method(cls, "rb_intern_const", symbol_spec_rb_intern_const, 1); diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c index 139652e326..743828b523 100644 --- a/spec/ruby/optional/capi/ext/thread_spec.c +++ b/spec/ruby/optional/capi/ext/thread_spec.c @@ -15,7 +15,7 @@ extern "C" { #endif -static VALUE thread_spec_rb_thread_alone() { +static VALUE thread_spec_rb_thread_alone(VALUE self) { return rb_thread_alone() ? Qtrue : Qfalse; } @@ -89,7 +89,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl_with_ubf_io(VALUE self) { return (VALUE)ret; } -static VALUE thread_spec_rb_thread_current() { +static VALUE thread_spec_rb_thread_current(VALUE self) { return rb_thread_current(); } diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c index a2cc53f54d..6eb91b76bf 100644 --- a/spec/ruby/optional/capi/ext/typed_data_spec.c +++ b/spec/ruby/optional/capi/ext/typed_data_spec.c @@ -8,7 +8,7 @@ extern "C" { #endif struct sample_typed_wrapped_struct_parent { - int foo; + int foo; }; void sample_typed_wrapped_struct_parent_free(void* st) { @@ -32,7 +32,7 @@ static const rb_data_type_t sample_typed_wrapped_struct_parent_data_type = { }; struct sample_typed_wrapped_struct { - int foo; + int foo; }; void sample_typed_wrapped_struct_free(void* st) { @@ -61,7 +61,7 @@ static const rb_data_type_t sample_typed_wrapped_struct_data_type = { }; struct sample_typed_wrapped_struct_other { - int foo; + int foo; }; void sample_typed_wrapped_struct_other_free(void* st) { @@ -86,43 +86,45 @@ static const rb_data_type_t sample_typed_wrapped_struct_other_data_type = { VALUE sdaf_alloc_typed_func(VALUE klass) { - struct sample_typed_wrapped_struct* bar = (struct sample_typed_wrapped_struct *)malloc(sizeof(struct sample_typed_wrapped_struct)); - bar->foo = 42; - return TypedData_Wrap_Struct(klass, &sample_typed_wrapped_struct_data_type, bar); + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); + bar->foo = 42; + return TypedData_Wrap_Struct(klass, &sample_typed_wrapped_struct_data_type, bar); } VALUE sdaf_typed_get_struct(VALUE self) { - struct sample_typed_wrapped_struct* bar; - TypedData_Get_Struct(self, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); + struct sample_typed_wrapped_struct* bar; + TypedData_Get_Struct(self, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); - return INT2FIX((*bar).foo); + return INT2FIX((*bar).foo); } VALUE sws_typed_wrap_struct(VALUE self, VALUE val) { - struct sample_typed_wrapped_struct* bar = (struct sample_typed_wrapped_struct *)malloc(sizeof(struct sample_typed_wrapped_struct)); - bar->foo = FIX2INT(val); - return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar); + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); + bar->foo = FIX2INT(val); + return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar); } VALUE sws_typed_get_struct(VALUE self, VALUE obj) { - struct sample_typed_wrapped_struct* bar; - TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); + struct sample_typed_wrapped_struct* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); - return INT2FIX((*bar).foo); + return INT2FIX((*bar).foo); } VALUE sws_typed_get_struct_different_type(VALUE self, VALUE obj) { - struct sample_typed_wrapped_struct_other* bar; - TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_other, &sample_typed_wrapped_struct_other_data_type, bar); + struct sample_typed_wrapped_struct_other* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_other, &sample_typed_wrapped_struct_other_data_type, bar); - return INT2FIX((*bar).foo); + return INT2FIX((*bar).foo); } VALUE sws_typed_get_struct_parent_type(VALUE self, VALUE obj) { - struct sample_typed_wrapped_struct_parent* bar; - TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_parent, &sample_typed_wrapped_struct_parent_data_type, bar); + struct sample_typed_wrapped_struct_parent* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_parent, &sample_typed_wrapped_struct_parent_data_type, bar); - return INT2FIX((*bar).foo); + return INT2FIX((*bar).foo); } VALUE sws_typed_get_struct_rdata(VALUE self, VALUE obj) { @@ -138,11 +140,10 @@ VALUE sws_typed_get_struct_data_ptr(VALUE self, VALUE obj) { } VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) { - struct sample_typed_wrapped_struct *old_struct, *new_struct; - new_struct = (struct sample_typed_wrapped_struct *)malloc(sizeof(struct sample_typed_wrapped_struct)); + struct sample_typed_wrapped_struct *new_struct; + new_struct = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); new_struct->foo = FIX2INT(new_val); - old_struct = RTYPEDDATA(obj)->data; - free(old_struct); + free(RTYPEDDATA(obj)->data); RTYPEDDATA(obj)->data = new_struct; return Qnil; } diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c index f3c6a1ba58..f7b45de6b6 100644 --- a/spec/ruby/optional/capi/ext/util_spec.c +++ b/spec/ruby/optional/capi/ext/util_spec.c @@ -60,8 +60,8 @@ static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys, int values_len = req + (opt < 0 ? -1 - opt : opt); int i = 0; - ID *ids = malloc(sizeof(VALUE) * len); - VALUE *results = malloc(sizeof(VALUE) * values_len); + ID *ids = (ID*) malloc(sizeof(VALUE) * len); + VALUE *results = (VALUE*) malloc(sizeof(VALUE) * values_len); int extracted = 0; VALUE ary = Qundef; diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index c6fddc3f64..5c272947ab 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -261,28 +261,28 @@ describe "C-API Kernel function" do describe "rb_protect" do it "will run a function with an argument" do proof = [] # Hold proof of work performed after the yield. - res = @s.rb_protect_yield(7, proof) { |x| x + 1 } - res.should == 8 + res = @s.rb_protect_yield(77, proof) { |x| x + 1 } + res.should == 78 proof[0].should == 23 end it "will allow cleanup code to run after break" do proof = [] # Hold proof of work performed after the yield. - @s.rb_protect_yield(7, proof) { |x| break } + @s.rb_protect_yield(77, proof) { |x| break } proof[0].should == 23 end it "will allow cleanup code to run after break with value" do proof = [] # Hold proof of work performed after the yield. - res = @s.rb_protect_yield(7, proof) { |x| break x + 1 } - res.should == 8 + res = @s.rb_protect_yield(77, proof) { |x| break x + 1 } + res.should == 78 proof[0].should == 23 end it "will allow cleanup code to run after a raise" do proof = [] # Hold proof of work performed after the yield. -> do - @s.rb_protect_yield(7, proof) { |x| raise NameError} + @s.rb_protect_yield(77, proof) { |x| raise NameError} end.should raise_error(NameError) proof[0].should == 23 end @@ -290,7 +290,7 @@ describe "C-API Kernel function" do it "will return nil if an error was raised" do proof = [] # Hold proof of work performed after the yield. -> do - @s.rb_protect_yield(7, proof) { |x| raise NameError} + @s.rb_protect_yield(77, proof) { |x| raise NameError} end.should raise_error(NameError) proof[0].should == 23 proof[1].should == nil @@ -316,47 +316,47 @@ describe "C-API Kernel function" do describe "rb_rescue" do before :each do @proc = -> x { x } - @raise_proc_returns_sentinel = -> *_ { :raise_proc_executed } - @raise_proc_returns_arg = -> *a { a } + @rescue_proc_returns_sentinel = -> *_ { :rescue_proc_executed } + @rescue_proc_returns_arg = -> *a { a } @arg_error_proc = -> *_ { raise ArgumentError, '' } @std_error_proc = -> *_ { raise StandardError, '' } @exc_error_proc = -> *_ { raise Exception, '' } end it "executes passed function" do - @s.rb_rescue(@proc, :no_exc, @raise_proc_returns_arg, :exc).should == :no_exc + @s.rb_rescue(@proc, :no_exc, @rescue_proc_returns_arg, :exc).should == :no_exc end - it "executes passed 'raise function' if a StandardError exception is raised" do - @s.rb_rescue(@arg_error_proc, nil, @raise_proc_returns_sentinel, :exc).should == :raise_proc_executed - @s.rb_rescue(@std_error_proc, nil, @raise_proc_returns_sentinel, :exc).should == :raise_proc_executed + it "executes the passed 'rescue function' if a StandardError exception is raised" do + @s.rb_rescue(@arg_error_proc, nil, @rescue_proc_returns_sentinel, :exc).should == :rescue_proc_executed + @s.rb_rescue(@std_error_proc, nil, @rescue_proc_returns_sentinel, :exc).should == :rescue_proc_executed end - it "passes the user supplied argument to the 'raise function' if a StandardError exception is raised" do - arg1, _ = @s.rb_rescue(@arg_error_proc, nil, @raise_proc_returns_arg, :exc1) + it "passes the user supplied argument to the 'rescue function' if a StandardError exception is raised" do + arg1, _ = @s.rb_rescue(@arg_error_proc, nil, @rescue_proc_returns_arg, :exc1) arg1.should == :exc1 - arg2, _ = @s.rb_rescue(@std_error_proc, nil, @raise_proc_returns_arg, :exc2) + arg2, _ = @s.rb_rescue(@std_error_proc, nil, @rescue_proc_returns_arg, :exc2) arg2.should == :exc2 end - it "passes the raised exception to the 'raise function' if a StandardError exception is raised" do - _, exc1 = @s.rb_rescue(@arg_error_proc, nil, @raise_proc_returns_arg, :exc) + it "passes the raised exception to the 'rescue function' if a StandardError exception is raised" do + _, exc1 = @s.rb_rescue(@arg_error_proc, nil, @rescue_proc_returns_arg, :exc) exc1.class.should == ArgumentError - _, exc2 = @s.rb_rescue(@std_error_proc, nil, @raise_proc_returns_arg, :exc) + _, exc2 = @s.rb_rescue(@std_error_proc, nil, @rescue_proc_returns_arg, :exc) exc2.class.should == StandardError end it "raises an exception if passed function raises an exception other than StandardError" do - -> { @s.rb_rescue(@exc_error_proc, nil, @raise_proc_returns_arg, nil) }.should raise_error(Exception) + -> { @s.rb_rescue(@exc_error_proc, nil, @rescue_proc_returns_arg, nil) }.should raise_error(Exception) end - it "raises an exception if any exception is raised inside 'raise function'" do + it "raises an exception if any exception is raised inside the 'rescue function'" do -> { @s.rb_rescue(@std_error_proc, nil, @std_error_proc, nil) }.should raise_error(StandardError) end - it "makes $! available only during 'raise function' execution" do + it "makes $! available only during the 'rescue function' execution" do @s.rb_rescue(@std_error_proc, nil, -> *_ { $! }, nil).class.should == StandardError $!.should == nil end @@ -368,6 +368,10 @@ describe "C-API Kernel function" do proc_caller { break :value }.should == :value end + + it "returns nil if the 'rescue function' is null" do + @s.rb_rescue(@std_error_proc, nil, nil, nil).should == nil + end end describe "rb_rescue2" do diff --git a/spec/ruby/optional/capi/language_spec.rb b/spec/ruby/optional/capi/language_spec.rb new file mode 100644 index 0000000000..7605332fbd --- /dev/null +++ b/spec/ruby/optional/capi/language_spec.rb @@ -0,0 +1,31 @@ +require_relative 'spec_helper' + +load_extension("language") + +describe "C language construct" do + before :each do + @s = CApiLanguageSpecs.new + end + + describe "switch (VALUE)" do + it "works for Qtrue" do + @s.switch(true).should == :true + end + + it "works for Qfalse" do + @s.switch(false).should == :false + end + + it "works for Qnil" do + @s.switch(nil).should == :nil + end + + it "works for Qundef" do + @s.switch(:undef).should == :undef + end + + it "works for the default case" do + @s.switch(Object.new).should == :default + end + end +end diff --git a/spec/ruby/optional/capi/numeric_spec.rb b/spec/ruby/optional/capi/numeric_spec.rb index d76f353850..de7e180414 100644 --- a/spec/ruby/optional/capi/numeric_spec.rb +++ b/spec/ruby/optional/capi/numeric_spec.rb @@ -143,6 +143,34 @@ describe "CApiNumericSpecs" do end end + describe "NUM2SHORT" do + it "raises a TypeError if passed nil" do + -> { @s.NUM2SHORT(nil) }.should raise_error(TypeError) + end + + it "converts a Float" do + @s.NUM2SHORT(4.2).should == 4 + end + + it "converts a Fixnum" do + @s.NUM2SHORT(5).should == 5 + end + + it "converts -1 to an signed number" do + @s.NUM2SHORT(-1).should == -1 + end + + it "raises a RangeError if the value is more than 32bits" do + -> { @s.NUM2SHORT(0xffff_ffff+1) }.should raise_error(RangeError) + end + + it "calls #to_int to coerce the value" do + obj = mock("number") + obj.should_receive(:to_int).and_return(2) + @s.NUM2SHORT(obj).should == 2 + end + end + describe "INT2NUM" do it "raises a TypeError if passed nil" do -> { @s.INT2NUM(nil) }.should raise_error(TypeError) diff --git a/spec/ruby/optional/capi/proc_spec.rb b/spec/ruby/optional/capi/proc_spec.rb index 9f9a37cc98..ff119416f6 100644 --- a/spec/ruby/optional/capi/proc_spec.rb +++ b/spec/ruby/optional/capi/proc_spec.rb @@ -54,6 +54,25 @@ describe "C-API Proc function" do @p.rb_proc_call(prc, [6, 7]).should == 42 end end + + describe "rb_obj_is_proc" do + it "returns true for Proc" do + prc = Proc.new {|a,b| a * b } + @p.rb_obj_is_proc(prc).should be_true + end + + it "returns true for subclass of Proc" do + prc = Class.new(Proc).new {} + @p.rb_obj_is_proc(prc).should be_true + end + + it "returns false for non Proc instances" do + @p.rb_obj_is_proc("aoeui").should be_false + @p.rb_obj_is_proc(123).should be_false + @p.rb_obj_is_proc(true).should be_false + @p.rb_obj_is_proc([]).should be_false + end + end end describe "C-API when calling Proc.new from a C function" do diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb index eda4964b69..30e6196d05 100644 --- a/spec/ruby/optional/capi/spec_helper.rb +++ b/spec/ruby/optional/capi/spec_helper.rb @@ -8,12 +8,17 @@ require 'rbconfig' OBJDIR ||= File.expand_path("../../../ext/#{RUBY_ENGINE}/#{RUBY_VERSION}", __FILE__) def object_path - mkdir_p(OBJDIR) - OBJDIR + path = OBJDIR + if ENV['SPEC_CAPI_CXX'] == 'true' + path = "#{path}/cxx" + end + mkdir_p(path) + path end def compile_extension(name) debug = false + cxx = ENV['SPEC_CAPI_CXX'] == 'true' run_mkmf_in_process = RUBY_ENGINE == 'truffleruby' core_ext_dir = File.expand_path("../ext", __FILE__) @@ -54,7 +59,11 @@ def compile_extension(name) Dir.mkdir(tmpdir) begin ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"].each do |file| - cp file, "#{tmpdir}/#{File.basename(file)}" + if cxx and file.end_with?('.c') + cp file, "#{tmpdir}/#{File.basename(file, '.c')}.cpp" + else + cp file, "#{tmpdir}/#{File.basename(file)}" + end end Dir.chdir(tmpdir) do @@ -64,11 +73,13 @@ def compile_extension(name) init_mkmf unless required create_makefile(ext, tmpdir) else - File.write("extconf.rb", "require 'mkmf'\n" + - "$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')\n" + + File.write("extconf.rb", <<-RUBY) + require 'mkmf' + $ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ') # MRI magic to consider building non-bundled extensions - "$extout = nil\n" + - "create_makefile(#{ext.inspect})\n") + $extout = nil + create_makefile(#{ext.inspect}) + RUBY output = ruby_exe("extconf.rb") raise "extconf failed:\n#{output}" unless $?.success? $stderr.puts output if debug diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 1ad35b9e8a..243765cdbe 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -513,6 +513,24 @@ describe "C-API String function" do end chars.should == [55, 48, 227, 131, 145, 227, 130, 175] end + + it "returns a pointer which can be cast and used as another type" do + s = "70パク". + encode(Encoding::UTF_16LE). + force_encoding(Encoding::UTF_16LE). + encode(Encoding::UTF_8) + + ints = [] + @s.RSTRING_PTR_iterate_uint32(s) do |i| + ints << i + end + ints.should == s.unpack('LL') + end + + it "allows a short memcpy to the string which may be converted to a single write operation by the compiler" do + str = " " + @s.RSTRING_PTR_short_memcpy(str).should == "Infinity" + end end describe "RSTRING_LEN" do diff --git a/spec/ruby/optional/capi/symbol_spec.rb b/spec/ruby/optional/capi/symbol_spec.rb index 7f345f879f..0d71c1c711 100644 --- a/spec/ruby/optional/capi/symbol_spec.rb +++ b/spec/ruby/optional/capi/symbol_spec.rb @@ -8,6 +8,16 @@ describe "C-API Symbol function" do @s = CApiSymbolSpecs.new end + describe "SYMBOL_P" do + it "returns true for a Symbol" do + @s.SYMBOL_P(:foo).should == true + end + + it "returns false for non-Symbols" do + @s.SYMBOL_P('bar').should == false + end + end + describe "rb_intern" do it "converts a string to a symbol, uniquely" do @s.rb_intern("test_symbol").should == :test_symbol