diff options
Diffstat (limited to 'spec/ruby')
46 files changed, 634 insertions, 99 deletions
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index 50d8af5931..8d18f1102d 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -59,8 +59,8 @@ There are a few extra specific matchers used in the couple specs that need it. (1 + 2).should == 3 # Calls #== (1 + 2).should_not == 5 -File.should equal(File) # Calls #equal? (tests identity) -(1 + 2).should eql(3) # Calls #eql? (Hash equality) +File.should.equal?(File) # Calls #equal? (tests identity) +(1 + 2).should.eql?(3) # Calls #eql? (Hash equality) 1.should < 2 2.should <= 2 @@ -73,11 +73,14 @@ File.should equal(File) # Calls #equal? (tests identity) #### Predicate matchers ```ruby -[].should be_empty # Calls #empty? -[1,2,3].should include(2) # Calls #include? +[].should.empty? +[1,2,3].should.include?(2) + +"hello".should.start_with?("h") +"hello".should.end_with?("o") (0.1 + 0.2).should be_close(0.3, TOLERANCE) # (0.2-0.1).abs < TOLERANCE -(0.0/0.0).should be_nan # Calls Float#nan? +(0.0/0.0).should.nan? (1.0/0.0).should be_positive_infinity (-1.0/0.0).should be_negative_infinity @@ -85,7 +88,7 @@ File.should equal(File) # Calls #equal? (tests identity) 3.14.should be_kind_of(Numeric) # Calls #is_a? Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric) -3.14.should respond_to(:to_i) # Calls #respond_to? +3.14.should.respond_to?(:to_i) Fixnum.should have_instance_method(:+) Array.should have_method(:new) ``` @@ -103,7 +106,7 @@ Also `have_constant`, `have_private_instance_method`, `have_singleton_method`, e raise "oops" }.should raise_error(RuntimeError) { |e| # Custom checks on the Exception object - e.message.should include("oops") + e.message.should.include?("oops") e.cause.should == nil } ``` diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb index 42071ed0cd..2791a2eb5d 100644 --- a/spec/ruby/core/array/fixtures/classes.rb +++ b/spec/ruby/core/array/fixtures/classes.rb @@ -144,7 +144,7 @@ module ArraySpecs end def self.universal_pack_object - obj = mock("string float int") + obj = mock("string float int".freeze) obj.stub!(:to_int).and_return(1) obj.stub!(:to_str).and_return("1") obj.stub!(:to_f).and_return(1.0) diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index d6b4547b2b..f36890fa4e 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -466,6 +466,12 @@ describe :array_slice, shared: true do obj = 8e19 -> { array.send(@method, obj) }.should raise_error(RangeError) + + # boundary value when longs are 64 bits + -> { array.send(@method, 2.0**63) }.should raise_error(RangeError) + + # just under the boundary value when longs are 64 bits + array.send(@method, max_long.to_f.prev_float).should == nil end it "raises a RangeError when the length is out of range of Fixnum" do diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb index 15e42d247e..100edc8455 100644 --- a/spec/ruby/core/enumerator/new_spec.rb +++ b/spec/ruby/core/enumerator/new_spec.rb @@ -75,5 +75,36 @@ describe "Enumerator.new" do enum.to_a.should == ["a\n", "b\n", "c"] end end + + describe 'yielded values' do + it 'handles yield arguments properly' do + Enumerator.new { |y| y.yield(1) }.to_a.should == [1] + Enumerator.new { |y| y.yield(1) }.first.should == 1 + + Enumerator.new { |y| y.yield([1]) }.to_a.should == [[1]] + Enumerator.new { |y| y.yield([1]) }.first.should == [1] + + Enumerator.new { |y| y.yield(1, 2) }.to_a.should == [[1, 2]] + Enumerator.new { |y| y.yield(1, 2) }.first.should == [1, 2] + + Enumerator.new { |y| y.yield([1, 2]) }.to_a.should == [[1, 2]] + Enumerator.new { |y| y.yield([1, 2]) }.first.should == [1, 2] + end + + it 'handles << arguments properly' do + Enumerator.new { |y| y.<<(1) }.to_a.should == [1] + Enumerator.new { |y| y.<<(1) }.first.should == 1 + + Enumerator.new { |y| y.<<([1]) }.to_a.should == [[1]] + Enumerator.new { |y| y.<<([1]) }.first.should == [1] + + # << doesn't accept multiple arguments + # Enumerator.new { |y| y.<<(1, 2) }.to_a.should == [[1, 2]] + # Enumerator.new { |y| y.<<(1, 2) }.first.should == [1, 2] + + Enumerator.new { |y| y.<<([1, 2]) }.to_a.should == [[1, 2]] + Enumerator.new { |y| y.<<([1, 2]) }.first.should == [1, 2] + end + end end end diff --git a/spec/ruby/core/enumerator/yielder/append_spec.rb b/spec/ruby/core/enumerator/yielder/append_spec.rb index dac66585a5..7f7059774d 100644 --- a/spec/ruby/core/enumerator/yielder/append_spec.rb +++ b/spec/ruby/core/enumerator/yielder/append_spec.rb @@ -21,4 +21,27 @@ describe "Enumerator::Yielder#<<" do y = Enumerator::Yielder.new {|x| x + 1} (y << 1).should equal(y) end + + context "when multiple arguments passed" do + ruby_version_is '' ... '2.6' do + it "yields the arguments list to the block" do + ary = [] + y = Enumerator::Yielder.new { |*x| ary << x } + y.<<(1, 2) + + ary.should == [[1, 2]] + end + end + + ruby_version_is '2.6' do + it "raises an ArgumentError" do + ary = [] + y = Enumerator::Yielder.new { |*x| ary << x } + + -> { + y.<<(1, 2) + }.should raise_error(ArgumentError, /wrong number of arguments/) + end + end + end end diff --git a/spec/ruby/core/enumerator/yielder/yield_spec.rb b/spec/ruby/core/enumerator/yielder/yield_spec.rb index 58fc8e007a..acfdf114b6 100644 --- a/spec/ruby/core/enumerator/yielder/yield_spec.rb +++ b/spec/ruby/core/enumerator/yielder/yield_spec.rb @@ -20,4 +20,14 @@ describe "Enumerator::Yielder#yield" do y = Enumerator::Yielder.new {|x| x + 1} y.yield(1).should == 2 end + + context "when multiple arguments passed" do + it "yields the arguments list to the block" do + ary = [] + y = Enumerator::Yielder.new { |*x| ary << x } + y.yield(1, 2) + + ary.should == [[1, 2]] + end + end end diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb index 4b5ef9386e..f9a8c9bbd1 100644 --- a/spec/ruby/core/integer/left_shift_spec.rb +++ b/spec/ruby/core/integer/left_shift_spec.rb @@ -71,8 +71,11 @@ describe "Integer#<< (with n << m)" do it "calls #to_int to convert the argument to an Integer" do obj = mock("4") obj.should_receive(:to_int).and_return(4) - (3 << obj).should == 48 + + obj = mock("to_int_neg_bignum") + obj.should_receive(:to_int).and_return(-bignum_value) + (3 << obj).should == 0 end it "raises a TypeError when #to_int does not return an Integer" do diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb index 3eeaf3eb2f..1eac6cb5bc 100644 --- a/spec/ruby/core/integer/right_shift_spec.rb +++ b/spec/ruby/core/integer/right_shift_spec.rb @@ -71,8 +71,11 @@ describe "Integer#>> (with n >> m)" do it "calls #to_int to convert the argument to an Integer" do obj = mock("2") obj.should_receive(:to_int).and_return(2) - (8 >> obj).should == 2 + + obj = mock("to_int_bignum") + obj.should_receive(:to_int).and_return(bignum_value) + (8 >> obj).should == 0 end it "raises a TypeError when #to_int does not return an Integer" do diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 69977194e9..28fdb5e451 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -242,6 +242,15 @@ describe :kernel_require, shared: true do @object.require("load_fixture").should be_true ScratchPad.recorded.should == [:loaded] end + + ruby_bug "#16926", "2.7"..."2.8" do + it "does not load a feature twice when $LOAD_PATH has been modified" do + $LOAD_PATH.replace [CODE_LOADING_DIR] + @object.require("load_fixture").should be_true + $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR] + @object.require("load_fixture").should be_false + end + end end describe "(file extensions)" do diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index 6f0ca49dcf..85a0d067d1 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -294,6 +294,32 @@ describe "Module#autoload" do ScratchPad.recorded.should == [nil, nil] @check.call.should == ["constant", nil] end + + it "does not raise an error if the autoload constant was not defined" do + module ModuleSpecs::Autoload + autoload :RequiredDirectlyNoConstant, fixture(__FILE__, "autoload_required_directly_no_constant.rb") + end + @path = fixture(__FILE__, "autoload_required_directly_no_constant.rb") + @remove << :RequiredDirectlyNoConstant + @check = -> { + [ + defined?(ModuleSpecs::Autoload::RequiredDirectlyNoConstant), + ModuleSpecs::Autoload.constants(false).include?(:RequiredDirectlyNoConstant), + ModuleSpecs::Autoload.const_defined?(:RequiredDirectlyNoConstant), + ModuleSpecs::Autoload.autoload?(:RequiredDirectlyNoConstant) + ] + } + ScratchPad.record @check + @check.call.should == ["constant", true, true, @path] + $:.push File.dirname(@path) + begin + require "autoload_required_directly_no_constant.rb" + ensure + $:.pop + end + ScratchPad.recorded.should == [nil, true, false, nil] + @check.call.should == [nil, true, false, nil] + end end describe "after the autoload is triggered by require" do diff --git a/spec/ruby/core/module/fixtures/autoload_required_directly_no_constant.rb b/spec/ruby/core/module/fixtures/autoload_required_directly_no_constant.rb new file mode 100644 index 0000000000..25e08c1129 --- /dev/null +++ b/spec/ruby/core/module/fixtures/autoload_required_directly_no_constant.rb @@ -0,0 +1,2 @@ +block = ScratchPad.recorded +ScratchPad.record(block.call) diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb index d38659c257..67f9274f32 100644 --- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb @@ -29,33 +29,35 @@ describe 'Thread::Backtrace::Location#absolute_path' do end end - platform_is_not :windows do - before :each do - @file = fixture(__FILE__, "absolute_path.rb") - @symlink = tmp("symlink.rb") - File.symlink(@file, @symlink) - ScratchPad.record [] - end - - after :each do - rm_r @symlink - end - - it "returns a canonical path without symlinks, even when __FILE__ does not" do - realpath = File.realpath(@symlink) - realpath.should_not == @symlink - - load @symlink - ScratchPad.recorded.should == [@symlink, realpath] - end - - it "returns a canonical path without symlinks, even when __FILE__ is removed" do - realpath = File.realpath(@symlink) - realpath.should_not == @symlink - - ScratchPad << -> { rm_r(@symlink) } - load @symlink - ScratchPad.recorded.should == [@symlink, realpath] + context "canonicalization" do + platform_is_not :windows do + before :each do + @file = fixture(__FILE__, "absolute_path.rb") + @symlink = tmp("symlink.rb") + File.symlink(@file, @symlink) + ScratchPad.record [] + end + + after :each do + rm_r @symlink + end + + it "returns a canonical path without symlinks, even when __FILE__ does not" do + realpath = File.realpath(@symlink) + realpath.should_not == @symlink + + load @symlink + ScratchPad.recorded.should == [@symlink, realpath] + end + + it "returns a canonical path without symlinks, even when __FILE__ is removed" do + realpath = File.realpath(@symlink) + realpath.should_not == @symlink + + ScratchPad << -> { rm_r(@symlink) } + load @symlink + ScratchPad.recorded.should == [@symlink, realpath] + end end end end diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/path.rb b/spec/ruby/core/thread/backtrace/location/fixtures/path.rb new file mode 100644 index 0000000000..fba34cb0bc --- /dev/null +++ b/spec/ruby/core/thread/backtrace/location/fixtures/path.rb @@ -0,0 +1,2 @@ +ScratchPad << __FILE__ +ScratchPad << caller_locations(0)[0].path diff --git a/spec/ruby/core/thread/backtrace/location/path_spec.rb b/spec/ruby/core/thread/backtrace/location/path_spec.rb index b1a3439747..93eb4982d8 100644 --- a/spec/ruby/core/thread/backtrace/location/path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/path_spec.rb @@ -86,4 +86,27 @@ describe 'Thread::Backtrace::Location#path' do end end end + + context "canonicalization" do + platform_is_not :windows do + before :each do + @file = fixture(__FILE__, "path.rb") + @symlink = tmp("symlink.rb") + File.symlink(@file, @symlink) + ScratchPad.record [] + end + + after :each do + rm_r @symlink + end + + it "returns a non-canonical path with symlinks, the same as __FILE__" do + realpath = File.realpath(@symlink) + realpath.should_not == @symlink + + load @symlink + ScratchPad.recorded.should == [@symlink, @symlink] + end + end + end end diff --git a/spec/ruby/core/tracepoint/binding_spec.rb b/spec/ruby/core/tracepoint/binding_spec.rb index f37753602e..6a7ef5f85a 100644 --- a/spec/ruby/core/tracepoint/binding_spec.rb +++ b/spec/ruby/core/tracepoint/binding_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#binding' do def test @@ -8,6 +9,7 @@ describe 'TracePoint#binding' do it 'return the generated binding object from event' do bindings = [] TracePoint.new(:return) { |tp| + next unless TracePointSpec.target_thread? bindings << tp.binding }.enable { test diff --git a/spec/ruby/core/tracepoint/callee_id_spec.rb b/spec/ruby/core/tracepoint/callee_id_spec.rb index d340290d8b..cc08a45504 100644 --- a/spec/ruby/core/tracepoint/callee_id_spec.rb +++ b/spec/ruby/core/tracepoint/callee_id_spec.rb @@ -7,6 +7,7 @@ describe "TracePoint#callee_id" do obj = TracePointSpec::ClassWithMethodAlias.new TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? a << tp.callee_id end.enable do obj.m_alias diff --git a/spec/ruby/core/tracepoint/defined_class_spec.rb b/spec/ruby/core/tracepoint/defined_class_spec.rb index 72536e6a56..4593db6d1f 100644 --- a/spec/ruby/core/tracepoint/defined_class_spec.rb +++ b/spec/ruby/core/tracepoint/defined_class_spec.rb @@ -5,6 +5,7 @@ describe 'TracePoint#defined_class' do it 'returns class or module of the method being called' do last_class_name = nil TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? last_class_name = tp.defined_class end.enable do TracePointSpec::B.new.foo diff --git a/spec/ruby/core/tracepoint/disable_spec.rb b/spec/ruby/core/tracepoint/disable_spec.rb index 2ab9b987f4..73a31b3b81 100644 --- a/spec/ruby/core/tracepoint/disable_spec.rb +++ b/spec/ruby/core/tracepoint/disable_spec.rb @@ -1,9 +1,11 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#disable' do it 'returns true if trace was enabled' do called = false trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? called = true end @@ -25,6 +27,7 @@ describe 'TracePoint#disable' do it 'returns false if trace was disabled' do called = false trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? called = true end diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb index 15eb2f1616..aa0c3aa0dc 100644 --- a/spec/ruby/core/tracepoint/enable_spec.rb +++ b/spec/ruby/core/tracepoint/enable_spec.rb @@ -1,20 +1,21 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#enable' do - # def test; end - describe 'without a block' do - it 'returns true if trace was enabled' do + it 'returns false if trace was disabled' do called = false trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? called = true end line_event = true called.should == false - trace.enable + ret = trace.enable begin + ret.should == false line_event = true called.should == true ensure @@ -22,30 +23,27 @@ describe 'TracePoint#enable' do end end - it 'returns false if trace was disabled' do + it 'returns true if trace was already enabled' do called = false trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? called = true end - trace.enable.should == false - begin - line_event = true - called.should == true - ensure - trace.disable - end - - called = false line_event = true called.should == false - trace.enable.should == false + ret = trace.enable begin + ret.should == false + + trace.enable.should == true + line_event = true called.should == true ensure trace.disable + trace.should_not.enabled? end end end @@ -54,13 +52,38 @@ describe 'TracePoint#enable' do it 'enables the trace object within a block' do event_name = nil TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? event_name = tp.event end.enable { event_name.should equal(:line) } end + it 'enables the trace object for any thread' do + threads = [] + trace = TracePoint.new(:line) do |tp| + # Runs on purpose on any Thread + threads << Thread.current + end + + thread = nil + trace.enable do + line_event = true + thread = Thread.new do + event_in_other_thread = true + end + thread.join + end + + threads = threads.uniq + threads.should.include?(Thread.current) + threads.should.include?(thread) + end + it 'can accept arguments within a block but it should not yield arguments' do event_name = nil - trace = TracePoint.new(:line) { |tp| event_name = tp.event } + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + end trace.enable do |*args| event_name.should equal(:line) args.should == [] @@ -87,7 +110,10 @@ describe 'TracePoint#enable' do it 'disables the trace object outside the block' do called = false - trace = TracePoint.new(:line) { called = true } + trace = TracePoint.new(:line) do + next unless TracePointSpec.target_thread? + called = true + end trace.enable { line_event = true } @@ -96,6 +122,35 @@ describe 'TracePoint#enable' do end end + describe "when nested" do + it "enables both TracePoints but only calls the respective callbacks" do + called = false + first = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + all = [] + inspects = [] + second = TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + all << tp + inspects << tp.inspect + } + + line = nil + first.enable do + second.enable do + line = __LINE__ + end + end + + all.uniq.should == [second] + inspects.uniq.should == ["#<TracePoint:line@#{__FILE__}:#{line}>"] + called.should == true + end + end + ruby_version_is "2.6" do describe 'target: option' do before :each do @@ -104,6 +159,7 @@ describe 'TracePoint#enable' do it 'enables trace point for specific location' do trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.method_id end @@ -121,6 +177,7 @@ describe 'TracePoint#enable' do it 'traces all the events triggered in specified location' do trace = TracePoint.new(:line, :call, :return, :b_call, :b_return) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.event end @@ -140,6 +197,7 @@ describe 'TracePoint#enable' do it 'does not trace events in nested locations' do trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.method_id end @@ -177,6 +235,7 @@ describe 'TracePoint#enable' do end trace = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.lineno end @@ -193,6 +252,7 @@ describe 'TracePoint#enable' do describe 'option value' do it 'accepts Method' do trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.method_id end @@ -208,6 +268,7 @@ describe 'TracePoint#enable' do it 'accepts UnboundMethod' do trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.method_id end @@ -225,6 +286,7 @@ describe 'TracePoint#enable' do it 'accepts Proc' do trace = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.lineno end @@ -242,6 +304,7 @@ describe 'TracePoint#enable' do it "raises ArgumentError if target object cannot trigger specified event" do trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.method_id end @@ -255,8 +318,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if passed not Method/UnboundMethod/Proc" do - trace = TracePoint.new(:call) do |tp| - end + trace = TracePoint.new(:call) {} -> { trace.enable(target: Object.new) do @@ -266,8 +328,7 @@ describe 'TracePoint#enable' do context "nested enabling and disabling" do it "raises ArgumentError if trace point already enabled with target is re-enabled with target" do - trace = TracePoint.new(:b_call) do - end + trace = TracePoint.new(:b_call) {} -> { trace.enable(target: -> {}) do @@ -278,8 +339,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if trace point already enabled without target is re-enabled with target" do - trace = TracePoint.new(:b_call) do - end + trace = TracePoint.new(:b_call) {} -> { trace.enable do @@ -290,8 +350,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if trace point already enabled with target is re-enabled without target" do - trace = TracePoint.new(:b_call) do - end + trace = TracePoint.new(:b_call) {} -> { trace.enable(target: -> {}) do @@ -302,8 +361,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if trace point already enabled with target is disabled with block" do - trace = TracePoint.new(:b_call) do - end + trace = TracePoint.new(:b_call) {} -> { trace.enable(target: -> {}) do @@ -315,10 +373,12 @@ describe 'TracePoint#enable' do it "traces events when trace point with target is enabled in another trace point enabled without target" do trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :outer end trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :inner end @@ -335,10 +395,12 @@ describe 'TracePoint#enable' do it "traces events when trace point with target is enabled in another trace point enabled with target" do trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :outer end trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :inner end @@ -355,10 +417,12 @@ describe 'TracePoint#enable' do it "traces events when trace point without target is enabled in another trace point enabled with target" do trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :outer end trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << :inner end @@ -382,6 +446,7 @@ describe 'TracePoint#enable' do it "traces :line events only on specified line of code" do trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.lineno end @@ -401,8 +466,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if :target option isn't specified" do - trace = TracePoint.new(:line) do |tp| - end + trace = TracePoint.new(:line) {} -> { trace.enable(target_line: 67) do @@ -411,8 +475,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if :line event isn't registered" do - trace = TracePoint.new(:call) do |tp| - end + trace = TracePoint.new(:call) {} target = -> { x = 1 @@ -429,8 +492,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if :target_line value is out of target code lines range" do - trace = TracePoint.new(:line) do |tp| - end + trace = TracePoint.new(:line) {} -> { trace.enable(target_line: 1, target: -> { }) do @@ -439,8 +501,7 @@ describe 'TracePoint#enable' do end it "raises TypeError if :target_line value couldn't be coerced to Integer" do - trace = TracePoint.new(:line) do |tp| - end + trace = TracePoint.new(:line) {} -> { trace.enable(target_line: Object.new, target: -> { }) do @@ -449,8 +510,7 @@ describe 'TracePoint#enable' do end it "raises ArgumentError if :target_line value is negative" do - trace = TracePoint.new(:line) do |tp| - end + trace = TracePoint.new(:line) {} -> { trace.enable(target_line: -2, target: -> { }) do @@ -460,6 +520,7 @@ describe 'TracePoint#enable' do it "accepts value that could be coerced to Integer" do trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? ScratchPad << tp.lineno end diff --git a/spec/ruby/core/tracepoint/enabled_spec.rb b/spec/ruby/core/tracepoint/enabled_spec.rb index dbc3c214c5..0e9566a02c 100644 --- a/spec/ruby/core/tracepoint/enabled_spec.rb +++ b/spec/ruby/core/tracepoint/enabled_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#enabled?' do it 'returns true when current status of the trace is enable' do diff --git a/spec/ruby/core/tracepoint/eval_script_spec.rb b/spec/ruby/core/tracepoint/eval_script_spec.rb index 1d8e425a9a..ccf7fb5975 100644 --- a/spec/ruby/core/tracepoint/eval_script_spec.rb +++ b/spec/ruby/core/tracepoint/eval_script_spec.rb @@ -13,6 +13,7 @@ ruby_version_is "2.6" do CODE TracePoint.new(:script_compiled) do |e| + next unless TracePointSpec.target_thread? ScratchPad << e.eval_script end.enable do eval script diff --git a/spec/ruby/core/tracepoint/event_spec.rb b/spec/ruby/core/tracepoint/event_spec.rb index 019d0c3253..9dea24d125 100644 --- a/spec/ruby/core/tracepoint/event_spec.rb +++ b/spec/ruby/core/tracepoint/event_spec.rb @@ -5,6 +5,7 @@ describe 'TracePoint#event' do it 'returns the type of event' do event_name = nil TracePoint.new(:end, :call) do |tp| + next unless TracePointSpec.target_thread? event_name = tp.event end.enable do TracePointSpec.test diff --git a/spec/ruby/core/tracepoint/fixtures/classes.rb b/spec/ruby/core/tracepoint/fixtures/classes.rb index 49c70e1915..3ab1b00b16 100644 --- a/spec/ruby/core/tracepoint/fixtures/classes.rb +++ b/spec/ruby/core/tracepoint/fixtures/classes.rb @@ -1,4 +1,10 @@ module TracePointSpec + @thread = Thread.current + + def self.target_thread? + Thread.current == @thread + end + class ClassWithMethodAlias def m end diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb index 465f01e229..1e48caa215 100644 --- a/spec/ruby/core/tracepoint/inspect_spec.rb +++ b/spec/ruby/core/tracepoint/inspect_spec.rb @@ -10,6 +10,7 @@ describe 'TracePoint#inspect' do inspect = nil line = nil TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? inspect ||= tp.inspect }.enable do line = __LINE__ @@ -22,6 +23,7 @@ describe 'TracePoint#inspect' do inspect = nil line = nil TracePoint.new(:class) { |tp| + next unless TracePointSpec.target_thread? inspect ||= tp.inspect }.enable do line = __LINE__ + 1 diff --git a/spec/ruby/core/tracepoint/lineno_spec.rb b/spec/ruby/core/tracepoint/lineno_spec.rb index a4d7e77e8d..77b3ac8b54 100644 --- a/spec/ruby/core/tracepoint/lineno_spec.rb +++ b/spec/ruby/core/tracepoint/lineno_spec.rb @@ -1,10 +1,20 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#lineno' do it 'returns the line number of the event' do lineno = nil - TracePoint.new(:line) { |tp| lineno = tp.lineno }.enable do - lineno.should == 7 + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + lineno = tp.lineno + }.enable do + line_event = true end + lineno.should == __LINE__ - 2 + end + + it 'raises RuntimeError if accessed from outside' do + tp = TracePoint.new(:line) {} + -> { tp.lineno }.should raise_error(RuntimeError, 'access from outside') end end diff --git a/spec/ruby/core/tracepoint/method_id_spec.rb b/spec/ruby/core/tracepoint/method_id_spec.rb index 82254d1299..43e23248b7 100644 --- a/spec/ruby/core/tracepoint/method_id_spec.rb +++ b/spec/ruby/core/tracepoint/method_id_spec.rb @@ -1,12 +1,14 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#method_id' do - def test; end - it 'returns the name at the definition of the method being called' do method_name = nil - TracePoint.new(:call) { |tp| method_name = tp.method_id}.enable do - test + TracePoint.new(:call) { |tp| + next unless TracePointSpec.target_thread? + method_name = tp.method_id + }.enable do + TracePointSpec.test method_name.should equal(:test) end end diff --git a/spec/ruby/core/tracepoint/new_spec.rb b/spec/ruby/core/tracepoint/new_spec.rb index 991048514c..e53c2b04a2 100644 --- a/spec/ruby/core/tracepoint/new_spec.rb +++ b/spec/ruby/core/tracepoint/new_spec.rb @@ -8,7 +8,10 @@ describe 'TracePoint.new' do it 'includes :line event when event is not specified' do event_name = nil - TracePoint.new() { |tp| event_name = tp.event }.enable do + TracePoint.new { |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + }.enable do event_name.should equal(:line) event_name = nil @@ -25,7 +28,10 @@ describe 'TracePoint.new' do event_name = nil (o = mock('line')).should_receive(:to_sym).and_return(:line) - TracePoint.new(o) { |tp| event_name = tp.event }.enable do + TracePoint.new(o) { |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + }.enable do line_event = true event_name.should == :line end @@ -34,6 +40,7 @@ describe 'TracePoint.new' do it 'includes multiple events when multiple event names are passed as params' do event_name = nil TracePoint.new(:end, :call) do |tp| + next unless TracePointSpec.target_thread? event_name = tp.event end.enable do TracePointSpec.test @@ -49,10 +56,10 @@ describe 'TracePoint.new' do it 'raises a TypeError when the given object is not a string/symbol' do o = mock('123') - -> { TracePoint.new(o) {}}.should raise_error(TypeError) + -> { TracePoint.new(o) {} }.should raise_error(TypeError) o.should_receive(:to_sym).and_return(123) - -> { TracePoint.new(o) {}}.should raise_error(TypeError) + -> { TracePoint.new(o) {} }.should raise_error(TypeError) end it 'expects to be called with a block' do diff --git a/spec/ruby/core/tracepoint/parameters_spec.rb b/spec/ruby/core/tracepoint/parameters_spec.rb index f901c184f4..3a2cdd7750 100644 --- a/spec/ruby/core/tracepoint/parameters_spec.rb +++ b/spec/ruby/core/tracepoint/parameters_spec.rb @@ -1,11 +1,15 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' ruby_version_is "2.6" do describe 'TracePoint#parameters' do it 'returns the parameters of block' do f = proc {|x, y, z| } parameters = nil - TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do + TracePoint.new(:b_call) { |tp| + next unless TracePointSpec.target_thread? + parameters = tp.parameters + }.enable do f.call parameters.should == [[:opt, :x], [:opt, :y], [:opt, :z]] end @@ -14,7 +18,10 @@ ruby_version_is "2.6" do it 'returns the parameters of lambda block' do f = -> x, y, z { } parameters = nil - TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do + TracePoint.new(:b_call) { |tp| + next unless TracePointSpec.target_thread? + parameters = tp.parameters + }.enable do f.call(1, 2, 3) parameters.should == [[:req, :x], [:req, :y], [:req, :z]] end diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb index 1e31c1bb68..5b6c6d4cfc 100644 --- a/spec/ruby/core/tracepoint/path_spec.rb +++ b/spec/ruby/core/tracepoint/path_spec.rb @@ -1,18 +1,26 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#path' do it 'returns the path of the file being run' do path = nil - TracePoint.new(:line) { |tp| path = tp.path }.enable do - path.should == "#{__FILE__}" + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do + line_event = true end + path.should == "#{__FILE__}" end it 'equals (eval) inside an eval for :end event' do path = nil - TracePoint.new(:end) { |tp| path = tp.path }.enable do + TracePoint.new(:end) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do eval("module TracePointSpec; end") - path.should == '(eval)' end + path.should == '(eval)' end end diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb index 450717b958..ca2f50abb3 100644 --- a/spec/ruby/core/tracepoint/raised_exception_spec.rb +++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb @@ -1,9 +1,13 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#raised_exception' do it 'returns value from exception raised on the :raise event' do raised_exception, error_result = nil - trace = TracePoint.new(:raise) { |tp| raised_exception = tp.raised_exception } + trace = TracePoint.new(:raise) { |tp| + next unless TracePointSpec.target_thread? + raised_exception = tp.raised_exception + } trace.enable do begin raise StandardError diff --git a/spec/ruby/core/tracepoint/return_value_spec.rb b/spec/ruby/core/tracepoint/return_value_spec.rb index f0ed86bd00..e84c7dd762 100644 --- a/spec/ruby/core/tracepoint/return_value_spec.rb +++ b/spec/ruby/core/tracepoint/return_value_spec.rb @@ -1,11 +1,15 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint#return_value' do def test; 'test' end it 'returns value from :return event' do trace_value = nil - TracePoint.new(:return) { |tp| trace_value = tp.return_value}.enable do + TracePoint.new(:return) { |tp| + next unless TracePointSpec.target_thread? + trace_value = tp.return_value + }.enable do test trace_value.should == 'test' end diff --git a/spec/ruby/core/tracepoint/self_spec.rb b/spec/ruby/core/tracepoint/self_spec.rb index 8bfd09301e..2098860e59 100644 --- a/spec/ruby/core/tracepoint/self_spec.rb +++ b/spec/ruby/core/tracepoint/self_spec.rb @@ -4,14 +4,20 @@ require_relative 'fixtures/classes' describe 'TracePoint#self' do it 'return the trace object from event' do trace = nil - TracePoint.new(:line) { |tp| trace = tp.self }.enable do + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + trace = tp.self + }.enable do trace.equal?(self).should be_true end end it 'return the class object from a class event' do trace = nil - TracePoint.new(:class) { |tp| trace = tp.self }.enable do + TracePoint.new(:class) { |tp| + next unless TracePointSpec.target_thread? + trace = tp.self + }.enable do class TracePointSpec::C end end diff --git a/spec/ruby/core/tracepoint/trace_spec.rb b/spec/ruby/core/tracepoint/trace_spec.rb index c39721e692..167f594bb9 100644 --- a/spec/ruby/core/tracepoint/trace_spec.rb +++ b/spec/ruby/core/tracepoint/trace_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe 'TracePoint.trace' do it 'activates the trace automatically' do diff --git a/spec/ruby/language/fixtures/squiggly_heredoc.rb b/spec/ruby/language/fixtures/squiggly_heredoc.rb index afc87514c7..d223966b93 100644 --- a/spec/ruby/language/fixtures/squiggly_heredoc.rb +++ b/spec/ruby/language/fixtures/squiggly_heredoc.rb @@ -29,6 +29,14 @@ module SquigglyHeredocSpecs HERE end + def self.least_indented_on_the_first_line + <<~HERE + a + b + c + HERE + end + def self.least_indented_on_the_last_line <<~HERE a @@ -36,4 +44,20 @@ module SquigglyHeredocSpecs c HERE end + + def self.least_indented_on_the_first_line_single + <<~'HERE' + a + b + c + HERE + end + + def self.least_indented_on_the_last_line_single + <<~'HERE' + a + b + c + HERE + end end diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb index e7655a9216..1ec21a2ec0 100644 --- a/spec/ruby/language/heredoc_spec.rb +++ b/spec/ruby/language/heredoc_spec.rb @@ -86,6 +86,13 @@ HERE it "selects the least-indented line and removes its indentation from all the lines" do require_relative 'fixtures/squiggly_heredoc' + SquigglyHeredocSpecs.least_indented_on_the_first_line.should == "a\n b\n c\n" SquigglyHeredocSpecs.least_indented_on_the_last_line.should == " a\n b\nc\n" end + + it "selects the least-indented line and removes its indentation from all the lines for <<~'identifier'" do + require_relative 'fixtures/squiggly_heredoc' + SquigglyHeredocSpecs.least_indented_on_the_first_line_single.should == "a\n b\n c\n" + SquigglyHeredocSpecs.least_indented_on_the_last_line_single.should == " a\n b\nc\n" + end end diff --git a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb index 4e839e21a3..5da0210145 100644 --- a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb +++ b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb @@ -112,6 +112,17 @@ describe "Kernel#BigDecimal" do neg_inf.should < 0 end + ruby_version_is "2.6" do + describe "with exception: false" do + it "returns nil for invalid strings" do + BigDecimal("invalid", exception: false).should be_nil + BigDecimal("0invalid", exception: false).should be_nil + BigDecimal("invalid0", exception: false).should be_nil + BigDecimal("0.", exception: false).should be_nil + end + end + end + describe "accepts NaN and [+-]Infinity as Float values" do it "works without an explicit precision" do BigDecimal(Float::NAN).should.nan? diff --git a/spec/ruby/library/net/http/http/get_spec.rb b/spec/ruby/library/net/http/http/get_spec.rb index 35bd51d9a3..dbdca4a431 100644 --- a/spec/ruby/library/net/http/http/get_spec.rb +++ b/spec/ruby/library/net/http/http/get_spec.rb @@ -60,15 +60,16 @@ describe "Net::HTTP.get" do Thread.current.report_on_exception = false Net::HTTP.get("127.0.0.1", '/', server.connect_address.ip_port) end + + socket = server_thread.value Thread.pass until client_thread.stop? - [server_thread, client_thread] + [socket, client_thread] end it "propagates exceptions interrupting the thread and does not replace it with Zlib::BufError" do my_exception = Class.new(RuntimeError) - server_thread, client_thread = start_threads - socket = server_thread.value + socket, client_thread = start_threads begin client_thread.raise my_exception, "my exception" -> { client_thread.value }.should raise_error(my_exception) @@ -79,8 +80,7 @@ describe "Net::HTTP.get" do ruby_version_is "2.8" do # https://bugs.ruby-lang.org/issues/13882#note-6 it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do - server_thread, client_thread = start_threads - socket = server_thread.value + socket, client_thread = start_threads begin client_thread.kill client_thread.value.should == nil diff --git a/spec/ruby/library/objectspace/memsize_of_spec.rb b/spec/ruby/library/objectspace/memsize_of_spec.rb index 06a80d9f9c..36d845824d 100644 --- a/spec/ruby/library/objectspace/memsize_of_spec.rb +++ b/spec/ruby/library/objectspace/memsize_of_spec.rb @@ -12,6 +12,10 @@ describe "ObjectSpace.memsize_of" do ObjectSpace.memsize_of(42).should == 0 end + it "returns 0 for literal Symbols" do + ObjectSpace.memsize_of(:abc).should == 0 + end + it "returns an Integer for an Object" do obj = Object.new ObjectSpace.memsize_of(obj).should be_kind_of(Integer) diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb index 0da4e2218b..d38d95e0e1 100644 --- a/spec/ruby/library/socket/tcpserver/accept_spec.rb +++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb @@ -58,6 +58,26 @@ describe "TCPServer#accept" do t.join end + it "is automatically retried when interrupted by SIGVTALRM" do + t = Thread.new do + client = @server.accept + value = client.read(2) + client.close + value + end + + Thread.pass while t.status and t.status != "sleep" + # Thread#backtrace uses SIGVTALRM on TruffleRuby and potentially other implementations. + # Sending a signal to a thread is not possible with Ruby APIs. + t.backtrace.join("\n").should.include?("in `accept'") + + socket = TCPSocket.new('127.0.0.1', @port) + socket.write("OK") + socket.close + + t.value.should == "OK" + end + it "raises an IOError if the socket is closed" do @server.close -> { @server.accept }.should raise_error(IOError) diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb index 430c2dfcc6..f550390c22 100644 --- a/spec/ruby/optional/capi/encoding_spec.rb +++ b/spec/ruby/optional/capi/encoding_spec.rb @@ -131,6 +131,29 @@ describe "C-API Encoding function" do end end + describe "rb_enc_precise_mbclen" do + it "returns the correct length for single byte characters" do + @s.rb_enc_precise_mbclen("hello", 7).should == 1 + @s.rb_enc_precise_mbclen("hello", 5).should == 1 + @s.rb_enc_precise_mbclen("hello", 1).should == 1 + @s.rb_enc_precise_mbclen("hello", 0).should == -2 + @s.rb_enc_precise_mbclen("hello", -1).should == -2 + @s.rb_enc_precise_mbclen("hello", -5).should == -2 + end + + it "returns the correct length for multi-byte characters" do + @s.rb_enc_precise_mbclen("ésumé", 2).should == 2 + @s.rb_enc_precise_mbclen("ésumé", 3).should == 2 + @s.rb_enc_precise_mbclen("ésumé", 0).should == -2 + @s.rb_enc_precise_mbclen("ésumé", 1).should == -2 + @s.rb_enc_precise_mbclen("あ", 20).should == 3 + @s.rb_enc_precise_mbclen("あ", 3).should == 3 + @s.rb_enc_precise_mbclen("あ", 2).should == -2 + @s.rb_enc_precise_mbclen("あ", 0).should == -2 + @s.rb_enc_precise_mbclen("あ", -2).should == -2 + end + end + describe "rb_obj_encoding" do it "returns the encoding associated with an object" do str = "abc".encode Encoding::BINARY @@ -173,6 +196,26 @@ describe "C-API Encoding function" do end end + describe "rb_enc_str_new_cstr" do + it "creates a new ruby string from a c string literal" do + result = @s.rb_enc_str_new_cstr_constant(Encoding::US_ASCII) + result.should == "test string literal" + result.encoding.should == Encoding::US_ASCII + end + + it "creates a new ruby string from a c string variable" do + result = @s.rb_enc_str_new_cstr("test string", Encoding::US_ASCII) + result.should == "test string" + result.encoding.should == Encoding::US_ASCII + end + + it "when null encoding is given with a c string literal, it creates a new ruby string with ASCII_8BIT encoding" do + result = @s.rb_enc_str_new_cstr_constant(nil) + result.should == "test string literal" + result.encoding.should == Encoding::ASCII_8BIT + end + end + describe "rb_enc_str_coderange" do describe "when the encoding is BINARY" do it "returns ENC_CODERANGE_7BIT if there are no high bits set" do @@ -217,6 +260,17 @@ describe "C-API Encoding function" do end end + describe "MBCLEN_CHARFOUND_P" do + it "returns non-zero for valid character" do + @s.MBCLEN_CHARFOUND_P("a".ord).should == 1 + end + + it "returns zero for invalid characters" do + @s.MBCLEN_CHARFOUND_P(0).should == 0 + @s.MBCLEN_CHARFOUND_P(-1).should == 0 + end + end + describe "ENCODING_GET" do it_behaves_like :rb_enc_get_index, :ENCODING_GET end @@ -497,4 +551,21 @@ describe "C-API Encoding function" do @s.rb_enc_str_asciionly_p("hüllo").should be_false end end + + describe "rb_uv_to_utf8" do + it 'converts a Unicode codepoint to a UTF-8 C string' do + str = ' ' * 6 + { + 0 => "\x01", + 0x7f => "\xC2\x80", + 0x7ff => "\xE0\xA0\x80", + 0xffff => "\xF0\x90\x80\x80", + 0x1fffff => "\xF8\x88\x80\x80\x80", + 0x3ffffff => "\xFC\x84\x80\x80\x80\x80", + }.each do |num, result| + len = @s.rb_uv_to_utf8(str, num + 1) + str[0..len-1].should == result + end + end + end end diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index 6b3a8be01a..6e2e7cece1 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -7,6 +7,10 @@ extern "C" { #endif +static VALUE encoding_spec_MBCLEN_CHARFOUND_P(VALUE self, VALUE obj) { + return INT2FIX(MBCLEN_CHARFOUND_P(FIX2INT(obj))); +} + static VALUE encoding_spec_ENC_CODERANGE_ASCIIONLY(VALUE self, VALUE obj) { if(ENC_CODERANGE_ASCIIONLY(obj)) { return Qtrue; @@ -114,6 +118,13 @@ static VALUE encoding_spec_rb_enc_get(VALUE self, VALUE obj) { return rb_str_new2(rb_enc_get(obj)->name); } +static VALUE encoding_spec_rb_enc_precise_mbclen(VALUE self, VALUE str, VALUE offset) { + int o = FIX2INT(offset); + char *p = RSTRING_PTR(str); + char *e = p + o; + return INT2FIX(rb_enc_precise_mbclen(p, e, rb_enc_get(str))); +} + static VALUE encoding_spec_rb_obj_encoding(VALUE self, VALUE obj) { return rb_obj_encoding(obj); } @@ -149,6 +160,16 @@ static VALUE encoding_spec_rb_enc_str_coderange(VALUE self, VALUE str) { } } +static VALUE encoding_spec_rb_enc_str_new_cstr(VALUE self, VALUE str, VALUE enc) { + rb_encoding *e = rb_to_encoding(enc); + return rb_enc_str_new_cstr(StringValueCStr(str), e); +} + +static VALUE encoding_spec_rb_enc_str_new_cstr_constant(VALUE self, VALUE enc) { + rb_encoding *e = NIL_P(enc) ? NULL : rb_to_encoding(enc); + return rb_enc_str_new_cstr("test string literal", e); +} + static VALUE encoding_spec_rb_enc_str_new(VALUE self, VALUE str, VALUE len, VALUE enc) { return rb_enc_str_new(RSTRING_PTR(str), FIX2INT(len), rb_to_encoding(enc)); } @@ -219,6 +240,10 @@ static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) { } } +static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) { + return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num))); +} + void Init_encoding_spec(void) { VALUE cls; native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*)); @@ -247,6 +272,7 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_enc_alias", encoding_spec_rb_enc_alias, 2); #endif + rb_define_method(cls, "MBCLEN_CHARFOUND_P", encoding_spec_MBCLEN_CHARFOUND_P, 1); rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2); rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2); rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2); @@ -256,10 +282,13 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1); rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1); rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1); + rb_define_method(cls, "rb_enc_precise_mbclen", encoding_spec_rb_enc_precise_mbclen, 2); rb_define_method(cls, "rb_obj_encoding", encoding_spec_rb_obj_encoding, 1); rb_define_method(cls, "rb_enc_get_index", encoding_spec_rb_enc_get_index, 1); rb_define_method(cls, "rb_enc_set_index", encoding_spec_rb_enc_set_index, 2); rb_define_method(cls, "rb_enc_str_coderange", encoding_spec_rb_enc_str_coderange, 1); + rb_define_method(cls, "rb_enc_str_new_cstr", encoding_spec_rb_enc_str_new_cstr, 2); + rb_define_method(cls, "rb_enc_str_new_cstr_constant", encoding_spec_rb_enc_str_new_cstr_constant, 1); rb_define_method(cls, "rb_enc_str_new", encoding_spec_rb_enc_str_new, 3); rb_define_method(cls, "ENCODING_GET", encoding_spec_ENCODING_GET, 1); rb_define_method(cls, "ENCODING_SET", encoding_spec_ENCODING_SET, 2); @@ -271,6 +300,7 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_enc_nth", encoding_spec_rb_enc_nth, 2); rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1); rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1); + rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index 270412673e..b6e03f29a5 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -49,6 +49,12 @@ VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) { return INT2FIX(RSTRING_LEN(str)); } +VALUE rb_fstring(VALUE str); /* internal.h, used in ripper */ + +VALUE string_spec_rb_str_fstring(VALUE self, VALUE str) { + return rb_fstring(str); +} + VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) { VALUE buf; @@ -93,6 +99,14 @@ VALUE string_spec_rb_str_cat2(VALUE self, VALUE str) { return rb_str_cat2(str, "?"); } +VALUE string_spec_rb_str_cat_cstr(VALUE self, VALUE str, VALUE other) { + return rb_str_cat_cstr(str, StringValueCStr(other)); +} + +VALUE string_spec_rb_str_cat_cstr_constant(VALUE self, VALUE str) { + return rb_str_cat_cstr(str, "?"); +} + VALUE string_spec_rb_str_cmp(VALUE self, VALUE str1, VALUE str2) { return INT2NUM(rb_str_cmp(str1, str2)); } @@ -452,6 +466,7 @@ void Init_string_spec(void) { VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject); rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2); rb_define_method(cls, "rb_cstr_to_inum", string_spec_rb_cstr_to_inum, 3); + rb_define_method(cls, "rb_fstring", string_spec_rb_str_fstring, 1); rb_define_method(cls, "rb_str2inum", string_spec_rb_str2inum, 2); rb_define_method(cls, "rb_str_append", string_spec_rb_str_append, 2); rb_define_method(cls, "rb_str_buf_new", string_spec_rb_str_buf_new, 2); @@ -462,6 +477,8 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_str_buf_cat", string_spec_rb_str_buf_cat, 1); rb_define_method(cls, "rb_str_cat", string_spec_rb_str_cat, 1); rb_define_method(cls, "rb_str_cat2", string_spec_rb_str_cat2, 1); + rb_define_method(cls, "rb_str_cat_cstr", string_spec_rb_str_cat_cstr, 2); + rb_define_method(cls, "rb_str_cat_cstr_constant", string_spec_rb_str_cat_cstr_constant, 1); rb_define_method(cls, "rb_str_cmp", string_spec_rb_str_cmp, 2); rb_define_method(cls, "rb_str_conv_enc", string_spec_rb_str_conv_enc, 3); rb_define_method(cls, "rb_str_conv_enc_opts", string_spec_rb_str_conv_enc_opts, 5); diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c index f7b45de6b6..a7269353c2 100644 --- a/spec/ruby/optional/capi/ext/util_spec.c +++ b/spec/ruby/optional/capi/ext/util_spec.c @@ -1,4 +1,5 @@ #include "ruby.h" +#include "ruby/util.h" #include "rubyspec.h" #ifdef __cplusplus @@ -93,6 +94,18 @@ static VALUE util_spec_rb_sourceline(VALUE self) { return INT2NUM(rb_sourceline()); } +static VALUE util_spec_strtod(VALUE self, VALUE string) { + char *endptr = NULL; + double value = strtod(RSTRING_PTR(string), &endptr); + return rb_ary_new_from_args(2, rb_float_new(value), endptr ? rb_str_new2(endptr) : Qnil); +} + +static VALUE util_spec_ruby_strtod(VALUE self, VALUE string) { + char *endptr = NULL; + double value = ruby_strtod(RSTRING_PTR(string), &endptr); + return rb_ary_new_from_args(2, rb_float_new(value), endptr ? rb_str_new2(endptr) : Qnil); +} + void Init_util_spec(void) { VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject); rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4); @@ -101,6 +114,8 @@ void Init_util_spec(void) { rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0); rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0); rb_define_method(cls, "rb_sourceline", util_spec_rb_sourceline, 0); + rb_define_method(cls, "strtod", util_spec_strtod, 1); + rb_define_method(cls, "ruby_strtod", util_spec_ruby_strtod, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 57ac9545f4..35a6fd1c92 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -382,6 +382,16 @@ describe "C-API String function" do end end + describe "rb_str_cat_cstr" do + it "concatenates a C string literal to a ruby string" do + @s.rb_str_cat_cstr_constant("Your house is on fire").should == "Your house is on fire?" + end + + it "concatenates a variable C string to a ruby string" do + @s.rb_str_cat_cstr("Your house is on fire", "?").should == "Your house is on fire?" + end + end + describe "rb_str_cmp" do it "returns 0 if two strings are identical" do @s.rb_str_cmp("ppp", "ppp").should == 0 @@ -454,6 +464,25 @@ describe "C-API String function" do end end + describe "rb_fstring" do + it 'returns self if the String is frozen' do + input = 'foo'.freeze + output = @s.rb_fstring(input) + + output.should equal(input) + output.should.frozen? + end + + it 'returns a frozen copy if the String is not frozen' do + input = 'foo' + output = @s.rb_fstring(input) + + output.should.frozen? + output.should_not equal(input) + output.should == 'foo' + end + end + describe "rb_str_subseq" do it "returns a byte-indexed substring" do str = "\x00\x01\x02\x03\x04".force_encoding("binary") diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb index cf19c55b57..099222b2d0 100644 --- a/spec/ruby/optional/capi/util_spec.rb +++ b/spec/ruby/optional/capi/util_spec.rb @@ -293,4 +293,34 @@ describe "C-API Util function" do end end + # ruby/util.h redefines strtod as a macro calling ruby_strtod + + describe "strtod" do + it "converts a string to a double and returns the remaining string" do + d, s = @o.strtod("14.25test") + d.should == 14.25 + s.should == "test" + end + + it "returns 0 and the full string if there's no numerical value" do + d, s = @o.strtod("test") + d.should == 0 + s.should == "test" + end + end + + describe "ruby_strtod" do + it "converts a string to a double and returns the remaining string" do + d, s = @o.ruby_strtod("14.25test") + d.should == 14.25 + s.should == "test" + end + + it "returns 0 and the full string if there's no numerical value" do + d, s = @o.ruby_strtod("test") + d.should == 0 + s.should == "test" + end + end + end diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb index 6827db2271..4dd59884c8 100644 --- a/spec/ruby/shared/string/times.rb +++ b/spec/ruby/shared/string/times.rb @@ -20,10 +20,16 @@ describe :string_times, shared: true do it "raises an ArgumentError when given integer is negative" do -> { @object.call("cool", -3) }.should raise_error(ArgumentError) -> { @object.call("cool", -3.14) }.should raise_error(ArgumentError) + -> { @object.call("cool", min_long) }.should raise_error(ArgumentError) end it "raises a RangeError when given integer is a Bignum" do -> { @object.call("cool", 999999999999999999999) }.should raise_error(RangeError) + -> { @object.call("", 999999999999999999999) }.should raise_error(RangeError) + end + + it "works with huge long values when string is empty" do + @object.call("", max_long).should == "" end it "returns subclass instances" do |