From d3d5ef0cca160fca538c7f556c5a6e08df5847e6 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 26 Jun 2022 14:50:14 +0200 Subject: [PATCH] Update to ruby/spec@ab32a1a --- spec/ruby/.rubocop.yml | 3 + spec/ruby/.rubocop_todo.yml | 11 -- spec/ruby/core/array/fill_spec.rb | 6 + spec/ruby/core/array/fixtures/classes.rb | 62 ++++++++ spec/ruby/core/array/sample_spec.rb | 18 +-- spec/ruby/core/dir/foreach_spec.rb | 10 +- .../core/exception/signal_exception_spec.rb | 6 +- spec/ruby/core/file/open_spec.rb | 8 + spec/ruby/core/float/divide_spec.rb | 4 + spec/ruby/core/float/round_spec.rb | 64 ++++++++ spec/ruby/core/integer/chr_spec.rb | 39 +++-- spec/ruby/core/integer/fdiv_spec.rb | 5 + spec/ruby/core/io/advise_spec.rb | 14 +- spec/ruby/core/io/fixtures/classes.rb | 14 ++ spec/ruby/core/io/gets_spec.rb | 14 ++ spec/ruby/core/io/readline_spec.rb | 31 ++++ spec/ruby/core/io/readlines_spec.rb | 22 +++ spec/ruby/core/io/shared/each.rb | 48 ++++++ spec/ruby/core/io/shared/readlines.rb | 135 +++++++++++------ .../core/kernel/instance_variable_get_spec.rb | 6 + .../core/kernel/instance_variable_set_spec.rb | 6 + .../kernel/remove_instance_variable_spec.rb | 13 ++ spec/ruby/core/kernel/shared/require.rb | 19 +++ spec/ruby/core/math/ldexp_spec.rb | 6 + spec/ruby/core/module/class_variables_spec.rb | 8 + spec/ruby/core/module/fixtures/classes.rb | 4 + spec/ruby/core/process/clock_gettime_spec.rb | 105 +++++++------ spec/ruby/core/process/egid_spec.rb | 41 ++++- spec/ruby/core/process/euid_spec.rb | 12 +- spec/ruby/core/process/spawn_spec.rb | 2 +- .../core/process/status/equal_value_spec.rb | 2 +- spec/ruby/core/process/status/exited_spec.rb | 2 +- .../core/process/status/exitstatus_spec.rb | 2 +- .../ruby/core/process/status/signaled_spec.rb | 2 +- spec/ruby/core/process/status/success_spec.rb | 2 +- spec/ruby/core/process/status/termsig_spec.rb | 4 +- spec/ruby/core/process/status/to_i_spec.rb | 2 +- spec/ruby/core/regexp/shared/quote.rb | 5 + spec/ruby/core/signal/trap_spec.rb | 4 +- spec/ruby/core/string/capitalize_spec.rb | 4 + spec/ruby/core/string/dup_spec.rb | 9 ++ spec/ruby/core/string/insert_spec.rb | 9 ++ spec/ruby/core/string/lstrip_spec.rb | 6 + spec/ruby/core/string/rstrip_spec.rb | 6 + spec/ruby/core/string/scrub_spec.rb | 5 + spec/ruby/core/string/shared/slice.rb | 14 +- spec/ruby/core/string/split_spec.rb | 19 ++- spec/ruby/core/string/unpack/z_spec.rb | 5 + spec/ruby/core/thread/raise_spec.rb | 24 +++ spec/ruby/fixtures/code/c/load_fixture.rb | 1 + .../language/optional_assignments_spec.rb | 38 +++++ spec/ruby/language/predefined_spec.rb | 66 +++++++- spec/ruby/language/variables_spec.rb | 18 +++ spec/ruby/language/yield_spec.rb | 10 ++ .../trace_object_allocations_spec.rb | 18 +++ .../library/openssl/x509/name/verify_spec.rb | 78 ++++++++++ spec/ruby/library/stringio/each_line_spec.rb | 4 + spec/ruby/library/stringio/each_spec.rb | 8 + spec/ruby/library/stringio/gets_spec.rb | 4 + spec/ruby/library/stringio/readline_spec.rb | 20 +++ spec/ruby/library/stringio/readlines_spec.rb | 18 +++ spec/ruby/library/stringio/shared/each.rb | 37 +++++ spec/ruby/library/zlib/crc_table_spec.rb | 143 +++++++++--------- spec/ruby/optional/capi/class_spec.rb | 10 -- spec/ruby/optional/capi/encoding_spec.rb | 16 +- spec/ruby/optional/capi/ext/class_spec.c | 15 -- spec/ruby/optional/capi/ext/encoding_spec.c | 4 +- spec/ruby/optional/capi/ext/module_spec.c | 56 +++---- spec/ruby/optional/capi/ext/object_spec.c | 8 + spec/ruby/optional/capi/ext/regexp_spec.c | 7 + spec/ruby/optional/capi/module_spec.rb | 34 +++-- spec/ruby/optional/capi/object_spec.rb | 25 +++ spec/ruby/optional/capi/regexp_spec.rb | 16 ++ spec/ruby/spec_helper.rb | 9 +- 74 files changed, 1201 insertions(+), 324 deletions(-) create mode 100644 spec/ruby/fixtures/code/c/load_fixture.rb create mode 100644 spec/ruby/library/openssl/x509/name/verify_spec.rb diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index e807b59321..1200e9d7ce 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -99,6 +99,9 @@ Lint/DuplicateElsifCondition: Lint/OutOfRangeRegexpRef: Enabled: false +Lint/InheritException: + Enabled: false + Lint/ElseLayout: Exclude: - 'language/if_spec.rb' diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml index a469213841..ac9cfae2bf 100644 --- a/spec/ruby/.rubocop_todo.yml +++ b/spec/ruby/.rubocop_todo.yml @@ -50,17 +50,6 @@ Lint/IneffectiveAccessModifier: - 'core/module/fixtures/classes.rb' - 'language/fixtures/private.rb' -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: runtime_error, standard_error -Lint/InheritException: - Exclude: - - 'core/enumerator/lazy/fixtures/classes.rb' - - 'core/exception/fixtures/common.rb' - - 'core/module/fixtures/autoload_ex1.rb' - - 'shared/kernel/raise.rb' - # Offense count: 72 # Cop supports --auto-correct. Lint/LiteralInInterpolation: diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb index 6369f23544..23728414be 100644 --- a/spec/ruby/core/array/fill_spec.rb +++ b/spec/ruby/core/array/fill_spec.rb @@ -205,6 +205,12 @@ describe "Array#fill with (filler, index, length)" do -> { [].fill('a', obj) }.should raise_error(TypeError) end + it "raises a TypeError when the length is not numeric" do + -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/) + -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/) + -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/) + end + not_supported_on :opal do it "raises an ArgumentError or RangeError for too-large sizes" do error_types = [RangeError, ArgumentError] diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb index affb3b49e6..aa5fecd96b 100644 --- a/spec/ruby/core/array/fixtures/classes.rb +++ b/spec/ruby/core/array/fixtures/classes.rb @@ -40,6 +40,68 @@ module ArraySpecs a end + # Chi squared critical values for tests with n degrees of freedom at 99% confidence. + # Values obtained from NIST Engineering Statistic Handbook at + # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm + + CHI_SQUARED_CRITICAL_VALUES = [ + 0, + 6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209, + 24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566, + 38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892, + 52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691, + 64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154, + 77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379, + 89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425, + 101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329, + 113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116, + 125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807, + ] + + def self.measure_sample_fairness(size, samples, iters) + ary = Array.new(size) { |x| x } + (samples).times do |i| + chi_results = [] + 3.times do + counts = Array.new(size) { 0 } + expected = iters / size + iters.times do + x = ary.sample(samples)[i] + counts[x] += 1 + end + chi_squared = 0.0 + counts.each do |count| + chi_squared += (((count - expected) ** 2) * 1.0 / expected) + end + chi_results << chi_squared + break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size] + end + + chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size] + end + end + + def self.measure_sample_fairness_large_sample_size(size, samples, iters) + ary = Array.new(size) { |x| x } + counts = Array.new(size) { 0 } + expected = iters * samples / size + iters.times do + ary.sample(samples).each do |sample| + counts[sample] += 1 + end + end + chi_squared = 0.0 + counts.each do |count| + chi_squared += (((count - expected) ** 2) * 1.0 / expected) + end + + # Chi squared critical values for tests with 4 degrees of freedom + # Values obtained from NIST Engineering Statistic Handbook at + # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm + + chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size] + end + class MyArray < Array # The #initialize method has a different signature than Array to help # catch places in the specs that do not assert the #initialize is not diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb index 755b46f126..5b3aac9aed 100644 --- a/spec/ruby/core/array/sample_spec.rb +++ b/spec/ruby/core/array/sample_spec.rb @@ -3,16 +3,14 @@ require_relative 'fixtures/classes' describe "Array#sample" do it "samples evenly" do - ary = [0, 1, 2, 3] - 3.times do |i| - counts = [0, 0, 0, 0] - 4000.times do - counts[ary.sample(3)[i]] += 1 - end - counts.each do |count| - (800..1200).should include(count) - end - end + ArraySpecs.measure_sample_fairness(4, 1, 400) + ArraySpecs.measure_sample_fairness(4, 2, 400) + ArraySpecs.measure_sample_fairness(4, 3, 400) + ArraySpecs.measure_sample_fairness(40, 3, 400) + ArraySpecs.measure_sample_fairness(40, 4, 400) + ArraySpecs.measure_sample_fairness(40, 8, 400) + ArraySpecs.measure_sample_fairness(40, 16, 400) + ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000) end it "returns nil for an empty Array" do diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb index b0e18afeb5..9cf34b1d71 100644 --- a/spec/ruby/core/dir/foreach_spec.rb +++ b/spec/ruby/core/dir/foreach_spec.rb @@ -41,13 +41,13 @@ describe "Dir.foreach" do it "accepts an encoding keyword for the encoding of the entries" do dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").to_a.sort - dirs.each {|dir| dir.encoding.should == Encoding::UTF_8} + dirs.each { |dir| dir.encoding.should == Encoding::UTF_8 } - dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE).to_a.sort - dirs.each {|dir| dir.encoding.should == Encoding::UTF_16LE} + dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1).to_a.sort + dirs.each { |dir| dir.encoding.should == Encoding::ISO_8859_1 } - Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE) do |f| - f.encoding.should == Encoding::UTF_16LE + Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1) do |f| + f.encoding.should == Encoding::ISO_8859_1 end end diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb index 566bcb4672..1a0940743f 100644 --- a/spec/ruby/core/exception/signal_exception_spec.rb +++ b/spec/ruby/core/exception/signal_exception_spec.rb @@ -93,7 +93,7 @@ describe "SignalException" do platform_is_not :windows do it "runs after at_exit" do - output = ruby_exe(<<-RUBY, exit_status: nil) + output = ruby_exe(<<-RUBY, exit_status: :SIGKILL) at_exit do puts "hello" $stdout.flush @@ -107,7 +107,7 @@ describe "SignalException" do end it "cannot be trapped with Signal.trap" do - ruby_exe(<<-RUBY, exit_status: nil) + ruby_exe(<<-RUBY, exit_status: :SIGPROF) Signal.trap("PROF") {} raise(SignalException, "PROF") RUBY @@ -116,7 +116,7 @@ describe "SignalException" do end it "self-signals for USR1" do - ruby_exe("raise(SignalException, 'USR1')", exit_status: nil) + ruby_exe("raise(SignalException, 'USR1')", exit_status: :SIGUSR1) $?.termsig.should == Signal.list.fetch('USR1') end end diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb index c7dd34d5c6..1729780570 100644 --- a/spec/ruby/core/file/open_spec.rb +++ b/spec/ruby/core/file/open_spec.rb @@ -494,6 +494,14 @@ describe "File.open" do File.open(@file, "w") { |f| f.puts "testing" } File.size(@file).should > 0 File.open(@file, "rb+") do |f| + f.binmode?.should == true + f.external_encoding.should == Encoding::ASCII_8BIT + f.pos.should == 0 + f.should_not.eof? + end + File.open(@file, "r+b") do |f| + f.binmode?.should == true + f.external_encoding.should == Encoding::ASCII_8BIT f.pos.should == 0 f.should_not.eof? end diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb index d8f71a6b98..72ab7527bd 100644 --- a/spec/ruby/core/float/divide_spec.rb +++ b/spec/ruby/core/float/divide_spec.rb @@ -36,4 +36,8 @@ describe "Float#/" do -> { 13.0 / "10" }.should raise_error(TypeError) -> { 13.0 / :symbol }.should raise_error(TypeError) end + + it "divides correctly by Rational numbers" do + (1.2345678901234567 / Rational(1, 10000000000000000000)).should == 1.2345678901234567e+19 + end end diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb index 4bd2dc460c..e5a8f534e7 100644 --- a/spec/ruby/core/float/round_spec.rb +++ b/spec/ruby/core/float/round_spec.rb @@ -103,6 +103,70 @@ describe "Float#round" do 5.55.round(1, half: :up).should eql(5.6) 5.55.round(1, half: :down).should eql(5.5) 5.55.round(1, half: :even).should eql(5.6) + -5.55.round(1, half: nil).should eql(-5.6) + -5.55.round(1, half: :up).should eql(-5.6) + -5.55.round(1, half: :down).should eql(-5.5) + -5.55.round(1, half: :even).should eql(-5.6) + end + + it "preserves cases where neighbouring floating pointer number increase the decimal places" do + 4.8100000000000005.round(5, half: nil).should eql(4.81) + 4.8100000000000005.round(5, half: :up).should eql(4.81) + 4.8100000000000005.round(5, half: :down).should eql(4.81) + 4.8100000000000005.round(5, half: :even).should eql(4.81) + -4.8100000000000005.round(5, half: nil).should eql(-4.81) + -4.8100000000000005.round(5, half: :up).should eql(-4.81) + -4.8100000000000005.round(5, half: :down).should eql(-4.81) + -4.8100000000000005.round(5, half: :even).should eql(-4.81) + 4.81.round(5, half: nil).should eql(4.81) + 4.81.round(5, half: :up).should eql(4.81) + 4.81.round(5, half: :down).should eql(4.81) + 4.81.round(5, half: :even).should eql(4.81) + -4.81.round(5, half: nil).should eql(-4.81) + -4.81.round(5, half: :up).should eql(-4.81) + -4.81.round(5, half: :down).should eql(-4.81) + -4.81.round(5, half: :even).should eql(-4.81) + 4.809999999999999.round(5, half: nil).should eql(4.81) + 4.809999999999999.round(5, half: :up).should eql(4.81) + 4.809999999999999.round(5, half: :down).should eql(4.81) + 4.809999999999999.round(5, half: :even).should eql(4.81) + -4.809999999999999.round(5, half: nil).should eql(-4.81) + -4.809999999999999.round(5, half: :up).should eql(-4.81) + -4.809999999999999.round(5, half: :down).should eql(-4.81) + -4.809999999999999.round(5, half: :even).should eql(-4.81) + end + + ruby_bug "", ""..."3.3" do + # These numbers are neighbouring floating point numbers round a + # precise value. They test that the rounding modes work correctly + # round that value and precision is not lost which might cause + # incorrect results. + it "does not lose precision during the rounding process" do + 767573.1875850001.round(5, half: nil).should eql(767573.18759) + 767573.1875850001.round(5, half: :up).should eql(767573.18759) + 767573.1875850001.round(5, half: :down).should eql(767573.18759) + 767573.1875850001.round(5, half: :even).should eql(767573.18759) + -767573.1875850001.round(5, half: nil).should eql(-767573.18759) + -767573.1875850001.round(5, half: :up).should eql(-767573.18759) + -767573.1875850001.round(5, half: :down).should eql(-767573.18759) + -767573.1875850001.round(5, half: :even).should eql(-767573.18759) + 767573.187585.round(5, half: nil).should eql(767573.18759) + 767573.187585.round(5, half: :up).should eql(767573.18759) + 767573.187585.round(5, half: :down).should eql(767573.18758) + 767573.187585.round(5, half: :even).should eql(767573.18758) + -767573.187585.round(5, half: nil).should eql(-767573.18759) + -767573.187585.round(5, half: :up).should eql(-767573.18759) + -767573.187585.round(5, half: :down).should eql(-767573.18758) + -767573.187585.round(5, half: :even).should eql(-767573.18758) + 767573.1875849998.round(5, half: nil).should eql(767573.18758) + 767573.1875849998.round(5, half: :up).should eql(767573.18758) + 767573.1875849998.round(5, half: :down).should eql(767573.18758) + 767573.1875849998.round(5, half: :even).should eql(767573.18758) + -767573.1875849998.round(5, half: nil).should eql(-767573.18758) + -767573.1875849998.round(5, half: :up).should eql(-767573.18758) + -767573.1875849998.round(5, half: :down).should eql(-767573.18758) + -767573.1875849998.round(5, half: :even).should eql(-767573.18758) + end end it "raises FloatDomainError for exceptional values with a half option" do diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb index 3e13f45480..8fe20ff812 100644 --- a/spec/ruby/core/integer/chr_spec.rb +++ b/spec/ruby/core/integer/chr_spec.rb @@ -223,26 +223,25 @@ describe "Integer#chr with an encoding argument" do # #5864 it "raises RangeError if self is invalid as a codepoint in the specified encoding" do - [ [0x80, "US-ASCII"], - [0x0100, "BINARY"], - [0x0100, "EUC-JP"], - [0xA1A0, "EUC-JP"], - [0xA1, "EUC-JP"], - [0x80, "SHIFT_JIS"], - [0xE0, "SHIFT_JIS"], - [0x0100, "ISO-8859-9"], - [620, "TIS-620"], - [0xD800, "UTF-8"], - [0xDBFF, "UTF-8"], - [0xDC00, "UTF-8"], - [0xDFFF, "UTF-8"], - [0xD800, "UTF-16"], - [0xDBFF, "UTF-16"], - [0xDC00, "UTF-16"], - [0xDFFF, "UTF-16"], - ].each do |integer, encoding_name| - -> { integer.chr(encoding_name) }.should raise_error(RangeError) - end + -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError) + -> { 0x0100.chr("BINARY") }.should raise_error(RangeError) + -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError) + -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError) + -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError) + -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError) + -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError) + -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError) + -> { 620.chr("TIS-620") }.should raise_error(RangeError) + # UTF-16 surrogate range + -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError) + -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError) + -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError) + -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError) + # UTF-16 surrogate range + -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError) + -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError) + -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError) + -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError) end it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb index d99a19eb0f..d9ea2fdf8d 100644 --- a/spec/ruby/core/integer/fdiv_spec.rb +++ b/spec/ruby/core/integer/fdiv_spec.rb @@ -55,6 +55,11 @@ describe "Integer#fdiv" do num.fdiv(den).should == -0.5555555555555556 end + it "rounds to the correct float for bignum denominators" do + 1.fdiv(10**324).should == 0.0 + 1.fdiv(10**323).should == 1.0e-323 + end + it "performs floating-point division between self and a Float" do 8.fdiv(9.0).should be_close(0.888888888888889, TOLERANCE) end diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb index 0a845487e2..651fc52378 100644 --- a/spec/ruby/core/io/advise_spec.rb +++ b/spec/ruby/core/io/advise_spec.rb @@ -73,19 +73,9 @@ describe "IO#advise" do end end - platform_is :linux do + guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported it "supports the willneed advice type" do - require 'etc' - uname = if Etc.respond_to?(:uname) - Etc.uname[:release] - else - `uname -r`.chomp - end - if (uname.split('.').map(&:to_i) <=> [3,6]) < 0 - skip "[ruby-core:65355] tmpfs is not supported" - else - @io.advise(:willneed).should be_nil - end + @io.advise(:willneed).should be_nil end end diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb index 5d81d5fcd9..067ab59d93 100644 --- a/spec/ruby/core/io/fixtures/classes.rb +++ b/spec/ruby/core/io/fixtures/classes.rb @@ -108,6 +108,14 @@ module IOSpecs "linha ", "cinco.\nHere ", "is ", "line ", "six.\n" ] end + def self.lines_space_separator_without_trailing_spaces + [ "Voici", "la", "ligne", "une.\nQui", + "\303\250", "la", "linea", "due.\n\n\nAqu\303\255", + "est\303\241", "la", "l\303\255nea", "tres.\nHier", + "ist", "Zeile", "vier.\n\nEst\303\241", "aqui", "a", + "linha", "cinco.\nHere", "is", "line", "six.\n" ] + end + def self.lines_arbitrary_separator [ "Voici la ligne une.\nQui \303\250", " la linea due.\n\n\nAqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.\n\nEst\303\241 aqui a linha cinco.\nHere is line six.\n" ] @@ -119,6 +127,12 @@ module IOSpecs "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ] end + def self.paragraphs_without_trailing_new_line_characters + [ "Voici la ligne une.\nQui \303\250 la linea due.", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.", + "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ] + end + # Creates an IO instance for an existing fixture file. The # file should obviously not be deleted. def self.io_fixture(name, mode = "r:utf-8") diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb index 42238f6201..b9f82f8133 100644 --- a/spec/ruby/core/io/gets_spec.rb +++ b/spec/ruby/core/io/gets_spec.rb @@ -119,6 +119,16 @@ describe "IO#gets" do it "returns the first line without a trailing newline character" do @io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0] end + + ruby_version_is "3.0" do + it "raises exception when options passed as Hash" do + -> { @io.gets({ chomp: true }) }.should raise_error(TypeError) + + -> { + @io.gets("\n", 1, { chomp: true }) + }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") + end + end end end @@ -200,6 +210,10 @@ describe "IO#gets" do it "reads all bytes when pass a separator and reading more than all bytes" do @io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n" end + + it "returns empty string when 0 passed as a limit" do + @io.gets(0).should == "" + end end describe "IO#gets" do diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb index 7cb1601816..ca30f31e39 100644 --- a/spec/ruby/core/io/readline_spec.rb +++ b/spec/ruby/core/io/readline_spec.rb @@ -43,9 +43,40 @@ describe "IO#readline" do end end + describe "when passed limit" do + it "reads limit bytes" do + @io.readline(3).should == "Voi" + end + + it "returns an empty string when passed 0 as a limit" do + @io.readline(0).should == "" + end + end + + describe "when passed separator and limit" do + it "reads limit bytes till the separator" do + # Voici la ligne une.\ + @io.readline(" ", 4).should == "Voic" + @io.readline(" ", 4).should == "i " + @io.readline(" ", 4).should == "la " + @io.readline(" ", 4).should == "lign" + @io.readline(" ", 4).should == "e " + end + end + describe "when passed chomp" do it "returns the first line without a trailing newline character" do @io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0] end + + ruby_version_is "3.0" do + it "raises exception when options passed as Hash" do + -> { @io.readline({ chomp: true }) }.should raise_error(TypeError) + + -> { + @io.readline("\n", 1, { chomp: true }) + }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") + end + end end end diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb index 254f2927b5..15af6debbe 100644 --- a/spec/ruby/core/io/readlines_spec.rb +++ b/spec/ruby/core/io/readlines_spec.rb @@ -101,6 +101,28 @@ describe "IO#readlines" do @io.readlines(obj).should == IOSpecs.lines_r_separator end end + + describe "when passed limit" do + it "raises ArgumentError when passed 0 as a limit" do + -> { @io.readlines(0) }.should raise_error(ArgumentError) + end + end + + describe "when passed chomp" do + it "returns the first line without a trailing newline character" do + @io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters + end + + ruby_version_is "3.0" do + it "raises exception when options passed as Hash" do + -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError) + + -> { + @io.readlines("\n", 1, { chomp: true }) + }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") + end + end + end end describe "IO#readlines" do diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb index 91766fbe03..badf8985e0 100644 --- a/spec/ruby/core/io/shared/each.rb +++ b/spec/ruby/core/io/shared/each.rb @@ -161,6 +161,54 @@ describe :io_each, shared: true do @io.send(@method, chomp: true) { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters end + + ruby_version_is "3.0" do + it "raises exception when options passed as Hash" do + -> { + @io.send(@method, { chomp: true }) { |s| } + }.should raise_error(TypeError) + + -> { + @io.send(@method, "\n", 1, { chomp: true }) { |s| } + }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") + end + end + end + + describe "when passed chomp and a separator" do + it "yields each line without separator to the passed block" do + @io.send(@method, " ", chomp: true) { |s| ScratchPad << s } + ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces + end + end + + describe "when passed chomp and empty line as a separator" do + it "yields each paragraph without trailing new line characters" do + @io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s } + ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters + end + end + + describe "when passed chomp and nil as a separator" do + it "yields self's content without trailing new line character" do + @io.pos = 100 + @io.send(@method, nil, chomp: true) { |s| ScratchPad << s } + ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."] + end + end + + describe "when passed chomp, nil as a separator, and a limit" do + it "yields each line of limit size without truncating trailing new line character" do + # 43 - is a size of the 1st paragraph in the file + @io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s } + + ScratchPad.recorded.should == [ + "Voici la ligne une.\nQui è la linea due.\n\n\n", + "Aquí está la línea tres.\n" + "Hier ist Zeile ", + "vier.\n\nEstá aqui a linha cinco.\nHere is li", + "ne six.\n" + ] + end end end diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb index 52b20364ef..479452b71c 100644 --- a/spec/ruby/core/io/shared/readlines.rb +++ b/spec/ruby/core/io/shared/readlines.rb @@ -78,6 +78,14 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, -2, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines end + + ruby_bug "#18767", ""..."3.3" do + describe "when passed limit" do + it "raises ArgumentError when passed 0 as a limit" do + -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError) + end + end + end end describe "when the object is a String" do @@ -92,31 +100,35 @@ describe :io_readlines_options_19, shared: true do end end - describe "when the object is a Hash" do - it "uses the value as the options hash" do - result = IO.send(@method, @name, mode: "r", &@object) - (result ? result : ScratchPad.recorded).should == IOSpecs.lines + describe "when the object is an options Hash" do + ruby_version_is "3.0" do + it "raises TypeError exception" do + -> { + IO.send(@method, @name, { chomp: true }, &@object) + }.should raise_error(TypeError) + end + end + end + + describe "when the object is neither Integer nor String" do + it "raises TypeError exception" do + obj = mock("not io readlines limit") + + -> { + IO.send(@method, @name, obj, &@object) + }.should raise_error(TypeError) end end end - describe "when passed name, object, object" do - describe "when the first object is an Integer" do - it "uses the second object as an options Hash" do - -> do - IO.send(@method, @filename, 10, mode: "w", &@object) - end.should raise_error(IOError) - end - - it "calls #to_hash to convert the second object to a Hash" do - options = mock("io readlines options Hash") - options.should_receive(:to_hash).and_return({ mode: "w" }) - -> do - IO.send(@method, @filename, 10, **options, &@object) - end.should raise_error(IOError) - end + describe "when passed name, keyword arguments" do + it "uses the keyword arguments as options" do + result = IO.send(@method, @name, mode: "r", &@object) + (result ? result : ScratchPad.recorded).should == IOSpecs.lines end + end + describe "when passed name, object, object" do describe "when the first object is a String" do it "uses the second object as a limit if it is an Integer" do result = IO.send(@method, @name, " ", 10, &@object) @@ -129,32 +141,18 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, " ", limit, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end - - it "uses the second object as an options Hash" do - -> do - IO.send(@method, @filename, " ", mode: "w", &@object) - end.should raise_error(IOError) - end - - it "calls #to_hash to convert the second object to a Hash" do - options = mock("io readlines options Hash") - options.should_receive(:to_hash).and_return({ mode: "w" }) - -> do - IO.send(@method, @filename, " ", **options, &@object) - end.should raise_error(IOError) - end end describe "when the first object is not a String or Integer" do it "calls #to_str to convert the object to a String" do sep = mock("io readlines separator") sep.should_receive(:to_str).at_least(1).and_return(" ") - result = IO.send(@method, @name, sep, 10, mode: "r", &@object) + result = IO.send(@method, @name, sep, 10, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end it "uses the second object as a limit if it is an Integer" do - result = IO.send(@method, @name, " ", 10, mode: "r", &@object) + result = IO.send(@method, @name, " ", 10, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end @@ -164,24 +162,59 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, " ", limit, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end + end - it "uses the second object as an options Hash" do + describe "when the second object is neither Integer nor String" do + it "raises TypeError exception" do + obj = mock("not io readlines limit") + + -> { + IO.send(@method, @name, " ", obj, &@object) + }.should raise_error(TypeError) + end + end + + describe "when the second object is an options Hash" do + ruby_version_is "3.0" do + it "raises TypeError exception" do + -> { + IO.send(@method, @name, "", { chomp: true }, &@object) + }.should raise_error(TypeError) + end + end + end + end + + describe "when passed name, object, keyword arguments" do + describe "when the first object is an Integer" do + it "uses the keyword arguments as options" do + -> do + IO.send(@method, @filename, 10, mode: "w", &@object) + end.should raise_error(IOError) + end + end + + describe "when the first object is a String" do + it "uses the keyword arguments as options" do -> do IO.send(@method, @filename, " ", mode: "w", &@object) end.should raise_error(IOError) end + end + + describe "when the first object is not a String or Integer" do + it "uses the keyword arguments as options" do + sep = mock("io readlines separator") + sep.should_receive(:to_str).at_least(1).and_return(" ") - it "calls #to_hash to convert the second object to a Hash" do - options = mock("io readlines options Hash") - options.should_receive(:to_hash).and_return({ mode: "w" }) -> do - IO.send(@method, @filename, " ", **options, &@object) + IO.send(@method, @filename, sep, mode: "w", &@object) end.should raise_error(IOError) end end end - describe "when passed name, separator, limit, options" do + describe "when passed name, separator, limit, keyword arguments" do it "calls #to_path to convert the name object" do name = mock("io name to_path") name.should_receive(:to_path).and_return(@name) @@ -203,12 +236,24 @@ describe :io_readlines_options_19, shared: true do (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end - it "calls #to_hash to convert the options object" do - options = mock("io readlines options Hash") - options.should_receive(:to_hash).and_return({ mode: "w" }) + it "uses the keyword arguments as options" do -> do - IO.send(@method, @filename, " ", 10, **options, &@object) + IO.send(@method, @filename, " ", 10, mode: "w", &@object) end.should raise_error(IOError) end + + describe "when passed chomp, nil as a separator, and a limit" do + it "yields each line of limit size without truncating trailing new line character" do + # 43 - is a size of the 1st paragraph in the file + result = IO.send(@method, @name, nil, 43, chomp: true, &@object) + + (result ? result : ScratchPad.recorded).should == [ + "Voici la ligne une.\nQui è la linea due.\n\n\n", + "Aquí está la línea tres.\n" + "Hier ist Zeile ", + "vier.\n\nEstá aqui a linha cinco.\nHere is li", + "ne six.\n" + ] + end + end end end diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb index bb6f03d3bf..f1d2a45df8 100644 --- a/spec/ruby/core/kernel/instance_variable_get_spec.rb +++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb @@ -67,6 +67,12 @@ describe "Kernel#instance_variable_get when passed Symbol" do it "raises a NameError when the passed Symbol is an invalid instance variable name" do -> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError) end + + it "returns nil or raises for frozen objects" do + nil.instance_variable_get(:@foo).should == nil + -> { nil.instance_variable_get(:foo) }.should raise_error(NameError) + :foo.instance_variable_get(:@foo).should == nil + end end describe "Kernel#instance_variable_get when passed String" do diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb index dbd257f7b9..2c25f4366f 100644 --- a/spec/ruby/core/kernel/instance_variable_set_spec.rb +++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb @@ -95,5 +95,11 @@ describe "Kernel#instance_variable_set" do o.instance_variable_set(:@💙, 42) o.instance_variable_get(:@💙).should == 42 end + + it "raises for frozen objects" do + -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError) + -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError) + -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError) + end end end diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb index e90efc8aed..4e5ba5e018 100644 --- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb +++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb @@ -41,6 +41,19 @@ describe "Kernel#remove_instance_variable" do end.should raise_error(TypeError) end + it "raises a FrozenError if self is frozen" do + o = Object.new + o.freeze + -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError) + -> { o.remove_instance_variable(:foo) }.should raise_error(NameError) + end + + it "raises for frozen objects" do + -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError) + -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError) + -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError) + end + describe "when passed a String" do it_behaves_like :kernel_remove_instance_variable, nil, "@greeting" end diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index cf01b9dc52..666ca15e11 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -568,6 +568,25 @@ describe :kernel_require, shared: true do -> { @object.require("unicode_normalize") }.should raise_error(LoadError) end + + ruby_version_is "3.0" do + it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do + Dir.chdir CODE_LOADING_DIR do + @object.send(@method, "../code/load_fixture").should be_true + end + ScratchPad.recorded.should == [:loaded] + + $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b" + # This loads because the above load was not on the $LOAD_PATH + @object.send(@method, "load_fixture").should be_true + ScratchPad.recorded.should == [:loaded, :loaded] + + $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c" + # This does not load because the above load was on the $LOAD_PATH + @object.send(@method, "load_fixture").should be_false + ScratchPad.recorded.should == [:loaded, :loaded] + end + end end describe "(shell expansion)" do diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb index fb7799cf26..6dcf94a663 100644 --- a/spec/ruby/core/math/ldexp_spec.rb +++ b/spec/ruby/core/math/ldexp_spec.rb @@ -45,6 +45,12 @@ describe "Math.ldexp" do it "accepts any second argument that can be coerced with Integer()" do Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE) end + + it "returns correct value that closes to the max value of double type" do + Math.ldexp(0.5122058490966879, 1024).should == 9.207889385574391e+307 + Math.ldexp(0.9999999999999999, 1024).should == 1.7976931348623157e+308 + Math.ldexp(0.99999999999999999, 1024).should == Float::INFINITY + end end describe "Math#ldexp" do diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb index fd7aa93aa8..e155f1deac 100644 --- a/spec/ruby/core/module/class_variables_spec.rb +++ b/spec/ruby/core/module/class_variables_spec.rb @@ -23,4 +23,12 @@ describe "Module#class_variables" do c.extend ModuleSpecs::MVars c.class_variables.should_not include(:@@mvar) end + + it "returns the correct class variables when inherit is given" do + ModuleSpecs::SubCVars.class_variables(false).should == [:@@sub] + ModuleSpecs::SubCVars.new.singleton_class.class_variables(false).should == [] + + ModuleSpecs::SubCVars.class_variables(true).should == [:@@sub, :@@cls, :@@meta] + ModuleSpecs::SubCVars.new.singleton_class.class_variables(true).should == [:@@sub, :@@cls, :@@meta] + end end diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb index 40777cdbbd..a64f672b2f 100644 --- a/spec/ruby/core/module/fixtures/classes.rb +++ b/spec/ruby/core/module/fixtures/classes.rb @@ -352,6 +352,10 @@ module ModuleSpecs end end + class SubCVars < CVars + @@sub = :sub + end + module MVars @@mvar = :mvar end diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb index 59e1406e02..f00b8db043 100644 --- a/spec/ruby/core/process/clock_gettime_spec.rb +++ b/spec/ruby/core/process/clock_gettime_spec.rb @@ -52,7 +52,7 @@ describe "Process.clock_gettime" do end # These specs need macOS 10.12+ / darwin 16+ - guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do + guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do platform_is :linux, :openbsd, :darwin do it "CLOCK_PROCESS_CPUTIME_ID" do Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float) @@ -65,20 +65,6 @@ describe "Process.clock_gettime" do end end - platform_is :freebsd, :openbsd do - it "CLOCK_VIRTUAL" do - Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float) - end - - it "CLOCK_PROF" do - Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float) - end - - it "CLOCK_UPTIME" do - Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float) - end - end - platform_is :linux, :darwin do it "CLOCK_MONOTONIC_RAW" do Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float) @@ -95,42 +81,69 @@ describe "Process.clock_gettime" do Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float) end end + end - platform_is :freebsd do - it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do - Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float) - end - - it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do - Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float) - end - - it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do - Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float) - end - - it "CLOCK_SECOND" do - Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float) - end + platform_is :freebsd, :openbsd do + it "CLOCK_VIRTUAL" do + Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float) end - platform_is :linux do - it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do - Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float) - end + it "CLOCK_PROF" do + Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float) + end - it "CLOCK_MONOTONIC_COARSE" do - Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float) - end + it "CLOCK_UPTIME" do + Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float) + end + end - it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do - Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float) - end + platform_is :freebsd do + it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do + Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float) + end + + it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do + Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float) + end + + it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do + Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float) + end + + it "CLOCK_SECOND" do + Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float) + end + end + + guard -> { platform_is :linux and kernel_version_is '2.6.32' } do + it "CLOCK_REALTIME_COARSE" do + Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float) + end + + it "CLOCK_MONOTONIC_COARSE" do + Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float) + end + end + + guard -> { platform_is :linux and kernel_version_is '2.6.39' } do + it "CLOCK_BOOTTIME" do + skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME) + Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float) + end + end + + guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do + it "CLOCK_REALTIME_ALARM" do + skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM) + Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float) + end + + it "CLOCK_BOOTTIME_ALARM" do + skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM) + Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float) end end end diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb index 24dda43804..a67b623d5c 100644 --- a/spec/ruby/core/process/egid_spec.rb +++ b/spec/ruby/core/process/egid_spec.rb @@ -15,5 +15,44 @@ describe "Process.egid" do end describe "Process.egid=" do - it "needs to be reviewed for spec completeness" + + platform_is_not :windows do + it "raises TypeError if not passed an Integer or String" do + -> { Process.egid = Object.new }.should raise_error(TypeError) + end + + it "sets the effective group id to its own gid if given the username corresponding to its own gid" do + raise unless Process.gid == Process.egid + + require "etc" + group = Etc.getgrgid(Process.gid).name + + Process.egid = group + Process.egid.should == Process.gid + end + + as_user do + it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do + -> { Process.egid = 0 }.should raise_error(Errno::EPERM) + end + + platform_is :linux do + it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do + -> { Process.egid = "root" }.should raise_error(Errno::EPERM) + end + end + end + + as_superuser do + context "when ran by a superuser" do + it "sets the effective group id for the current process if run by a superuser" do + code = <<-RUBY + Process.egid = 1 + puts Process.egid + RUBY + ruby_exe(code).should == "1\n" + end + end + end + end end diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb index a2f1bbf42e..c1ec4171d0 100644 --- a/spec/ruby/core/process/euid_spec.rb +++ b/spec/ruby/core/process/euid_spec.rb @@ -21,9 +21,19 @@ describe "Process.euid=" do -> { Process.euid = Object.new }.should raise_error(TypeError) end + it "sets the effective user id to its own uid if given the username corresponding to its own uid" do + raise unless Process.uid == Process.euid + + require "etc" + user = Etc.getpwuid(Process.uid).name + + Process.euid = user + Process.euid.should == Process.uid + end + as_user do it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do - -> { (Process.euid = 0)}.should raise_error(Errno::EPERM) + -> { Process.euid = 0 }.should raise_error(Errno::EPERM) end it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb index 6be3f41a87..9aa8da8125 100644 --- a/spec/ruby/core/process/spawn_spec.rb +++ b/spec/ruby/core/process/spawn_spec.rb @@ -349,7 +349,7 @@ describe "Process.spawn" do pgid = Process.getpgid(Process.pid) # The process group is not available on all platforms. # See "man proc" - /proc/[pid]/stat - (5) pgrp - # In Travis arm64 environment, the value is 0. + # In Travis aarch64 environment, the value is 0. # # $ cat /proc/[pid]/stat # 19179 (ruby) S 19160 0 0 ... diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb index d85bb22214..d8a2be26b8 100644 --- a/spec/ruby/core/process/status/equal_value_spec.rb +++ b/spec/ruby/core/process/status/equal_value_spec.rb @@ -8,7 +8,7 @@ describe "Process::Status#==" do end it "returns true when compared to the integer status of a terminated child" do - ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) $?.to_i.should == $? $?.should == $?.to_i end diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb index 059cd5b1aa..a61292b146 100644 --- a/spec/ruby/core/process/status/exited_spec.rb +++ b/spec/ruby/core/process/status/exited_spec.rb @@ -14,7 +14,7 @@ describe "Process::Status#exited?" do describe "for a terminated child" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb index 3087bd619e..5c86c2b3c8 100644 --- a/spec/ruby/core/process/status/exitstatus_spec.rb +++ b/spec/ruby/core/process/status/exitstatus_spec.rb @@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do describe "for a child that raised SignalException" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb index 389092a533..c0de7b8006 100644 --- a/spec/ruby/core/process/status/signaled_spec.rb +++ b/spec/ruby/core/process/status/signaled_spec.rb @@ -13,7 +13,7 @@ describe "Process::Status#signaled?" do describe "for a terminated child" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb index c531121f08..3589cc611f 100644 --- a/spec/ruby/core/process/status/success_spec.rb +++ b/spec/ruby/core/process/status/success_spec.rb @@ -23,7 +23,7 @@ describe "Process::Status#success?" do describe "for a child that was terminated" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb index 1c87a6f455..5d286950f8 100644 --- a/spec/ruby/core/process/status/termsig_spec.rb +++ b/spec/ruby/core/process/status/termsig_spec.rb @@ -13,7 +13,7 @@ describe "Process::Status#termsig" do describe "for a child that raised SignalException" do before :each do - ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil) + ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM) end platform_is_not :windows do @@ -25,7 +25,7 @@ describe "Process::Status#termsig" do describe "for a child that was sent a signal" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb index 7cde9b915b..39f8e2d84c 100644 --- a/spec/ruby/core/process/status/to_i_spec.rb +++ b/spec/ruby/core/process/status/to_i_spec.rb @@ -7,7 +7,7 @@ describe "Process::Status#to_i" do end it "returns an integer when the child is signaled" do - ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil) + ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM) $?.to_i.should be_an_instance_of(Integer) end end diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb index a55adb5bf2..33bdfd9979 100644 --- a/spec/ruby/core/regexp/shared/quote.rb +++ b/spec/ruby/core/regexp/shared/quote.rb @@ -12,6 +12,11 @@ describe :regexp_quote, shared: true do Regexp.send(@method, :symbol).should == 'symbol' end + it "works with substrings" do + str = ".+[]()"[1...-1] + Regexp.send(@method, str).should == '\+\[\]\(' + end + it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do str = "abc".force_encoding("euc-jp") Regexp.send(@method, str).encoding.should == Encoding::US_ASCII diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb index 3c78922694..2a94a81634 100644 --- a/spec/ruby/core/signal/trap_spec.rb +++ b/spec/ruby/core/signal/trap_spec.rb @@ -254,12 +254,10 @@ describe "Signal.trap" do r.close loop { w.write("a"*1024) } RUBY - out = ruby_exe(code, exit_status: nil) + out = ruby_exe(code, exit_status: :SIGPIPE) status = $? out.should == "nil\n" status.should.signaled? - status.termsig.should be_kind_of(Integer) - Signal.signame(status.termsig).should == "PIPE" end end diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb index ca8df88fec..8afaefc021 100644 --- a/spec/ruby/core/string/capitalize_spec.rb +++ b/spec/ruby/core/string/capitalize_spec.rb @@ -35,6 +35,10 @@ describe "String#capitalize" do it "does not capitalize non-ASCII characters" do "ßet".capitalize(:ascii).should == "ßet" end + + it "handles non-ASCII substrings properly" do + "garçon"[1..-1].capitalize(:ascii).should == "Arçon" + end end describe "full Unicode case mapping adapted for Turkic languages" do diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb index d650788210..eec3cf0a70 100644 --- a/spec/ruby/core/string/dup_spec.rb +++ b/spec/ruby/core/string/dup_spec.rb @@ -49,4 +49,13 @@ describe "String#dup" do orig.should == "xtring" dup.should == "string" end + + it "does not modify the original setbyte-mutated string when changing dupped string" do + orig = "a" + orig.setbyte 0, "b".ord + copy = orig.dup + orig.setbyte 0, "c".ord + orig.should == "c" + copy.should == "b" + end end diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb index db42a37941..0c87df3a95 100644 --- a/spec/ruby/core/string/insert_spec.rb +++ b/spec/ruby/core/string/insert_spec.rb @@ -69,4 +69,13 @@ describe "String#insert with index, other" do "あれ".insert 0, pat end.should raise_error(Encoding::CompatibilityError) end + + it "should not call subclassed string methods" do + cls = Class.new(String) do + def replace(arg) + raise "should not call replace" + end + end + cls.new("abcd").insert(0, 'X').should == "Xabcd" + end end diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb index 6e868eac4f..02bc6b4322 100644 --- a/spec/ruby/core/string/lstrip_spec.rb +++ b/spec/ruby/core/string/lstrip_spec.rb @@ -50,4 +50,10 @@ describe "String#lstrip!" do -> { "hello".freeze.lstrip! }.should raise_error(FrozenError) -> { "".freeze.lstrip! }.should raise_error(FrozenError) end + + it "raises an ArgumentError if the first codepoint is invalid" do + s = "\xDFabc".force_encoding(Encoding::UTF_8) + s.valid_encoding?.should be_false + -> { s.lstrip! }.should raise_error(ArgumentError) + end end diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb index 2dc55182ae..dc34b12719 100644 --- a/spec/ruby/core/string/rstrip_spec.rb +++ b/spec/ruby/core/string/rstrip_spec.rb @@ -46,4 +46,10 @@ describe "String#rstrip!" do -> { "hello".freeze.rstrip! }.should raise_error(FrozenError) -> { "".freeze.rstrip! }.should raise_error(FrozenError) end + + it "raises an ArgumentError if the last codepoint is invalid" do + s = "abc\xDF".force_encoding(Encoding::UTF_8) + s.valid_encoding?.should be_false + -> { s.rstrip! }.should raise_error(ArgumentError) + end end diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb index 3137399291..66755bcc7b 100644 --- a/spec/ruby/core/string/scrub_spec.rb +++ b/spec/ruby/core/string/scrub_spec.rb @@ -14,6 +14,11 @@ describe "String#scrub with a default replacement" do "abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD" end + it "replaces invalid byte sequences in lazy substrings" do + x81 = [0x81].pack('C').force_encoding('utf-8') + "abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde" + end + it "returns a copy of self when the input encoding is BINARY" do input = "foo".encode('BINARY') diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb index 228af5f824..713234fffd 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -375,10 +375,20 @@ describe :string_slice_regexp_index, shared: true do "hello there".send(@method, /(what?)/, 1).should == nil end + it "returns nil if the index is larger than the number of captures" do + "hello there".send(@method, /hello (.)/, 2).should == nil + # You can't refer to 0 using negative indices + "hello there".send(@method, /hello (.)/, -2).should == nil + end + it "returns nil if there is no capture for the given index" do "hello there".send(@method, /[aeiou](.)\1/, 2).should == nil - # You can't refer to 0 using negative indices - "hello there".send(@method, /[aeiou](.)\1/, -2).should == nil + end + + it "returns nil if the given capture group was not matched but still sets $~" do + "test".send(@method, /te(z)?/, 1).should == nil + $~[0].should == "te" + $~[1].should == nil end it "calls to_int on the given index" do diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index 82911ef50b..7ef34c65da 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -3,12 +3,17 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#split with String" do + it "throws an ArgumentError if the string is not a valid" do + s = "\xDF".force_encoding(Encoding::UTF_8) + + -> { s.split }.should raise_error(ArgumentError) + -> { s.split(':') }.should raise_error(ArgumentError) + end + it "throws an ArgumentError if the pattern is not a valid string" do str = 'проверка' - broken_str = 'проверка' - broken_str.force_encoding('binary') - broken_str.chop! - broken_str.force_encoding('utf-8') + broken_str = "\xDF".force_encoding(Encoding::UTF_8) + -> { str.split(broken_str) }.should raise_error(ArgumentError) end @@ -218,6 +223,12 @@ describe "String#split with String" do end describe "String#split with Regexp" do + it "throws an ArgumentError if the string is not a valid" do + s = "\xDF".force_encoding(Encoding::UTF_8) + + -> { s.split(/./) }.should raise_error(ArgumentError) + end + it "divides self on regexp matches" do " now's the time".split(/ /).should == ["", "now's", "", "the", "time"] " x\ny ".split(/ /).should == ["", "x\ny"] diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb index 552851ce04..ce8da4b29e 100644 --- a/spec/ruby/core/string/unpack/z_spec.rb +++ b/spec/ruby/core/string/unpack/z_spec.rb @@ -20,4 +20,9 @@ describe "String#unpack with format 'Z'" do ["\x00a\x00 bc \x00", ["", "c"]] ].should be_computed_by(:unpack, "Z5Z") end + + it "does not advance past the null byte when given a 'Z' format specifier" do + "a\x00\x0f".unpack('Zxc').should == ['a', 15] + "a\x00\x0f".unpack('Zcc').should == ['a', 0, 15] + end end diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb index 27de3cc627..49323cf270 100644 --- a/spec/ruby/core/thread/raise_spec.rb +++ b/spec/ruby/core/thread/raise_spec.rb @@ -102,6 +102,30 @@ describe "Thread#raise on a sleeping thread" do raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") end end + + it "calls #exception in both the caller and in the target thread" do + cls = Class.new(Exception) do + attr_accessor :log + def initialize(*args) + @log = [] # This is shared because the super #exception uses a shallow clone + super + end + + def exception(*args) + @log << [self, Thread.current, args] + super + end + end + exc = cls.new + + @thr.raise exc, "Thread#raise #exception spec" + @thr.join + ScratchPad.recorded.should.is_a?(cls) + exc.log.should == [ + [exc, Thread.current, ["Thread#raise #exception spec"]], + [ScratchPad.recorded, @thr, []] + ] + end end describe "Thread#raise on a running thread" do diff --git a/spec/ruby/fixtures/code/c/load_fixture.rb b/spec/ruby/fixtures/code/c/load_fixture.rb new file mode 100644 index 0000000000..4a6e9c9601 --- /dev/null +++ b/spec/ruby/fixtures/code/c/load_fixture.rb @@ -0,0 +1 @@ +ScratchPad << :loaded diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb index 217dcab74b..02461655d6 100644 --- a/spec/ruby/language/optional_assignments_spec.rb +++ b/spec/ruby/language/optional_assignments_spec.rb @@ -300,6 +300,44 @@ describe 'Optional variable assignments' do (@b[:k] ||= 12).should == 12 end + it 'correctly handles a splatted argument for the index' do + (@b[*[:k]] ||= 12).should == 12 + end + + it "evaluates the index precisely once" do + ary = [:x, :y] + @a[:x] = 15 + @a[ary.pop] ||= 25 + ary.should == [:x] + @a.should == { x: 15, y: 25 } + end + + it "evaluates the index arguments in the correct order" do + ary = Class.new(Array) do + def [](x, y) + super(x + 3 * y) + end + + def []=(x, y, value) + super(x + 3 * y, value) + end + end.new + ary[0, 0] = 1 + ary[1, 0] = 1 + ary[2, 0] = nil + ary[3, 0] = 1 + ary[4, 0] = 1 + ary[5, 0] = 1 + ary[6, 0] = nil + + foo = [0, 2] + + ary[foo.pop, foo.pop] ||= 2 + + ary[2, 0].should == 2 + ary[6, 0].should == nil + end + it 'returns the assigned value, not the result of the []= method with +=' do @b[:k] = 17 (@b[:k] += 12).should == 29 diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index b5eda7f789..87385a29e5 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -570,7 +570,6 @@ describe "Predefined global $/" do ($/ = "xyz").should == "xyz" end - it "changes $-0" do $/ = "xyz" $-0.should equal($/) @@ -641,6 +640,45 @@ describe "Predefined global $-0" do end end +describe "Predefined global $\\" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + @dollar_backslash = $\ + end + + after :each do + $\ = @dollar_backslash + $VERBOSE = @verbose + end + + it "can be assigned a String" do + str = "abc" + $\ = str + $\.should equal(str) + end + + it "can be assigned nil" do + $\ = nil + $\.should be_nil + end + + it "returns the value assigned" do + ($\ = "xyz").should == "xyz" + end + + it "does not call #to_str to convert the object to a String" do + obj = mock("$\\ value") + obj.should_not_receive(:to_str) + + -> { $\ = obj }.should raise_error(TypeError) + end + + it "raises a TypeError if assigned not String" do + -> { $\ = 1 }.should raise_error(TypeError) + -> { $\ = true }.should raise_error(TypeError) + end +end + describe "Predefined global $," do after :each do $, = nil @@ -1340,3 +1378,29 @@ describe "$LOAD_PATH.resolve_feature_path" do end end end + +# Some other pre-defined global variables + +describe "Predefined global $=" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + @dollar_assign = $= + end + + after :each do + $= = @dollar_assign + $VERBOSE = @verbose + end + + it "warns when accessed" do + -> { a = $= }.should complain(/is no longer effective/) + end + + it "warns when assigned" do + -> { $= = "_" }.should complain(/is no longer effective/) + end + + it "returns the value assigned" do + ($= = "xyz").should == "xyz" + end +end diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb index 431c5aca99..c900c03d37 100644 --- a/spec/ruby/language/variables_spec.rb +++ b/spec/ruby/language/variables_spec.rb @@ -849,4 +849,22 @@ describe "Instance variables" do -> { obj.foobar }.should_not complain(verbose: true) end end + + describe "global variable" do + context "when global variable is uninitialized" do + it "warns about accessing uninitialized global variable in verbose mode" do + obj = Object.new + def obj.foobar; a = $specs_uninitialized_global_variable; end + + -> { obj.foobar }.should complain(/warning: global variable `\$specs_uninitialized_global_variable' not initialized/, verbose: true) + end + + it "doesn't warn at lazy initialization" do + obj = Object.new + def obj.foobar; $specs_uninitialized_global_variable_lazy ||= 42; end + + -> { obj.foobar }.should_not complain(verbose: true) + end + end + end end diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb index 85bd5af25b..05d713af70 100644 --- a/spec/ruby/language/yield_spec.rb +++ b/spec/ruby/language/yield_spec.rb @@ -213,3 +213,13 @@ describe "Using yield in a singleton class literal" do end end end + +describe "Using yield in non-lambda block" do + it 'raises a SyntaxError' do + code = <<~RUBY + 1.times { yield } + RUBY + + -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) + end +end diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb index 3100511dc9..612430e067 100644 --- a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb +++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb @@ -128,4 +128,22 @@ describe "ObjectSpace.trace_object_allocations" do ObjectSpace.trace_object_allocations_stop end end + + it "returns nil for class_path, generation, method_id, sourcefile, and sourceline for immutable objects" do + ObjectSpace.trace_object_allocations_start + begin + one = nil + two = 42 + three = :foo + [one, two, three].each do |i| + ObjectSpace.allocation_class_path(i).should == nil + ObjectSpace.allocation_generation(i).should == nil + ObjectSpace.allocation_method_id(i).should == nil + ObjectSpace.allocation_sourcefile(i).should == nil + ObjectSpace.allocation_sourceline(i).should == nil + end + ensure + ObjectSpace.trace_object_allocations_stop + end + end end diff --git a/spec/ruby/library/openssl/x509/name/verify_spec.rb b/spec/ruby/library/openssl/x509/name/verify_spec.rb new file mode 100644 index 0000000000..f5384f5764 --- /dev/null +++ b/spec/ruby/library/openssl/x509/name/verify_spec.rb @@ -0,0 +1,78 @@ +require_relative '../../../../spec_helper' +require 'openssl' + +describe "OpenSSL::X509::Name.verify" do + it "returns true for valid certificate" do + key = OpenSSL::PKey::RSA.new 2048 + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 1 + cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" + cert.issuer = cert.subject + cert.public_key = key.public_key + cert.not_before = Time.now + cert.not_after = cert.not_before + 365 * 24 * 60 * 60 + cert.sign key, OpenSSL::Digest.new('SHA1') + store = OpenSSL::X509::Store.new + store.add_cert(cert) + store.verify(cert).should == true + end + + it "returns false for an expired certificate" do + key = OpenSSL::PKey::RSA.new 2048 + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 1 + cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" + cert.issuer = cert.subject + cert.public_key = key.public_key + cert.not_before = Time.now - 10 + cert.not_after = Time.now - 5 + cert.sign key, OpenSSL::Digest.new('SHA1') + store = OpenSSL::X509::Store.new + store.add_cert(cert) + store.verify(cert).should == false + end + + it "returns false for an expired root certificate" do + root_key = OpenSSL::PKey::RSA.new 2048 + root_cert = OpenSSL::X509::Certificate.new + root_cert.version = 2 + root_cert.serial = 1 + root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" + root_cert.issuer = root_cert.subject + root_cert.public_key = root_key.public_key + root_cert.not_before = Time.now - 10 + root_cert.not_after = Time.now - 5 + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = root_cert + ef.issuer_certificate = root_cert + root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true)) + root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true)) + root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) + root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false)) + root_cert.sign(root_key, OpenSSL::Digest.new('SHA256')) + + + key = OpenSSL::PKey::RSA.new 2048 + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 2 + cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate" + cert.issuer = root_cert.subject + cert.public_key = key.public_key + cert.not_before = Time.now + cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = cert + ef.issuer_certificate = root_cert + cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true)) + cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) + cert.sign(root_key, OpenSSL::Digest.new('SHA256')) + + store = OpenSSL::X509::Store.new + store.add_cert(root_cert) + store.add_cert(cert) + store.verify(cert).should == false + end +end diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb index 1389408399..c68f7dae82 100644 --- a/spec/ruby/library/stringio/each_line_spec.rb +++ b/spec/ruby/library/stringio/each_line_spec.rb @@ -17,3 +17,7 @@ end describe "StringIO#each_line when passed chomp" do it_behaves_like :stringio_each_chomp, :each_line end + +describe "StringIO#each_line when passed limit" do + it_behaves_like :stringio_each_limit, :each_line +end diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb index a76460049b..2c30ed5cda 100644 --- a/spec/ruby/library/stringio/each_spec.rb +++ b/spec/ruby/library/stringio/each_spec.rb @@ -17,3 +17,11 @@ end describe "StringIO#each when passed chomp" do it_behaves_like :stringio_each_chomp, :each end + +describe "StringIO#each when passed chomp" do + it_behaves_like :stringio_each_separator_and_chomp, :each +end + +describe "StringIO#each when passed limit" do + it_behaves_like :stringio_each_limit, :each +end diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb index 97429e6a29..d597ec0e45 100644 --- a/spec/ruby/library/stringio/gets_spec.rb +++ b/spec/ruby/library/stringio/gets_spec.rb @@ -171,6 +171,10 @@ describe "StringIO#gets when passed [limit]" do it "returns a blank string when passed a limit of 0" do @io.gets(0).should == "" end + + it "ignores it when passed a negative limit" do + @io.gets(-4).should == "this>is>an>example" + end end describe "StringIO#gets when passed [separator] and [limit]" do diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb index 94b67bc92d..b794e5fade 100644 --- a/spec/ruby/library/stringio/readline_spec.rb +++ b/spec/ruby/library/stringio/readline_spec.rb @@ -128,3 +128,23 @@ describe "StringIO#readline when passed [chomp]" do io.readline(chomp: true).should == "this>is>an>example" end end + +describe "StringIO#readline when passed [limit]" do + before :each do + @io = StringIO.new("this>is>an>example") + end + + it "returns the data read until the limit is met" do + io = StringIO.new("this>is>an>example\n") + io.readline(3).should == "thi" + end + + it "returns a blank string when passed a limit of 0" do + @io.readline(0).should == "" + end + + it "ignores it when the limit is negative" do + seen = [] + @io.readline(-4).should == "this>is>an>example" + end +end diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb index 4b007787e2..c471d0fd73 100644 --- a/spec/ruby/library/stringio/readlines_spec.rb +++ b/spec/ruby/library/stringio/readlines_spec.rb @@ -98,3 +98,21 @@ describe "StringIO#readlines when passed [chomp]" do io.readlines(chomp: true).should == ["this>is", "an>example"] end end + +describe "StringIO#readlines when passed [limit]" do + before :each do + @io = StringIO.new("a b c d e\n1 2 3 4 5") + end + + it "returns the data read until the limit is met" do + @io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] + end + + it "raises ArgumentError when limit is 0" do + -> { @io.readlines(0) }.should raise_error(ArgumentError) + end + + it "ignores it when the limit is negative" do + @io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"] + end +end diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb index 3be6661ce5..bf3265ee46 100644 --- a/spec/ruby/library/stringio/shared/each.rb +++ b/spec/ruby/library/stringio/shared/each.rb @@ -123,4 +123,41 @@ describe :stringio_each_chomp, shared: true do io.send(@method, chomp: true) {|s| seen << s } seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] end + + it "returns each line with removed newline characters when called without block" do + seen = [] + io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end") + enum = io.send(@method, chomp: true) + enum.each {|s| seen << s } + seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] + end +end + +describe :stringio_each_separator_and_chomp, shared: true do + it "yields each line with removed separator to the passed block" do + seen = [] + io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") + io.send(@method, "|", chomp: true) {|s| seen << s } + seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] + end + + it "returns each line with removed separator when called without block" do + seen = [] + io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") + enum = io.send(@method, "|", chomp: true) + enum.each {|s| seen << s } + seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] + end +end + +describe :stringio_each_limit, shared: true do + before :each do + @io = StringIO.new("a b c d e\n1 2 3 4 5") + end + + it "returns the data read until the limit is met" do + seen = [] + @io.send(@method, 4) { |s| seen << s } + seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] + end end diff --git a/spec/ruby/library/zlib/crc_table_spec.rb b/spec/ruby/library/zlib/crc_table_spec.rb index f7fc2749fa..de8876086b 100644 --- a/spec/ruby/library/zlib/crc_table_spec.rb +++ b/spec/ruby/library/zlib/crc_table_spec.rb @@ -2,74 +2,79 @@ require_relative '../../spec_helper' require "zlib" describe "Zlib.crc_table" do - - it "returns the same value as zlib's get_crc_table()" do - Zlib.crc_table.should == [ - 0, 1996959894, 3993919788, 2567524794, - 124634137, 1886057615, 3915621685, 2657392035, - 249268274, 2044508324, 3772115230, 2547177864, - 162941995, 2125561021, 3887607047, 2428444049, - 498536548, 1789927666, 4089016648, 2227061214, - 450548861, 1843258603, 4107580753, 2211677639, - 325883990, 1684777152, 4251122042, 2321926636, - 335633487, 1661365465, 4195302755, 2366115317, - 997073096, 1281953886, 3579855332, 2724688242, - 1006888145, 1258607687, 3524101629, 2768942443, - 901097722, 1119000684, 3686517206, 2898065728, - 853044451, 1172266101, 3705015759, 2882616665, - 651767980, 1373503546, 3369554304, 3218104598, - 565507253, 1454621731, 3485111705, 3099436303, - 671266974, 1594198024, 3322730930, 2970347812, - 795835527, 1483230225, 3244367275, 3060149565, - 1994146192, 31158534, 2563907772, 4023717930, - 1907459465, 112637215, 2680153253, 3904427059, - 2013776290, 251722036, 2517215374, 3775830040, - 2137656763, 141376813, 2439277719, 3865271297, - 1802195444, 476864866, 2238001368, 4066508878, - 1812370925, 453092731, 2181625025, 4111451223, - 1706088902, 314042704, 2344532202, 4240017532, - 1658658271, 366619977, 2362670323, 4224994405, - 1303535960, 984961486, 2747007092, 3569037538, - 1256170817, 1037604311, 2765210733, 3554079995, - 1131014506, 879679996, 2909243462, 3663771856, - 1141124467, 855842277, 2852801631, 3708648649, - 1342533948, 654459306, 3188396048, 3373015174, - 1466479909, 544179635, 3110523913, 3462522015, - 1591671054, 702138776, 2966460450, 3352799412, - 1504918807, 783551873, 3082640443, 3233442989, - 3988292384, 2596254646, 62317068, 1957810842, - 3939845945, 2647816111, 81470997, 1943803523, - 3814918930, 2489596804, 225274430, 2053790376, - 3826175755, 2466906013, 167816743, 2097651377, - 4027552580, 2265490386, 503444072, 1762050814, - 4150417245, 2154129355, 426522225, 1852507879, - 4275313526, 2312317920, 282753626, 1742555852, - 4189708143, 2394877945, 397917763, 1622183637, - 3604390888, 2714866558, 953729732, 1340076626, - 3518719985, 2797360999, 1068828381, 1219638859, - 3624741850, 2936675148, 906185462, 1090812512, - 3747672003, 2825379669, 829329135, 1181335161, - 3412177804, 3160834842, 628085408, 1382605366, - 3423369109, 3138078467, 570562233, 1426400815, - 3317316542, 2998733608, 733239954, 1555261956, - 3268935591, 3050360625, 752459403, 1541320221, - 2607071920, 3965973030, 1969922972, 40735498, - 2617837225, 3943577151, 1913087877, 83908371, - 2512341634, 3803740692, 2075208622, 213261112, - 2463272603, 3855990285, 2094854071, 198958881, - 2262029012, 4057260610, 1759359992, 534414190, - 2176718541, 4139329115, 1873836001, 414664567, - 2282248934, 4279200368, 1711684554, 285281116, - 2405801727, 4167216745, 1634467795, 376229701, - 2685067896, 3608007406, 1308918612, 956543938, - 2808555105, 3495958263, 1231636301, 1047427035, - 2932959818, 3654703836, 1088359270, 936918000, - 2847714899, 3736837829, 1202900863, 817233897, - 3183342108, 3401237130, 1404277552, 615818150, - 3134207493, 3453421203, 1423857449, 601450431, - 3009837614, 3294710456, 1567103746, 711928724, - 3020668471, 3272380065, 1510334235, 755167117, - ] + # This spec fails when zlib.h and libz.so are not from the same version. + # In older zlib (< 1.2.7 it seems), get_crc_table() is stored as u64[], + # but in newer zlib, get_crc_table() is stored as u32[]. + # Technically, there is ABI breakage between those zlib versions, + # but get_crc_table() is an "undocumented function" according to zlib.h. + guard -> { ENV["RUBY_SPEC_TEST_ZLIB_CRC_TABLE"] != "false" } do + it "returns the same value as zlib's get_crc_table()" do + Zlib.crc_table.should == [ + 0, 1996959894, 3993919788, 2567524794, + 124634137, 1886057615, 3915621685, 2657392035, + 249268274, 2044508324, 3772115230, 2547177864, + 162941995, 2125561021, 3887607047, 2428444049, + 498536548, 1789927666, 4089016648, 2227061214, + 450548861, 1843258603, 4107580753, 2211677639, + 325883990, 1684777152, 4251122042, 2321926636, + 335633487, 1661365465, 4195302755, 2366115317, + 997073096, 1281953886, 3579855332, 2724688242, + 1006888145, 1258607687, 3524101629, 2768942443, + 901097722, 1119000684, 3686517206, 2898065728, + 853044451, 1172266101, 3705015759, 2882616665, + 651767980, 1373503546, 3369554304, 3218104598, + 565507253, 1454621731, 3485111705, 3099436303, + 671266974, 1594198024, 3322730930, 2970347812, + 795835527, 1483230225, 3244367275, 3060149565, + 1994146192, 31158534, 2563907772, 4023717930, + 1907459465, 112637215, 2680153253, 3904427059, + 2013776290, 251722036, 2517215374, 3775830040, + 2137656763, 141376813, 2439277719, 3865271297, + 1802195444, 476864866, 2238001368, 4066508878, + 1812370925, 453092731, 2181625025, 4111451223, + 1706088902, 314042704, 2344532202, 4240017532, + 1658658271, 366619977, 2362670323, 4224994405, + 1303535960, 984961486, 2747007092, 3569037538, + 1256170817, 1037604311, 2765210733, 3554079995, + 1131014506, 879679996, 2909243462, 3663771856, + 1141124467, 855842277, 2852801631, 3708648649, + 1342533948, 654459306, 3188396048, 3373015174, + 1466479909, 544179635, 3110523913, 3462522015, + 1591671054, 702138776, 2966460450, 3352799412, + 1504918807, 783551873, 3082640443, 3233442989, + 3988292384, 2596254646, 62317068, 1957810842, + 3939845945, 2647816111, 81470997, 1943803523, + 3814918930, 2489596804, 225274430, 2053790376, + 3826175755, 2466906013, 167816743, 2097651377, + 4027552580, 2265490386, 503444072, 1762050814, + 4150417245, 2154129355, 426522225, 1852507879, + 4275313526, 2312317920, 282753626, 1742555852, + 4189708143, 2394877945, 397917763, 1622183637, + 3604390888, 2714866558, 953729732, 1340076626, + 3518719985, 2797360999, 1068828381, 1219638859, + 3624741850, 2936675148, 906185462, 1090812512, + 3747672003, 2825379669, 829329135, 1181335161, + 3412177804, 3160834842, 628085408, 1382605366, + 3423369109, 3138078467, 570562233, 1426400815, + 3317316542, 2998733608, 733239954, 1555261956, + 3268935591, 3050360625, 752459403, 1541320221, + 2607071920, 3965973030, 1969922972, 40735498, + 2617837225, 3943577151, 1913087877, 83908371, + 2512341634, 3803740692, 2075208622, 213261112, + 2463272603, 3855990285, 2094854071, 198958881, + 2262029012, 4057260610, 1759359992, 534414190, + 2176718541, 4139329115, 1873836001, 414664567, + 2282248934, 4279200368, 1711684554, 285281116, + 2405801727, 4167216745, 1634467795, 376229701, + 2685067896, 3608007406, 1308918612, 956543938, + 2808555105, 3495958263, 1231636301, 1047427035, + 2932959818, 3654703836, 1088359270, 936918000, + 2847714899, 3736837829, 1202900863, 817233897, + 3183342108, 3401237130, 1404277552, 615818150, + 3134207493, 3453421203, 1423857449, 601450431, + 3009837614, 3294710456, 1567103746, 711928724, + 3020668471, 3272380065, 1510334235, 755167117, + ] + end end - end diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index a57b8f644f..8e678c9111 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -196,16 +196,6 @@ describe "C-API Class function" do end end - describe "rb_define_method" do - it "defines a method taking variable arguments as a C array if the argument count is -1" do - @s.rb_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4] - end - - it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do - @s.rb_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4] - end - end - describe "rb_class2name" do it "returns the class name" do @s.rb_class2name(CApiClassSpecs).should == "CApiClassSpecs" diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb index 66c2dd40de..e18108c022 100644 --- a/spec/ruby/optional/capi/encoding_spec.rb +++ b/spec/ruby/optional/capi/encoding_spec.rb @@ -613,15 +613,15 @@ describe "C-API Encoding function" 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", + 1 => "\x01", + 0x80 => "\xC2\x80", + 0x800 => "\xE0\xA0\x80", + 0x10000 => "\xF0\x90\x80\x80", + 0x200000 => "\xF8\x88\x80\x80\x80", + 0x4000000 => "\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 + len = @s.rb_uv_to_utf8(str, num) + str.byteslice(0, len).should == result end end end diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c index b860742906..589025f677 100644 --- a/spec/ruby/optional/capi/ext/class_spec.c +++ b/spec/ruby/optional/capi/ext/class_spec.c @@ -142,19 +142,6 @@ static VALUE class_spec_include_module(VALUE self, VALUE klass, VALUE module) { return klass; } -static VALUE class_spec_method_var_args_1(int argc, VALUE *argv, VALUE self) { - VALUE ary = rb_ary_new(); - int i; - for (i = 0; i < argc; i++) { - rb_ary_push(ary, argv[i]); - } - return ary; -} - -static VALUE class_spec_method_var_args_2(VALUE self, VALUE argv) { - return argv; -} - void Init_class_spec(void) { VALUE cls = rb_define_class("CApiClassSpecs", rb_cObject); rb_define_method(cls, "define_call_super_method", class_spec_define_call_super_method, 2); @@ -185,8 +172,6 @@ void Init_class_spec(void) { rb_define_method(cls, "rb_define_class_id_under", class_spec_rb_define_class_id_under, 3); rb_define_method(cls, "rb_define_class_variable", class_spec_define_class_variable, 3); rb_define_method(cls, "rb_include_module", class_spec_include_module, 2); - rb_define_method(cls, "rb_method_varargs_1", class_spec_method_var_args_1, -1); - rb_define_method(cls, "rb_method_varargs_2", class_spec_method_var_args_2, -2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index cde4d0c351..68c4161bab 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -275,7 +275,9 @@ 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))); + int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)); + RB_ENC_CODERANGE_CLEAR(buf); + return INT2NUM(len); } static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) { diff --git a/spec/ruby/optional/capi/ext/module_spec.c b/spec/ruby/optional/capi/ext/module_spec.c index 7475994fa1..12bcf99983 100644 --- a/spec/ruby/optional/capi/ext/module_spec.c +++ b/spec/ruby/optional/capi/ext/module_spec.c @@ -9,18 +9,6 @@ static VALUE module_specs_test_method(VALUE self) { return ID2SYM(rb_intern("test_method")); } -static VALUE module_specs_test_method_2required(VALUE self, VALUE arg1, VALUE arg2) { - return ID2SYM(rb_intern("test_method_2required")); -} - -static VALUE module_specs_test_method_c_array(int argc, VALUE *argv, VALUE self) { - return ID2SYM(rb_intern("test_method_c_array")); -} - -static VALUE module_specs_test_method_ruby_array(VALUE self, VALUE args) { - return ID2SYM(rb_intern("test_method_ruby_array")); -} - static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) { return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse; } @@ -88,19 +76,25 @@ static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name return Qnil; } -static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE cls, VALUE str_name) { - rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_2required, 2); - return Qnil; +static VALUE module_specs_method_var_args_1(int argc, VALUE *argv, VALUE self) { + VALUE ary = rb_ary_new(); + int i; + for (i = 0; i < argc; i++) { + rb_ary_push(ary, argv[i]); + } + return ary; } -static VALUE module_specs_rb_define_method_c_array(VALUE self, VALUE cls, VALUE str_name) { - rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_c_array, -1); - return Qnil; +static VALUE module_specs_method_var_args_2(VALUE self, VALUE argv) { + return argv; } -static VALUE module_specs_rb_define_method_ruby_array(VALUE self, VALUE cls, VALUE str_name) { - rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_ruby_array, -2); - return Qnil; +static VALUE module_specs_rb_define_method_1required(VALUE self, VALUE arg1) { + return arg1; +} + +static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE arg1, VALUE arg2) { + return arg2; } static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) { @@ -155,25 +149,21 @@ void Init_module_spec(void) { rb_define_method(cls, "rb_define_module_under", module_specs_rb_define_module_under, 2); rb_define_method(cls, "rb_define_const", module_specs_define_const, 3); rb_define_method(cls, "rb_define_global_const", module_specs_define_global_const, 2); - rb_define_method(cls, "rb_define_global_function", - module_specs_rb_define_global_function, 1); + rb_define_method(cls, "rb_define_global_function", module_specs_rb_define_global_function, 1); rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2); + rb_define_method(cls, "rb_define_method_varargs_1", module_specs_method_var_args_1, -1); + rb_define_method(cls, "rb_define_method_varargs_2", module_specs_method_var_args_2, -2); + rb_define_method(cls, "rb_define_method_1required", module_specs_rb_define_method_1required, 1); rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2); - rb_define_method(cls, "rb_define_method_c_array", module_specs_rb_define_method_c_array, 2); - rb_define_method(cls, "rb_define_method_ruby_array", module_specs_rb_define_method_ruby_array, 2); - rb_define_method(cls, "rb_define_module_function", - module_specs_rb_define_module_function, 2); + rb_define_method(cls, "rb_define_module_function", module_specs_rb_define_module_function, 2); - rb_define_method(cls, "rb_define_private_method", - module_specs_rb_define_private_method, 2); + rb_define_method(cls, "rb_define_private_method", module_specs_rb_define_private_method, 2); - rb_define_method(cls, "rb_define_protected_method", - module_specs_rb_define_protected_method, 2); + rb_define_method(cls, "rb_define_protected_method", module_specs_rb_define_protected_method, 2); - rb_define_method(cls, "rb_define_singleton_method", - module_specs_rb_define_singleton_method, 2); + rb_define_method(cls, "rb_define_singleton_method", module_specs_rb_define_singleton_method, 2); rb_define_method(cls, "rb_undef_method", module_specs_rb_undef_method, 2); rb_define_method(cls, "rb_undef", module_specs_rb_undef, 2); diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c index 2670f24661..967b355c4a 100644 --- a/spec/ruby/optional/capi/ext/object_spec.c +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -301,6 +301,13 @@ static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) { return Qfalse; } +static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) { + if(rb_type_p(obj, T_FILE)) { + return Qtrue; + } + return Qfalse; +} + static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) { if(BUILTIN_TYPE(obj) == T_OBJECT) { return Qtrue; @@ -478,6 +485,7 @@ void Init_object_spec(void) { rb_define_method(cls, "rb_is_rb_type_p_module", so_is_rb_type_p_module, 1); rb_define_method(cls, "rb_is_rb_type_p_class", so_is_rb_type_p_class, 1); rb_define_method(cls, "rb_is_rb_type_p_data", so_is_rb_type_p_data, 1); + rb_define_method(cls, "rb_is_rb_type_p_file", so_is_rb_type_p_file, 1); rb_define_method(cls, "rb_is_builtin_type_object", so_is_builtin_type_object, 1); rb_define_method(cls, "rb_is_builtin_type_array", so_is_builtin_type_array, 1); rb_define_method(cls, "rb_is_builtin_type_module", so_is_builtin_type_module, 1); diff --git a/spec/ruby/optional/capi/ext/regexp_spec.c b/spec/ruby/optional/capi/ext/regexp_spec.c index 0a62616f33..9de7982b50 100644 --- a/spec/ruby/optional/capi/ext/regexp_spec.c +++ b/spec/ruby/optional/capi/ext/regexp_spec.c @@ -49,6 +49,12 @@ VALUE regexp_spec_match(VALUE self, VALUE regexp, VALUE str) { return rb_funcall(regexp, rb_intern("match"), 1, str); } +VALUE regexp_spec_memcicmp(VALUE self, VALUE str1, VALUE str2) { + long l1 = RSTRING_LEN(str1); + long l2 = RSTRING_LEN(str2); + return INT2FIX(rb_memcicmp(RSTRING_PTR(str1), RSTRING_PTR(str2), l1 < l2 ? l1 : l2)); +} + void Init_regexp_spec(void) { VALUE cls = rb_define_class("CApiRegexpSpecs", rb_cObject); rb_define_method(cls, "match", regexp_spec_match, 2); @@ -60,6 +66,7 @@ void Init_regexp_spec(void) { rb_define_method(cls, "rb_reg_match_backref_get", regexp_spec_reg_match_backref_get, 2); rb_define_method(cls, "rb_reg_options", regexp_spec_rb_reg_options, 1); rb_define_method(cls, "rb_reg_regcomp", regexp_spec_rb_reg_regcomp, 1); + rb_define_method(cls, "rb_memcicmp", regexp_spec_memcicmp, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb index acf4d1fe48..d7c0ab9c52 100644 --- a/spec/ruby/optional/capi/module_spec.rb +++ b/spec/ruby/optional/capi/module_spec.rb @@ -252,22 +252,30 @@ describe "CApiModule" do cls.new.method(:test_method).arity.should == 0 end - it "returns the correct arity when argc of the method in class is -1" do - cls = Class.new - @m.rb_define_method_c_array(cls, "test_method_c_array") - cls.new.method(:test_method_c_array).arity.should == -1 - end - - it "returns the correct arity when argc of the method in class is -2" do - cls = Class.new - @m.rb_define_method_ruby_array(cls, "test_method_ruby_array") - cls.new.method(:test_method_ruby_array).arity.should == -1 + it "returns the correct arity when argc of the method in class is 1" do + @m.rb_define_method_1required(42).should == 42 + @m.method(:rb_define_method_1required).arity.should == 1 end it "returns the correct arity when argc of the method in class is 2" do - cls = Class.new - @m.rb_define_method_2required(cls, "test_method_2required") - cls.new.method(:test_method_2required).arity.should == 2 + @m.rb_define_method_2required(1, 2).should == 2 + @m.method(:rb_define_method_2required).arity.should == 2 + end + + it "defines a method taking variable arguments as a C array if the argument count is -1" do + @m.rb_define_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4] + end + + it "returns the correct arity when argc of the method in class is -1" do + @m.method(:rb_define_method_varargs_1).arity.should == -1 + end + + it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do + @m.rb_define_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4] + end + + it "returns the correct arity when argc of the method in class is -2" do + @m.method(:rb_define_method_varargs_2).arity.should == -1 end it "defines a method on a module" do diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb index 294247910b..b0f8a1f891 100644 --- a/spec/ruby/optional/capi/object_spec.rb +++ b/spec/ruby/optional/capi/object_spec.rb @@ -30,6 +30,7 @@ describe "CApiObject" do class ObjectTest def initialize @foo = 7 + yield if block_given? end def foo @@ -88,6 +89,15 @@ describe "CApiObject" do o.initialized.should be_true o.arguments.should == [:one, :two] end + + it "passes the block to #initialize" do + v = nil + o = @o.rb_obj_alloc(ObjectTest) + @o.rb_obj_call_init(o, 0, []) do + v = :foo + end + v.should == :foo + end end describe "rb_is_instance_of" do @@ -513,6 +523,21 @@ describe "CApiObject" do @o.rb_is_type_class(ObjectTest).should == true @o.rb_is_type_data(Time.now).should == true end + + it "returns T_FILE for instances of IO and subclasses" do + STDERR.class.should == IO + @o.rb_is_rb_type_p_file(STDERR).should == true + + File.open(__FILE__) do |f| + f.class.should == File + @o.rb_is_rb_type_p_file(f).should == true + end + + require 'socket' + TCPServer.open(0) do |s| + @o.rb_is_rb_type_p_file(s).should == true + end + end end describe "rb_check_type" do diff --git a/spec/ruby/optional/capi/regexp_spec.rb b/spec/ruby/optional/capi/regexp_spec.rb index 81844e2a6e..af366e17a2 100644 --- a/spec/ruby/optional/capi/regexp_spec.rb +++ b/spec/ruby/optional/capi/regexp_spec.rb @@ -109,4 +109,20 @@ describe "C-API Regexp function" do thr.join end end + + describe "rb_memicmp" do + it "returns 0 for identical strings" do + @p.rb_memcicmp('Hello', 'Hello').should == 0 + end + + it "returns 0 for strings which only differ in case" do + @p.rb_memcicmp('Hello', 'HELLO').should == 0 + @p.rb_memcicmp('HELLO', 'Hello').should == 0 + end + + it "returns the difference between the first non matching characters" do + @p.rb_memcicmp('Hello', 'HELLP').should == -1 + @p.rb_memcicmp('HELLp', 'Hello').should == 1 + end + end end diff --git a/spec/ruby/spec_helper.rb b/spec/ruby/spec_helper.rb index c38965d3c5..f92d316c2a 100644 --- a/spec/ruby/spec_helper.rb +++ b/spec/ruby/spec_helper.rb @@ -14,8 +14,7 @@ else end end -# Running directly with ruby some_spec.rb -unless ENV['MSPEC_RUNNER'] +unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb mspec_lib = File.expand_path("../../mspec/lib", __FILE__) $LOAD_PATH << mspec_lib if File.directory?(mspec_lib) @@ -26,7 +25,13 @@ unless ENV['MSPEC_RUNNER'] puts "Please add -Ipath/to/mspec/lib or clone mspec as a sibling to run the specs." exit 1 end +end +ruby_version_is ""..."2.7" do + abort "This version of ruby/spec requires Ruby 2.7+" +end + +unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb ARGV.unshift $0 MSpecRun.main end