diff options
author | Benoit Daloze <[email protected]> | 2022-09-28 18:37:17 +0200 |
---|---|---|
committer | Benoit Daloze <[email protected]> | 2022-09-28 18:37:17 +0200 |
commit | 31cf1bb5256314b69eae92673d3dd5815158ee91 (patch) | |
tree | 5ee049f751426794bfe47d0fa847f5621d3a039d | |
parent | 5a1ab740fc287df8bf4038f19bd28bbb73e181b6 (diff) |
Update to ruby/spec@1d9d5c6
51 files changed, 1142 insertions, 259 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 1200e9d7ce..3a16fc43f8 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -161,6 +161,9 @@ Lint/Debugger: Lint/Loop: Enabled: false +Style/BlockComments: + Enabled: true + Style/Lambda: Enabled: true EnforcedStyle: literal diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb index b6a146095d..350b08a30e 100644 --- a/spec/ruby/core/basicobject/instance_eval_spec.rb +++ b/spec/ruby/core/basicobject/instance_eval_spec.rb @@ -20,12 +20,18 @@ describe "BasicObject#instance_eval" do a.instance_eval('self').equal?(a).should be_true end - it "expects a block with no arguments" do - -> { "hola".instance_eval }.should raise_error(ArgumentError) + it "raises an ArgumentError when no arguments and no block are given" do + -> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)") end - it "takes no arguments with a block" do - -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError) + it "raises an ArgumentError when a block and normal arguments are given" do + -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") + end + + it "raises an ArgumentError when more than 3 arguments are given" do + -> { + "hola".instance_eval("1 + 1", "some file", 0, "bogus") + }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") end it "yields the object to the block" do @@ -185,4 +191,58 @@ end x.should == :value end + + it "converts string argument with #to_str method" do + source_code = Object.new + def source_code.to_str() "1" end + + a = BasicObject.new + a.instance_eval(source_code).should == 1 + end + + it "raises ArgumentError if returned value is not String" do + source_code = Object.new + def source_code.to_str() :symbol end + + a = BasicObject.new + -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/) + end + + it "converts filename argument with #to_str method" do + filename = Object.new + def filename.to_str() "file.rb" end + + err = begin + Object.new.instance_eval("raise", filename) + rescue => e + e + end + err.backtrace.first.split(":")[0].should == "file.rb" + end + + it "raises ArgumentError if returned value is not String" do + filename = Object.new + def filename.to_str() :symbol end + + -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/) + end + + it "converts lineno argument with #to_int method" do + lineno = Object.new + def lineno.to_int() 15 end + + err = begin + Object.new.instance_eval("raise", "file.rb", lineno) + rescue => e + e + end + err.backtrace.first.split(":")[1].should == "15" + end + + it "raises ArgumentError if returned value is not Integer" do + lineno = Object.new + def lineno.to_int() :symbol end + + -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/) + end end diff --git a/spec/ruby/core/enumerable/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb index 4a978794e5..fc173e4173 100644 --- a/spec/ruby/core/enumerable/sum_spec.rb +++ b/spec/ruby/core/enumerable/sum_spec.rb @@ -22,8 +22,21 @@ describe 'Enumerable#sum' do @enum.sum.should == 5/3r end - it 'takes a block to transform the elements' do - @enum.sum { |element| element * 2 }.should == 10/3r + context 'with a block' do + it 'transforms the elements' do + @enum.sum { |element| element * 2 }.should == 10/3r + end + + it 'does not destructure array elements' do + class << @enum + def each + yield [1,2] + yield [3] + end + end + + @enum.sum(&:last).should == 5 + end end # https://bugs.ruby-lang.org/issues/12217 diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb index b9f82f8133..07be99f400 100644 --- a/spec/ruby/core/io/gets_spec.rb +++ b/spec/ruby/core/io/gets_spec.rb @@ -213,6 +213,8 @@ describe "IO#gets" do it "returns empty string when 0 passed as a limit" do @io.gets(0).should == "" + @io.gets(nil, 0).should == "" + @io.gets("", 0).should == "" end end diff --git a/spec/ruby/core/io/print_spec.rb b/spec/ruby/core/io/print_spec.rb index 04e971ef6d..085852024c 100644 --- a/spec/ruby/core/io/print_spec.rb +++ b/spec/ruby/core/io/print_spec.rb @@ -3,16 +3,27 @@ require_relative 'fixtures/classes' describe "IO#print" do before :each do - @old_separator = $\ - suppress_warning {$\ = '->'} + @old_record_separator = $\ + @old_field_separator = $, + suppress_warning { + $\ = '->' + $, = '^^' + } @name = tmp("io_print") end after :each do - suppress_warning {$\ = @old_separator} + suppress_warning { + $\ = @old_record_separator + $, = @old_field_separator + } rm_r @name end + it "returns nil" do + touch(@name) { |f| f.print.should be_nil } + end + it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do o = mock('o') o.should_receive(:to_s).and_return("mockmockmock") @@ -38,13 +49,15 @@ describe "IO#print" do IO.read(@name).should == "hello#{$\}" end - it "writes each obj.to_s to the stream and appends $\\ (if any) given multiple objects" do + it "writes each obj.to_s to the stream separated by $, (if any) and appends $\\ (if any) given multiple objects" do o, o2 = Object.new, Object.new def o.to_s(); 'o'; end def o2.to_s(); 'o2'; end - touch(@name) { |f| f.print(o, o2) } - IO.read(@name).should == "#{o.to_s}#{o2.to_s}#{$\}" + suppress_warning { + touch(@name) { |f| f.print(o, o2) } + } + IO.read(@name).should == "#{o.to_s}#{$,}#{o2.to_s}#{$\}" end it "raises IOError on closed stream" do diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb index e50531d336..a62b75274c 100644 --- a/spec/ruby/core/io/read_nonblock_spec.rb +++ b/spec/ruby/core/io/read_nonblock_spec.rb @@ -55,6 +55,27 @@ describe "IO#read_nonblock" do @read.read_nonblock(4).should == "hell" end + it "reads after ungetc with data in the buffer" do + @write.write("foobar") + @read.set_encoding( + 'utf-8', universal_newline: false + ) + c = @read.getc + @read.ungetc(c) + @read.read_nonblock(3).should == "foo" + @read.read_nonblock(3).should == "bar" + end + + it "raises an exception after ungetc with data in the buffer and character conversion enabled" do + @write.write("foobar") + @read.set_encoding( + 'utf-8', universal_newline: true + ) + c = @read.getc + @read.ungetc(c) + -> { @read.read_nonblock(3).should == "foo" }.should raise_error(IOError) + end + it "returns less data if that is all that is available" do @write << "hello" @read.read_nonblock(10).should == "hello" @@ -70,6 +91,10 @@ describe "IO#read_nonblock" do @read.read_nonblock(1).should == "1" end + it "raises ArgumentError when length is less than 0" do + -> { @read.read_nonblock(-1) }.should raise_error(ArgumentError) + end + it "reads into the passed buffer" do buffer = "" @write.write("1") @@ -84,6 +109,21 @@ describe "IO#read_nonblock" do output.should equal(buffer) end + it "discards the existing buffer content upon successful read" do + buffer = "existing content" + @write.write("hello world") + @write.close + @read.read_nonblock(11, buffer) + buffer.should == "hello world" + end + + it "discards the existing buffer content upon error" do + buffer = "existing content" + @write.close + -> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError) + buffer.should be_empty + end + it "raises IOError on closed stream" do -> { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError) end @@ -96,4 +136,13 @@ describe "IO#read_nonblock" do -> { @read.read_nonblock(5) }.should raise_error(EOFError) end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @write.write("abc") + @write.close + @read.read_nonblock(10, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index 28cab13340..d34f7bd0eb 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -270,6 +270,13 @@ describe "IO#read" do @io.read(nil, buf).should equal buf end + it "returns the given buffer when there is nothing to read" do + buf = "" + + @io.read + @io.read(nil, buf).should equal buf + end + it "coerces the second argument to string and uses it as a buffer" do buf = "ABCDE" obj = mock("buff") @@ -312,6 +319,9 @@ describe "IO#read" do -> { IOSpecs.closed_io.read }.should raise_error(IOError) end + it "raises ArgumentError when length is less than 0" do + -> { @io.read(-1) }.should raise_error(ArgumentError) + end platform_is_not :windows do it "raises IOError when stream is closed by another thread" do diff --git a/spec/ruby/core/io/readchar_spec.rb b/spec/ruby/core/io/readchar_spec.rb index b5f762a846..a66773851a 100644 --- a/spec/ruby/core/io/readchar_spec.rb +++ b/spec/ruby/core/io/readchar_spec.rb @@ -1,6 +1,16 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +describe :io_readchar_internal_encoding, shared: true do + it "returns a transcoded String" do + @io.readchar.should == "あ" + end + + it "sets the String encoding to the internal encoding" do + @io.readchar.encoding.should equal(Encoding::UTF_8) + end +end + describe "IO#readchar" do before :each do @io = IOSpecs.io_fixture "lines.txt" @@ -29,6 +39,62 @@ describe "IO#readchar" do end end +describe "IO#readchar with internal encoding" do + after :each do + @io.close if @io + end + + describe "not specified" do + before :each do + @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp" + end + + it "does not transcode the String" do + @io.readchar.should == ("あ").encode(Encoding::EUC_JP) + end + + it "sets the String encoding to the external encoding" do + @io.readchar.encoding.should equal(Encoding::EUC_JP) + end + end + + describe "specified by open mode" do + before :each do + @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp:utf-8" + end + + it_behaves_like :io_readchar_internal_encoding, nil + end + + describe "specified by mode: option" do + before :each do + @io = IOSpecs.io_fixture "read_euc_jp.txt", mode: "r:euc-jp:utf-8" + end + + it_behaves_like :io_readchar_internal_encoding, nil + end + + describe "specified by internal_encoding: option" do + before :each do + options = { mode: "r", + internal_encoding: "utf-8", + external_encoding: "euc-jp" } + @io = IOSpecs.io_fixture "read_euc_jp.txt", options + end + + it_behaves_like :io_readchar_internal_encoding, nil + end + + describe "specified by encoding: option" do + before :each do + options = { mode: "r", encoding: "euc-jp:utf-8" } + @io = IOSpecs.io_fixture "read_euc_jp.txt", options + end + + it_behaves_like :io_readchar_internal_encoding, nil + end +end + describe "IO#readchar" do before :each do @io = IOSpecs.io_fixture "empty.txt" diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb index 2b33a0d5b1..324ae0b6e6 100644 --- a/spec/ruby/core/io/readpartial_spec.rb +++ b/spec/ruby/core/io/readpartial_spec.rb @@ -59,7 +59,7 @@ describe "IO#readpartial" do end it "discards the existing buffer content upon successful read" do - buffer = "existing" + buffer = "existing content" @wr.write("hello world") @wr.close @rd.readpartial(11, buffer) @@ -93,4 +93,17 @@ describe "IO#readpartial" do @rd.readpartial(0).should == "" end + it "clears and returns the given buffer if the length argument is 0" do + buffer = "existing content" + @rd.readpartial(0, buffer).should == buffer + buffer.should == "" + end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @wr.write("abc") + @wr.close + @rd.readpartial(10, buffer) + buffer.encoding.should == Encoding::ISO_8859_1 + end end diff --git a/spec/ruby/core/io/rewind_spec.rb b/spec/ruby/core/io/rewind_spec.rb index 649041afaf..5579cbd988 100644 --- a/spec/ruby/core/io/rewind_spec.rb +++ b/spec/ruby/core/io/rewind_spec.rb @@ -18,6 +18,17 @@ describe "IO#rewind" do @io.readline.should == "Voici la ligne une.\n" end + it "positions the instance to the beginning of output for write-only IO" do + name = tmp("io_rewind_spec") + io = File.open(name, "w") + io.write("Voici la ligne une.\n") + io.rewind + io.pos.should == 0 + ensure + io.close + rm_r name + end + it "positions the instance to the beginning of input and clears EOF" do value = @io.read @io.rewind @@ -32,6 +43,10 @@ describe "IO#rewind" do @io.lineno.should == 0 end + it "returns 0" do + @io.rewind.should == 0 + end + it "raises IOError on closed stream" do -> { IOSpecs.closed_io.rewind }.should raise_error(IOError) end diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb index b52d3a943a..92433d6640 100644 --- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb +++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb @@ -12,45 +12,232 @@ describe "IO#set_encoding_by_bom" do rm_r @name end + it "returns nil if not readable" do + not_readable_io = new_io(@name, 'wb') + + not_readable_io.set_encoding_by_bom.should be_nil + not_readable_io.external_encoding.should == Encoding::ASCII_8BIT + ensure + not_readable_io.close + end + it "returns the result encoding if found BOM UTF-8 sequence" do + File.binwrite(@name, "\u{FEFF}") + + @io.set_encoding_by_bom.should == Encoding::UTF_8 + @io.external_encoding.should == Encoding::UTF_8 + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + File.binwrite(@name, "\u{FEFF}abc") @io.set_encoding_by_bom.should == Encoding::UTF_8 @io.external_encoding.should == Encoding::UTF_8 + @io.read.b.should == "abc".b end it "returns the result encoding if found BOM UTF_16LE sequence" do + File.binwrite(@name, "\xFF\xFE") + + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + File.binwrite(@name, "\xFF\xFEabc") @io.set_encoding_by_bom.should == Encoding::UTF_16LE @io.external_encoding.should == Encoding::UTF_16LE + @io.read.b.should == "abc".b end it "returns the result encoding if found BOM UTF_16BE sequence" do + File.binwrite(@name, "\xFE\xFF") + + @io.set_encoding_by_bom.should == Encoding::UTF_16BE + @io.external_encoding.should == Encoding::UTF_16BE + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + File.binwrite(@name, "\xFE\xFFabc") @io.set_encoding_by_bom.should == Encoding::UTF_16BE @io.external_encoding.should == Encoding::UTF_16BE + @io.read.b.should == "abc".b end it "returns the result encoding if found BOM UTF_32LE sequence" do + File.binwrite(@name, "\xFF\xFE\x00\x00") + + @io.set_encoding_by_bom.should == Encoding::UTF_32LE + @io.external_encoding.should == Encoding::UTF_32LE + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + File.binwrite(@name, "\xFF\xFE\x00\x00abc") @io.set_encoding_by_bom.should == Encoding::UTF_32LE @io.external_encoding.should == Encoding::UTF_32LE + @io.read.b.should == "abc".b end it "returns the result encoding if found BOM UTF_32BE sequence" do + File.binwrite(@name, "\x00\x00\xFE\xFF") + + @io.set_encoding_by_bom.should == Encoding::UTF_32BE + @io.external_encoding.should == Encoding::UTF_32BE + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + File.binwrite(@name, "\x00\x00\xFE\xFFabc") @io.set_encoding_by_bom.should == Encoding::UTF_32BE @io.external_encoding.should == Encoding::UTF_32BE + @io.read.b.should == "abc".b + end + + it "returns nil if io is empty" do + @io.set_encoding_by_bom.should be_nil + @io.external_encoding.should == Encoding::ASCII_8BIT + end + + it "returns nil if UTF-8 BOM sequence is incomplete" do + File.write(@name, "\xEF") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xEF".b + @io.rewind + + File.write(@name, "\xEFa") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xEFa".b + @io.rewind + + File.write(@name, "\xEF\xBB") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xEF\xBB".b + @io.rewind + + File.write(@name, "\xEF\xBBa") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xEF\xBBa".b + end + + it "returns nil if UTF-16BE BOM sequence is incomplete" do + File.write(@name, "\xFE") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xFE".b + @io.rewind + + File.write(@name, "\xFEa") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xFEa".b + end + + it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do + File.write(@name, "\xFF") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xFF".b + @io.rewind + + File.write(@name, "\xFFa") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\xFFa".b + end + + it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do + File.write(@name, "\xFF\xFE") + + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + @io.read.b.should == "".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + + File.write(@name, "\xFF\xFE\x00") + + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + @io.read.b.should == "\x00".b + @io.rewind + @io.set_encoding(Encoding::ASCII_8BIT) + + File.write(@name, "\xFF\xFE\x00a") + + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + @io.read.b.should == "\x00a".b + end + + it "returns nil if UTF-32BE BOM sequence is incomplete" do + File.write(@name, "\x00") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00".b + @io.rewind + + File.write(@name, "\x00a") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00a".b + @io.rewind + + File.write(@name, "\x00\x00") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00\x00".b + @io.rewind + + File.write(@name, "\x00\x00a") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00\x00a".b + @io.rewind + + File.write(@name, "\x00\x00\xFE") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00\x00\xFE".b + @io.rewind + + File.write(@name, "\x00\x00\xFEa") + + @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read.b.should == "\x00\x00\xFEa".b end it "returns nil if found BOM sequence not provided" do File.write(@name, "abc") @io.set_encoding_by_bom.should == nil + @io.external_encoding.should == Encoding::ASCII_8BIT + @io.read(3).should == "abc".b end it 'returns exception if io not in binary mode' do diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb index 5aec6a96c3..bc448acfce 100644 --- a/spec/ruby/core/io/set_encoding_spec.rb +++ b/spec/ruby/core/io/set_encoding_spec.rb @@ -188,4 +188,21 @@ describe "IO#set_encoding" do @io.external_encoding.should == Encoding::UTF_8 @io.internal_encoding.should == Encoding::UTF_16BE end + + it "saves encoding options passed as a hash in the last argument" do + File.write(@name, "\xff") + io = File.open(@name) + io.set_encoding(Encoding::EUC_JP, Encoding::SHIFT_JIS, invalid: :replace, replace: ".") + io.read.should == "." + ensure + io.close + end + + it "raises ArgumentError when no arguments are given" do + -> { @io.set_encoding() }.should raise_error(ArgumentError) + end + + it "raises ArgumentError when too many arguments are given" do + -> { @io.set_encoding(1, 2, 3) }.should raise_error(ArgumentError) + end end diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb index 607e7de03e..1b8abce5ff 100644 --- a/spec/ruby/core/io/shared/each.rb +++ b/spec/ruby/core/io/shared/each.rb @@ -113,6 +113,13 @@ describe :io_each, shared: true do @io.send(@method, "") { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.paragraphs end + + it "discards leading newlines" do + @io.readline + @io.readline + @io.send(@method, "") { |s| ScratchPad << s } + ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1] + end end describe "with both separator and limit" do @@ -152,6 +159,13 @@ describe :io_each, shared: true do @io.send(@method, "", 1024) { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.paragraphs end + + it "discards leading newlines" do + @io.readline + @io.readline + @io.send(@method, "", 1024) { |s| ScratchPad << s } + ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1] + end end end end @@ -220,6 +234,14 @@ describe :io_each, shared: true do ] end end + + describe "when passed too many arguments" do + it "raises ArgumentError" do + -> { + @io.send(@method, "", 1, "excess argument", chomp: true) {} + }.should raise_error(ArgumentError) + end + end end describe :io_each_default_separator, shared: true do diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb index 270b84ac39..9503f94212 100644 --- a/spec/ruby/core/io/shared/write.rb +++ b/spec/ruby/core/io/shared/write.rb @@ -69,16 +69,6 @@ describe :io_write, shared: true do -> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError) end - it "does not modify the passed argument" do - File.open(@filename, "w") do |f| - f.set_encoding(Encoding::IBM437) - # A character whose codepoint differs between UTF-8 and IBM437 - f.write "ƒ".freeze - end - - File.binread(@filename).bytes.should == [159] - end - describe "on a pipe" do before :each do @r, @w = IO.pipe diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb index 8201ad47ca..e7f63cefec 100644 --- a/spec/ruby/core/io/sysread_spec.rb +++ b/spec/ruby/core/io/sysread_spec.rb @@ -6,7 +6,7 @@ describe "IO#sysread on a file" do @file_name = tmp("IO_sysread_file") + $$.to_s File.open(@file_name, "w") do |f| # write some stuff - f.write("012345678901234567890123456789") + f.write("012345678901234567890123456789\nabcdef") end @file = File.open(@file_name, "r+") end @@ -84,6 +84,29 @@ describe "IO#sysread on a file" do it "raises IOError on closed stream" do -> { IOSpecs.closed_io.sysread(5) }.should raise_error(IOError) end + + it "immediately returns an empty string if the length argument is 0" do + @file.sysread(0).should == "" + end + + it "immediately returns the given buffer if the length argument is 0" do + buffer = "existing content" + @file.sysread(0, buffer).should == buffer + buffer.should == "existing content" + end + + it "discards the existing buffer content upon successful read" do + buffer = "existing content" + @file.sysread(11, buffer) + buffer.should == "01234567890" + end + + it "discards the existing buffer content upon error" do + buffer = "existing content" + @file.seek(0, :END) + -> { @file.sysread(1, buffer) }.should raise_error(EOFError) + buffer.should be_empty + end end describe "IO#sysread" do @@ -100,4 +123,10 @@ describe "IO#sysread" do @write.syswrite "ab" @read.sysread(3).should == "ab" end + + guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do # https://bugs.ruby-lang.org/issues/18880 + it "raises ArgumentError when length is less than 0" do + -> { @read.sysread(-1) }.should raise_error(ArgumentError) + end + end end diff --git a/spec/ruby/core/io/syswrite_spec.rb b/spec/ruby/core/io/syswrite_spec.rb index a28cc62174..eeb8d302a7 100644 --- a/spec/ruby/core/io/syswrite_spec.rb +++ b/spec/ruby/core/io/syswrite_spec.rb @@ -29,6 +29,16 @@ describe "IO#syswrite on a file" do end end + it "does not modify the passed argument" do + File.open(@filename, "w") do |f| + f.set_encoding(Encoding::IBM437) + # A character whose codepoint differs between UTF-8 and IBM437 + f.syswrite("ƒ".freeze) + end + + File.binread(@filename).bytes.should == [198, 146] + end + it "warns if called immediately after a buffered IO#write" do @file.write("abcde") -> { @file.syswrite("fghij") }.should complain(/syswrite/) diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb index a8b9ce0a36..5532556d8a 100644 --- a/spec/ruby/core/io/write_nonblock_spec.rb +++ b/spec/ruby/core/io/write_nonblock_spec.rb @@ -31,6 +31,16 @@ platform_is_not :windows do end end + it "does not modify the passed argument" do + File.open(@filename, "w") do |f| + f.set_encoding(Encoding::IBM437) + # A character whose codepoint differs between UTF-8 and IBM437 + f.write_nonblock("ƒ".freeze) + end + + File.binread(@filename).bytes.should == [198, 146] + end + it "checks if the file is writable if writing zero bytes" do -> { @readonly_file.write_nonblock("") diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb index f29fdf3a01..bcc0582d9e 100644 --- a/spec/ruby/core/io/write_spec.rb +++ b/spec/ruby/core/io/write_spec.rb @@ -44,6 +44,16 @@ describe "IO#write on a file" do @file.write("hellø").should == 6 end + it "does not modify the passed argument" do + File.open(@filename, "w") do |f| + f.set_encoding(Encoding::IBM437) + # A character whose codepoint differs between UTF-8 and IBM437 + f.write("ƒ".freeze) + end + + File.binread(@filename).bytes.should == [159] + end + it "uses the encoding from the given option for non-ascii encoding" do File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file| file.write("hi").should == 8 diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb index 1bdd1740ca..eae191aa54 100644 --- a/spec/ruby/core/kernel/p_spec.rb +++ b/spec/ruby/core/kernel/p_spec.rb @@ -76,10 +76,8 @@ describe "Kernel#p" do -> { p(*[]) }.should output("") end -=begin Not sure how to spec this, but wanted to note the behavior here - it "does not flush if receiver is not a TTY or a File" do - end -=end + # Not sure how to spec this, but wanted to note the behavior here + it "does not flush if receiver is not a TTY or a File" end describe "Kernel.p" do diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb index be96f65e25..50daa773e1 100644 --- a/spec/ruby/core/method/fixtures/classes.rb +++ b/spec/ruby/core/method/fixtures/classes.rb @@ -213,4 +213,28 @@ module MethodSpecs n * m end end + + module InheritedMethods + module A + private + def derp(message) + 'A' + end + end + + module B + private + def derp + 'B' + super('superclass') + end + end + + class C + include A + include B + + public :derp + alias_method :meow, :derp + end + end end diff --git a/spec/ruby/core/method/super_method_spec.rb b/spec/ruby/core/method/super_method_spec.rb index e5d8b87a06..dc8764f6c7 100644 --- a/spec/ruby/core/method/super_method_spec.rb +++ b/spec/ruby/core/method/super_method_spec.rb @@ -42,4 +42,32 @@ describe "Method#super_method" do method.super_method.should == nil end + + # https://github.com/jruby/jruby/issues/7240 + context "after changing an inherited methods visibility" do + it "calls the proper super method" do + MethodSpecs::InheritedMethods::C.new.derp.should == 'BA' + end + + ruby_version_is ""..."3.2" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.new.method(:derp) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end + end + + ruby_version_is "3.2" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.new.method(:derp) + method.super_method.owner.should == MethodSpecs::InheritedMethods::B + end + end + end + + context "after aliasing an inherited method" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.new.method(:meow) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end + end end diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb index 75730395e8..0c15629c08 100644 --- a/spec/ruby/core/module/const_defined_spec.rb +++ b/spec/ruby/core/module/const_defined_spec.rb @@ -17,11 +17,16 @@ describe "Module#const_defined?" do ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true end - it "returns true if the constant is defined in a mixed-in module of the receiver" do + it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do # CS_CONST10 is defined in a module included by ChildA ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true end + it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do + # CS_CONST11 is defined in the module included by ContainerPrepend + ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true + end + it "returns true if the constant is defined in Object and the receiver is a module" do # CS_CONST1 is defined in Object ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb index c65b30de24..ce94436bfd 100644 --- a/spec/ruby/core/module/define_method_spec.rb +++ b/spec/ruby/core/module/define_method_spec.rb @@ -219,18 +219,55 @@ describe "Module#define_method" do o.block_test2.should == o end + it "raises TypeError if name cannot converted to String" do + -> { + Class.new { define_method(1001, -> {}) } + }.should raise_error(TypeError, /is not a symbol nor a string/) + + -> { + Class.new { define_method([], -> {}) } + }.should raise_error(TypeError, /is not a symbol nor a string/) + end + + it "converts non-String name to String with #to_str" do + obj = Object.new + def obj.to_str() "foo" end + + new_class = Class.new { define_method(obj, -> { :called }) } + new_class.new.foo.should == :called + end + + it "raises TypeError when #to_str called on non-String name returns non-String value" do + obj = Object.new + def obj.to_str() [] end + + -> { + Class.new { define_method(obj, -> {}) } + }.should raise_error(TypeError, /can't convert Object to String/) + end + it "raises a TypeError when the given method is no Method/Proc" do -> { Class.new { define_method(:test, "self") } - }.should raise_error(TypeError) + }.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)") -> { Class.new { define_method(:test, 1234) } - }.should raise_error(TypeError) + }.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)") -> { Class.new { define_method(:test, nil) } - }.should raise_error(TypeError) + }.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)") + end + + it "uses provided Method/Proc even if block is specified" do + new_class = Class.new do + define_method(:test, -> { :method_is_called }) do + :block_is_called + end + end + + new_class.new.test.should == :method_is_called end it "raises an ArgumentError when no block is given" do diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb index a64f672b2f..2b47ff112e 100644 --- a/spec/ruby/core/module/fixtures/classes.rb +++ b/spec/ruby/core/module/fixtures/classes.rb @@ -42,6 +42,14 @@ module ModuleSpecs class LookupChild < Lookup end + module ModuleWithPrepend + prepend LookupMod + end + + class WithPrependedModule + include ModuleWithPrepend + end + class Parent # For private_class_method spec def self.private_method; end diff --git a/spec/ruby/core/module/included_modules_spec.rb b/spec/ruby/core/module/included_modules_spec.rb index 40e20953f4..ce94ed1285 100644 --- a/spec/ruby/core/module/included_modules_spec.rb +++ b/spec/ruby/core/module/included_modules_spec.rb @@ -4,9 +4,11 @@ require_relative 'fixtures/classes' describe "Module#included_modules" do it "returns a list of modules included in self" do ModuleSpecs.included_modules.should == [] + ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel) ModuleSpecs::Parent.included_modules.should include(Kernel) ModuleSpecs::Basic.included_modules.should == [] ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic) + ModuleSpecs::WithPrependedModule.included_modules.should include(ModuleSpecs::ModuleWithPrepend) end end diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb index b4d6a0d8c8..30e27bb180 100644 --- a/spec/ruby/core/module/instance_method_spec.rb +++ b/spec/ruby/core/module/instance_method_spec.rb @@ -51,14 +51,36 @@ describe "Module#instance_method" do @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ end - it "raises a TypeError if not passed a symbol" do - -> { Object.instance_method([]) }.should raise_error(TypeError) - -> { Object.instance_method(0) }.should raise_error(TypeError) + it "raises a TypeError if the given name is not a String/Symbol" do + -> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/) + -> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/) + -> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/) + -> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/) end - it "raises a TypeError if the given name is not a string/symbol" do - -> { Object.instance_method(nil) }.should raise_error(TypeError) - -> { Object.instance_method(mock('x')) }.should raise_error(TypeError) + it "accepts String name argument" do + method = ModuleSpecs::InstanceMeth.instance_method(:foo) + method.should be_kind_of(UnboundMethod) + end + + it "accepts Symbol name argument" do + method = ModuleSpecs::InstanceMeth.instance_method("foo") + method.should be_kind_of(UnboundMethod) + end + + it "converts non-String name by calling #to_str method" do + obj = Object.new + def obj.to_str() "foo" end + + method = ModuleSpecs::InstanceMeth.instance_method(obj) + method.should be_kind_of(UnboundMethod) + end + + it "raises TypeError when passed non-String name and #to_str returns non-String value" do + obj = Object.new + def obj.to_str() [] end + + -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/) end it "raises a NameError if the method has been undefined" do diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb index 224078ae54..9ef7b5be44 100644 --- a/spec/ruby/core/module/shared/class_eval.rb +++ b/spec/ruby/core/module/shared/class_eval.rb @@ -55,40 +55,49 @@ describe :module_class_eval, shared: true do it "converts a non-string filename to a string using to_str" do (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__) ModuleSpecs.send(@method, "1+1", file) + + (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__) + ModuleSpecs.send(@method, "1+1", file, 15) end it "raises a TypeError when the given filename can't be converted to string using to_str" do (file = mock('123')).should_receive(:to_str).and_return(123) - -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError) + -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/) end it "converts non string eval-string to string using to_str" do (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") ModuleSpecs.send(@method, o).should == 2 + + (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") + ModuleSpecs.send(@method, o, "file.rb").should == 2 + + (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") + ModuleSpecs.send(@method, o, "file.rb", 15).should == 2 end it "raises a TypeError when the given eval-string can't be converted to string using to_str" do o = mock('x') - -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError) + -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String") (o = mock('123')).should_receive(:to_str).and_return(123) - -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError) + -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/) end it "raises an ArgumentError when no arguments and no block are given" do - -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError) + -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)") end it "raises an ArgumentError when more than 3 arguments are given" do -> { ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus") - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") end it "raises an ArgumentError when a block and normal arguments are given" do -> { ModuleSpecs.send(@method, "1 + 1") { 1 + 1 } - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)") end # This case was found because Rubinius was caching the compiled diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index b57f660816..0417486692 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -29,9 +29,35 @@ describe "String#split with String" do "1,2,,3,4,,".split(',').should == ["1", "2", "", "3", "4"] "1,2,,3,4,,".split(',', 0).should == ["1", "2", "", "3", "4"] " a b c\nd ".split(" ").should == ["", "a", "b", "c\nd"] + " a あ c\nd ".split(" ").should == ["", "a", "あ", "c\nd"] "hai".split("hai").should == [] ",".split(",").should == [] ",".split(",", 0).should == [] + "あ".split("あ").should == [] + "あ".split("あ", 0).should == [] + end + + it "does not suppress trailing empty fields when a positive limit is given" do + " 1 2 ".split(" ", 2).should == ["1", "2 "] + " 1 2 ".split(" ", 3).should == ["1", "2", ""] + " 1 2 ".split(" ", 4).should == ["1", "2", ""] + " 1 あ ".split(" ", 2).should == ["1", "あ "] + " 1 あ ".split(" ", 3).should == ["1", "あ", ""] + " 1 あ ".split(" ", 4).should == ["1", "あ", ""] + + "1,2,".split(',', 2).should == ["1", "2,"] + "1,2,".split(',', 3).should == ["1", "2", ""] + "1,2,".split(',', 4).should == ["1", "2", ""] + "1,あ,".split(',', 2).should == ["1", "あ,"] + "1,あ,".split(',', 3).should == ["1", "あ", ""] + "1,あ,".split(',', 4).should == ["1", "あ", ""] + + "1 2 ".split(/ /, 2).should == ["1", "2 "] + "1 2 ".split(/ /, 3).should == ["1", "2", ""] + "1 2 ".split(/ /, 4).should == ["1", "2", ""] + "1 あ ".split(/ /, 2).should == ["1", "あ "] + "1 あ ".split(/ /, 3).should == ["1", "あ", ""] + "1 あ ".split(/ /, 4).should == ["1", "あ", ""] end it "returns an array with one entry if limit is 1: the original string" do diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb index 4136f09348..e35e1fc0b4 100644 --- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb @@ -17,6 +17,15 @@ describe 'Thread::Backtrace::Location#absolute_path' do end end + it 'returns the correct absolute path when using a relative main script path and changing CWD' do + script = fixture(__FILE__, 'subdir/absolute_path_main_chdir.rb') + sibling = fixture(__FILE__, 'subdir/sibling.rb') + subdir = File.dirname script + Dir.chdir(fixture(__FILE__)) do + ruby_exe('subdir/absolute_path_main_chdir.rb').should == "subdir/absolute_path_main_chdir.rb\n#{subdir}\n#{subdir}\n#{script}\n#{sibling}\n" + end + end + context "when used in eval with a given filename" do code = "caller_locations(0)[0].absolute_path" diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb new file mode 100644 index 0000000000..33c8fb36ef --- /dev/null +++ b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb @@ -0,0 +1,11 @@ +puts __FILE__ +puts __dir__ +Dir.chdir __dir__ + +# Check __dir__ is still correct after chdir +puts __dir__ + +puts caller_locations(0)[0].absolute_path + +# require_relative also needs to know the absolute path of the current file so we test it here too +require_relative 'sibling' diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb new file mode 100644 index 0000000000..2a854ddccd --- /dev/null +++ b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb @@ -0,0 +1 @@ +puts __FILE__ diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb index 46b1c51669..1f466e39d8 100644 --- a/spec/ruby/core/unboundmethod/fixtures/classes.rb +++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb @@ -84,4 +84,14 @@ module UnboundMethodSpecs class C < B def overridden; end end + + module HashSpecs + class SuperClass + def foo + end + end + + class SubClass < SuperClass + end + end end diff --git a/spec/ruby/core/unboundmethod/hash_spec.rb b/spec/ruby/core/unboundmethod/hash_spec.rb index 12dce0020f..6888675bc1 100644 --- a/spec/ruby/core/unboundmethod/hash_spec.rb +++ b/spec/ruby/core/unboundmethod/hash_spec.rb @@ -12,4 +12,11 @@ describe "UnboundMethod#hash" do to_s, inspect = Array.instance_method(:to_s), Array.instance_method(:inspect) to_s.hash.should == inspect.hash end + + it "equals a hash of the same method in the superclass" do + foo_in_superclass = UnboundMethodSpecs::HashSpecs::SuperClass.instance_method(:foo) + foo = UnboundMethodSpecs::HashSpecs::SubClass.instance_method(:foo) + + foo.hash.should == foo_in_superclass.hash + end end diff --git a/spec/ruby/core/unboundmethod/super_method_spec.rb b/spec/ruby/core/unboundmethod/super_method_spec.rb index c9fa1ec533..5cf96e6fa9 100644 --- a/spec/ruby/core/unboundmethod/super_method_spec.rb +++ b/spec/ruby/core/unboundmethod/super_method_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative '../method/fixtures/classes' describe "UnboundMethod#super_method" do it "returns the method that would be called by super in the method" do @@ -25,4 +26,28 @@ describe "UnboundMethod#super_method" do method.super_method.should == nil end + + # https://github.com/jruby/jruby/issues/7240 + context "after changing an inherited methods visibility" do + ruby_version_is ""..."3.2" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.instance_method(:derp) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end + end + + ruby_version_is "3.2" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.instance_method(:derp) + method.super_method.owner.should == MethodSpecs::InheritedMethods::B + end + end + end + + context "after aliasing an inherited method" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.instance_method(:meow) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end + end end diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb index 4c456dae89..47a8e87e56 100644 --- a/spec/ruby/fixtures/constants.rb +++ b/spec/ruby/fixtures/constants.rb @@ -75,6 +75,13 @@ module ConstantSpecs CS_CONST10 = :const10_8 end + # Included in ContainerA + module ModuleIncludePrepended + prepend ModuleD + + CS_CONST11 = :const11_8 + end + # The following classes/modules have all the constants set "statically". # Contrast with the classes below where the constants are set as the specs # are run. @@ -169,6 +176,10 @@ module ConstantSpecs def const10; CS_CONST10; end end + class ContainerPrepend + include ModuleIncludePrepended + end + class ContainerA::ChildA def self.const23; CS_CONST23; end end diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb index 5a3c2861ce..c5adcca2c0 100644 --- a/spec/ruby/language/precedence_spec.rb +++ b/spec/ruby/language/precedence_spec.rb @@ -14,46 +14,44 @@ require_relative 'fixtures/precedence' # the level below (as well as showing associativity within # the precedence level). -=begin -Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide' -Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324 - -Table 22.4. Ruby operators (high to low precedence) -Method Operator Description ------------------------------------------------------------------------ - :: . - x* [ ] [ ]= Element reference, element set - x ** Exponentiation - x ! ~ + - Not, complement, unary plus and minus - (method names for the last two are +@ and -@) - x * / % Multiply, divide, and modulo - x + - Plus and minus - x >> << Right and left shift - x & “And” (bitwise for integers) - x ^ | Exclusive “or” and regular “or” (bitwise for integers) - x <= < > >= Comparison operators - x <=> == === != =~ !~ Equality and pattern match operators (!= - and !~ may not be defined as methods) - && Logical “and” - || Logical “or” - .. ... Range (inclusive and exclusive) - ? : Ternary if-then-else - = %= /= -= += |= &= Assignment - >>= <<= *= &&= ||= **= - defined? Check if symbol defined - not Logical negation - or and Logical composition - if unless while until Expression modifiers - begin/end Block expression ------------------------------------------------------------------------ - -* Operators marked with 'x' in the Method column are implemented as methods -and can be overridden (except != and !~ as noted). (But see the specs -below for implementations that define != and !~ as methods.) - -** These are not included in the excerpted table but are shown here for -completeness. -=end +# Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide' +# Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324 +# +# Table 22.4. Ruby operators (high to low precedence) +# Method Operator Description +# ----------------------------------------------------------------------- +# :: . +# x* [ ] [ ]= Element reference, element set +# x ** Exponentiation +# x ! ~ + - Not, complement, unary plus and minus +# (method names for the last two are +@ and -@) +# x * / % Multiply, divide, and modulo +# x + - Plus and minus +# x >> << Right and left shift +# x & “And” (bitwise for integers) +# x ^ | Exclusive “or” and regular “or” (bitwise for integers) +# x <= < > >= Comparison operators +# x <=> == === != =~ !~ Equality and pattern match operators (!= +# and !~ may not be defined as methods) +# && Logical “and” +# || Logical “or” +# .. ... Range (inclusive and exclusive) +# ? : Ternary if-then-else +# = %= /= -= += |= &= Assignment +# >>= <<= *= &&= ||= **= +# defined? Check if symbol defined +# not Logical negation +# or and Logical composition +# if unless while until Expression modifiers +# begin/end Block expression +# ----------------------------------------------------------------------- +# +# * Operators marked with 'x' in the Method column are implemented as methods +# and can be overridden (except != and !~ as noted). (But see the specs +# below for implementations that define != and !~ as methods.) +# +# ** These are not included in the excerpted table but are shown here for +# completeness. # ----------------------------------------------------------------------- # It seems that this table is not correct anymore diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index 87385a29e5..d1cda25918 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -7,37 +7,33 @@ require 'stringio' # Entries marked [r/o] are read-only and an error will be raised of the program attempts to # modify them. Entries marked [thread] are thread local. -=begin -Exception Information ---------------------------------------------------------------------------------------------------- - -$! Exception The exception object passed to raise. [thread] -$@ Array The stack backtrace generated by the last exception. [thread] -=end - -=begin -Pattern Matching Variables ---------------------------------------------------------------------------------------------------- - -These variables are set to nil after an unsuccessful pattern match. - -$& String The string matched (following a successful pattern match). This variable is - local to the current scope. [r/o, thread] -$+ String The contents of the highest-numbered group matched following a successful - pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This - variable is local to the current scope. [r/o, thread] -$` String The string preceding the match in a successful pattern match. This variable - is local to the current scope. [r/o, thread] -$' String The string following the match in a successful pattern match. This variable - is local to the current scope. [r/o, thread] -$1 to $<N> String The contents of successive groups matched in a successful pattern match. In - "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable - is local to the current scope. [r/o, thread] -$~ MatchData An object that encapsulates the results of a successful pattern match. The - variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~ - changes the values of these derived variables. This variable is local to the - current scope. [thread] -=end +# Exception Information +# --------------------------------------------------------------------------------------------------- +# +# $! Exception The exception object passed to raise. [thread] +# $@ Array The stack backtrace generated by the last exception. [thread] + +# Pattern Matching Variables +# --------------------------------------------------------------------------------------------------- +# +# These variables are set to nil after an unsuccessful pattern match. +# +# $& String The string matched (following a successful pattern match). This variable is +# local to the current scope. [r/o, thread] +# $+ String The contents of the highest-numbered group matched following a successful +# pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This +# variable is local to the current scope. [r/o, thread] +# $` String The string preceding the match in a successful pattern match. This variable +# is local to the current scope. [r/o, thread] +# $' String The string following the match in a successful pattern match. This variable +# is local to the current scope. [r/o, thread] +# $1 to $<N> String The contents of successive groups matched in a successful pattern match. In +# "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable +# is local to the current scope. [r/o, thread] +# $~ MatchData An object that encapsulates the results of a successful pattern match. The +# variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~ +# changes the values of these derived variables. This variable is local to the +# current scope. [thread] describe "Predefined global $~" do @@ -506,41 +502,39 @@ describe "Predefined global $!" do end end -=begin -Input/Output Variables ---------------------------------------------------------------------------------------------------- - -$/ String The input record separator (newline by default). This is the value that rou- - tines such as Kernel#gets use to determine record boundaries. If set to - nil, gets will read the entire file. -$-0 String Synonym for $/. -$\ String The string appended to the output of every call to methods such as - Kernel#print and IO#write. The default value is nil. -$, String The separator string output between the parameters to methods such as - Kernel#print and Array#join. Defaults to nil, which adds no text. -$. Integer The number of the last line read from the current input file. -$; String The default separator pattern used by String#split. May be set from the - command line using the -F flag. -$< Object An object that provides access to the concatenation of the contents of all - the files given as command-line arguments or $stdin (in the case where - there are no arguments). $< supports methods similar to a File object: - binmode, close, closed?, each, each_byte, each_line, eof, eof?, - file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=, - read, readchar, readline, readlines, rewind, seek, skip, tell, to_a, - to_i, to_io, to_s, along with the methods in Enumerable. The method - file returns a File object for the file currently being read. This may change - as $< reads through the files on the command line. [r/o] -$> IO The destination of output for Kernel#print and Kernel#printf. The - default value is $stdout. -$_ String The last line read by Kernel#gets or Kernel#readline. Many string- - related functions in the Kernel module operate on $_ by default. The vari- - able is local to the current scope. [thread] -$-F String Synonym for $;. -$stderr IO The current standard error output. -$stdin IO The current standard input. -$stdout IO The current standard output. Assignment to $stdout is deprecated: use - $stdout.reopen instead. -=end +# Input/Output Variables +# --------------------------------------------------------------------------------------------------- +# +# $/ String The input record separator (newline by default). This is the value that rou- +# tines such as Kernel#gets use to determine record boundaries. If set to +# nil, gets will read the entire file. +# $-0 String Synonym for $/. +# $\ String The string appended to the output of every call to methods such as +# Kernel#print and IO#write. The default value is nil. +# $, String The separator string output between the parameters to methods such as +# Kernel#print and Array#join. Defaults to nil, which adds no text. +# $. Integer The number of the last line read from the current input file. +# $; String The default separator pattern used by String#split. May be set from the +# command line using the -F flag. +# $< Object An object that provides access to the concatenation of the contents of all +# the files given as command-line arguments or $stdin (in the case where +# there are no arguments). $< supports methods similar to a File object: +# binmode, close, closed?, each, each_byte, each_line, eof, eof?, +# file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=, +# read, readchar, readline, readlines, rewind, seek, skip, tell, to_a, +# to_i, to_io, to_s, along with the methods in Enumerable. The method +# file returns a File object for the file currently being read. This may change +# as $< reads through the files on the command line. [r/o] +# $> IO The destination of output for Kernel#print and Kernel#printf. The +# default value is $stdout. +# $_ String The last line read by Kernel#gets or Kernel#readline. Many string- +# related functions in the Kernel module operate on $_ by default. The vari- +# able is local to the current scope. [thread] +# $-F String Synonym for $;. +# $stderr IO The current standard error output. +# $stdin IO The current standard input. +# $stdout IO The current standard output. Assignment to $stdout is deprecated: use +# $stdout.reopen instead. describe "Predefined global $/" do before :each do @@ -803,54 +797,52 @@ describe "Predefined global $_" do end end -=begin -Execution Environment Variables ---------------------------------------------------------------------------------------------------- - -$0 String The name of the top-level Ruby program being executed. Typically this will - be the program’s filename. On some operating systems, assigning to this - variable will change the name of the process reported (for example) by the - ps(1) command. -$* Array An array of strings containing the command-line options from the invoca- - tion of the program. Options used by the Ruby interpreter will have been - removed. [r/o] -$" Array An array containing the filenames of modules loaded by require. [r/o] -$$ Integer The process number of the program being executed. [r/o] -$? Process::Status The exit status of the last child process to terminate. [r/o, thread] -$: Array An array of strings, where each string specifies a directory to be searched for - Ruby scripts and binary extensions used by the load and require methods. - The initial value is the value of the arguments passed via the -I command- - line option, followed by an installation-defined standard library location, fol- - lowed by the current directory (“.”). This variable may be set from within a - program to alter the default search path; typically, programs use $: << dir - to append dir to the path. [r/o] -$-a Object True if the -a option is specified on the command line. [r/o] -$-d Object Synonym for $DEBUG. -$DEBUG Object Set to true if the -d command-line option is specified. -__FILE__ String The name of the current source file. [r/o] -$F Array The array that receives the split input line if the -a command-line option is - used. -$FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o] -$-i String If in-place edit mode is enabled (perhaps using the -i command-line - option), $-i holds the extension used when creating the backup file. If you - set a value into $-i, enables in-place edit mode. -$-I Array Synonym for $:. [r/o] -$-K String Sets the multibyte coding system for strings and regular expressions. Equiv- - alent to the -K command-line option. -$-l Object Set to true if the -l option (which enables line-end processing) is present - on the command line. [r/o] -__LINE__ String The current line number in the source file. [r/o] -$LOAD_PATH Array A synonym for $:. [r/o] -$-p Object Set to true if the -p option (which puts an implicit while gets . . . end - loop around your program) is present on the command line. [r/o] -$VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com- - mand line. Set to false if no option, or -W1 is given. Set to nil if -W0 - was specified. Setting this option to true causes the interpreter and some - library routines to report additional information. Setting to nil suppresses - all warnings (including the output of Kernel.warn). -$-v Object Synonym for $VERBOSE. -$-w Object Synonym for $VERBOSE. -=end +# Execution Environment Variables +# --------------------------------------------------------------------------------------------------- +# +# $0 String The name of the top-level Ruby program being executed. Typically this will +# be the program’s filename. On some operating systems, assigning to this +# variable will change the name of the process reported (for example) by the +# ps(1) command. +# $* Array An array of strings containing the command-line options from the invoca- +# tion of the program. Options used by the Ruby interpreter will have been +# removed. [r/o] +# $" Array An array containing the filenames of modules loaded by require. [r/o] +# $$ Integer The process number of the program being executed. [r/o] +# $? Process::Status The exit status of the last child process to terminate. [r/o, thread] +# $: Array An array of strings, where each string specifies a directory to be searched for +# Ruby scripts and binary extensions used by the load and require methods. +# The initial value is the value of the arguments passed via the -I command- +# line option, followed by an installation-defined standard library location, fol- +# lowed by the current directory (“.”). This variable may be set from within a +# program to alter the default search path; typically, programs use $: << dir +# to append dir to the path. [r/o] +# $-a Object True if the -a option is specified on the command line. [r/o] +# $-d Object Synonym for $DEBUG. +# $DEBUG Object Set to true if the -d command-line option is specified. +# __FILE__ String The name of the current source file. [r/o] +# $F Array The array that receives the split input line if the -a command-line option is +# used. +# $FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o] +# $-i String If in-place edit mode is enabled (perhaps using the -i command-line +# option), $-i holds the extension used when creating the backup file. If you +# set a value into $-i, enables in-place edit mode. +# $-I Array Synonym for $:. [r/o] +# $-K String Sets the multibyte coding system for strings and regular expressions. Equiv- +# alent to the -K command-line option. +# $-l Object Set to true if the -l option (which enables line-end processing) is present +# on the command line. [r/o] +# __LINE__ String The current line number in the source file. [r/o] +# $LOAD_PATH Array A synonym for $:. [r/o] +# $-p Object Set to true if the -p option (which puts an implicit while gets . . . end +# loop around your program) is present on the command line. [r/o] +# $VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com- +# mand line. Set to false if no option, or -W1 is given. Set to nil if -W0 +# was specified. Setting this option to true causes the interpreter and some +# library routines to report additional information. Setting to nil suppresses +# all warnings (including the output of Kernel.warn). +# $-v Object Synonym for $VERBOSE. +# $-w Object Synonym for $VERBOSE. describe "Execution variable $:" do it "is initialized to an array of strings" do $:.is_a?(Array).should == true @@ -1068,22 +1060,20 @@ describe "Global variable $0" do end end -=begin -Standard Objects ---------------------------------------------------------------------------------------------------- - -ARGF Object A synonym for $<. -ARGV Array A synonym for $*. -ENV Object A hash-like object containing the program’s environment variables. An - instance of class Object, ENV implements the full set of Hash methods. Used - to query and set the value of an environment variable, as in ENV["PATH"] - and ENV["term"]="ansi". -false FalseClass Singleton instance of class FalseClass. [r/o] -nil NilClass The singleton instance of class NilClass. The value of uninitialized - instance and global variables. [r/o] -self Object The receiver (object) of the current method. [r/o] -true TrueClass Singleton instance of class TrueClass. [r/o] -=end +# Standard Objects +# --------------------------------------------------------------------------------------------------- +# +# ARGF Object A synonym for $<. +# ARGV Array A synonym for $*. +# ENV Object A hash-like object containing the program’s environment variables. An +# instance of class Object, ENV implements the full set of Hash methods. Used +# to query and set the value of an environment variable, as in ENV["PATH"] +# and ENV["term"]="ansi". +# false FalseClass Singleton instance of class FalseClass. [r/o] +# nil NilClass The singleton instance of class NilClass. The value of uninitialized +# instance and global variables. [r/o] +# self Object The receiver (object) of the current method. [r/o] +# true TrueClass Singleton instance of class TrueClass. [r/o] describe "The predefined standard objects" do it "includes ARGF" do @@ -1136,36 +1126,34 @@ describe "The self pseudo-variable" do end end -=begin -Global Constants ---------------------------------------------------------------------------------------------------- - -The following constants are defined by the Ruby interpreter. - -DATA IO If the main program file contains the directive __END__, then - the constant DATA will be initialized so that reading from it will - return lines following __END__ from the source file. -FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3). -NIL NilClass Synonym for nil (deprecated, removed in Ruby 3). -RUBY_PLATFORM String The identifier of the platform running this program. This string - is in the same form as the platform identifier used by the GNU - configure utility (which is not a coincidence). -RUBY_RELEASE_DATE String The date of this release. -RUBY_VERSION String The version number of the interpreter. -STDERR IO The actual standard error stream for the program. The initial - value of $stderr. -STDIN IO The actual standard input stream for the program. The initial - value of $stdin. -STDOUT IO The actual standard output stream for the program. The initial - value of $stdout. -SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash, - Ruby will store an entry containing the contents of each file it - parses, with the file’s name as the key and an array of strings as - the value. -TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level— - the level where programs are initially executed. -TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3). -=end +# Global Constants +# --------------------------------------------------------------------------------------------------- +# +# The following constants are defined by the Ruby interpreter. +# +# DATA IO If the main program file contains the directive __END__, then +# the constant DATA will be initialized so that reading from it will +# return lines following __END__ from the source file. +# FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3). +# NIL NilClass Synonym for nil (deprecated, removed in Ruby 3). +# RUBY_PLATFORM String The identifier of the platform running this program. This string +# is in the same form as the platform identifier used by the GNU +# configure utility (which is not a coincidence). +# RUBY_RELEASE_DATE String The date of this release. +# RUBY_VERSION String The version number of the interpreter. +# STDERR IO The actual standard error stream for the program. The initial +# value of $stderr. +# STDIN IO The actual standard input stream for the program. The initial +# value of $stdin. +# STDOUT IO The actual standard output stream for the program. The initial +# value of $stdout. +# SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash, +# Ruby will store an entry containing the contents of each file it +# parses, with the file’s name as the key and an array of strings as +# the value. +# TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level— +# the level where programs are initially executed. +# TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3). describe "The predefined global constants" do describe "TRUE" do diff --git a/spec/ruby/library/bigdecimal/exponent_spec.rb b/spec/ruby/library/bigdecimal/exponent_spec.rb index f63c4e5798..8877147955 100644 --- a/spec/ruby/library/bigdecimal/exponent_spec.rb +++ b/spec/ruby/library/bigdecimal/exponent_spec.rb @@ -18,17 +18,6 @@ describe "BigDecimal#exponent" do BigDecimal("1234567E10").exponent.should == 17 end -# commenting this spec out after discussion with Defiler, since it seems to be an MRI bug, not a real feature -=begin - platform_is wordsize: 32 do - # TODO: write specs for both 32 and 64 bit - it "returns 0 if exponent can't be represented as Integer" do - BigDecimal("2E1000000000000000").exponent.should == 0 - BigDecimal("-5E-999999999999999").exponent.should == 0 - end - end -=end - it "returns 0 if self is 0" do BigDecimal("0").exponent.should == 0 BigDecimal("+0").exponent.should == 0 diff --git a/spec/ruby/library/fiddle/handle/initialize_spec.rb b/spec/ruby/library/fiddle/handle/initialize_spec.rb new file mode 100644 index 0000000000..51c2470efd --- /dev/null +++ b/spec/ruby/library/fiddle/handle/initialize_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' +require 'fiddle' + +describe "Fiddle::Handle#initialize" do + it "raises Fiddle::DLError if the library cannot be found" do + -> { + Fiddle::Handle.new("doesnotexist.doesnotexist") + }.should raise_error(Fiddle::DLError) + end +end diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb new file mode 100644 index 0000000000..48e0b4ef7d --- /dev/null +++ b/spec/ruby/library/io-wait/wait_readable_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' + +require 'io/wait' + +describe "IO#wait_readable" do + before :each do + @io = File.new(__FILE__ ) + end + + after :each do + @io.close + end + + it "waits for the IO to become readable with no timeout" do + @io.wait_readable.should == @io + end + + it "waits for the IO to become readable with the given timeout" do + @io.wait_readable(1).should == @io + end + + it "waits for the IO to become readable with the given large timeout" do + @io.wait_readable(365 * 24 * 60 * 60).should == @io + end +end diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb new file mode 100644 index 0000000000..5900a0c566 --- /dev/null +++ b/spec/ruby/library/io-wait/wait_writable_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../spec_helper' + +require 'io/wait' + +describe "IO#wait_writable" do + it "waits for the IO to become writable with no timeout" do + STDOUT.wait_writable.should == STDOUT + end + + it "waits for the IO to become writable with the given timeout" do + STDOUT.wait_writable(1).should == STDOUT + end + + it "waits for the IO to become writable with the given large timeout" do + # Represents one year and is larger than a 32-bit int + STDOUT.wait_writable(365 * 24 * 60 * 60).should == STDOUT + end +end diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index 00250439fd..83b204b575 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -91,7 +91,7 @@ describe "Addrinfo#initialize" do @addrinfo.afamily.should == Socket::AF_INET6 end - it "returns the 0 socket type" do + it "returns the specified socket type" do @addrinfo.socktype.should == Socket::SOCK_STREAM end diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb index 2df09027c9..ca823742cb 100644 --- a/spec/ruby/library/socket/shared/pack_sockaddr.rb +++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb @@ -19,6 +19,11 @@ describe :socket_pack_sockaddr_in, shared: true do Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1'] end + it 'resolves the service name to a port' do + sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1') + Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1'] + end + describe 'using an IPv4 address' do it 'returns a String of 16 bytes' do str = Socket.public_send(@method, 80, '127.0.0.1') diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index 8e678c9111..abeba0f741 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -204,6 +204,10 @@ describe "C-API Class function" do it "returns a string for an anonymous class" do @s.rb_class2name(Class.new).should be_kind_of(String) end + + it "returns a string beginning with # for an anonymous class" do + @s.rb_class2name(Struct.new(:x, :y).new(1, 2).class).should.start_with?('#') + end end describe "rb_class_path" do diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index 46af8696a5..e194ba8fde 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -112,6 +112,10 @@ VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) { return rb_eval_string(RSTRING_PTR(str)); } +VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) { + return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat)); +} + VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) { rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before"))); if (self != Qundef) @@ -361,6 +365,7 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_frame_this_func_test_again", kernel_spec_rb_frame_this_func, 0); rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4); rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1); + rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3); rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1); rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1); rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2); diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c index 967b355c4a..30ac44cf1f 100644 --- a/spec/ruby/optional/capi/ext/object_spec.c +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -393,6 +393,18 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg) return rb_class_inherited_p(mod, arg); } +static int foreach_f(ID key, VALUE val, VALUE ary) { + rb_ary_push(ary, ID2SYM(key)); + rb_ary_push(ary, val); + return ST_CONTINUE; +} + +static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) { + VALUE ary = rb_ary_new(); + rb_ivar_foreach(obj, foreach_f, ary); + return ary; +} + static VALUE speced_allocator(VALUE klass) { VALUE flags = 0; VALUE instance; @@ -508,6 +520,7 @@ void Init_object_spec(void) { rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1); rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1); rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1); + rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/fixtures/object.rb b/spec/ruby/optional/capi/fixtures/object.rb new file mode 100644 index 0000000000..a59f2309d8 --- /dev/null +++ b/spec/ruby/optional/capi/fixtures/object.rb @@ -0,0 +1,29 @@ +class CApiObjectSpecs + class IVars + def initialize + @a = 3 + @b = 7 + @c = 4 + end + + def self.set_class_variables + @@foo = :a + @@bar = :b + @@baz = :c + end + end + + module MVars + @@mvar = :foo + @@mvar2 = :bar + + @ivar = :baz + end + + module CVars + @@cvar = :foo + @@cvar2 = :bar + + @ivar = :baz + end +end diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index d1e3e03582..54d8d8a8d3 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -504,6 +504,25 @@ describe "C-API Kernel function" do end end + describe "rb_eval_cmd_kw" do + it "evaluates a string of ruby code" do + @s.rb_eval_cmd_kw("1+1", [], 0).should == 2 + end + + it "calls a proc with the supplied arguments" do + @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8] + end + + it "calls a proc with keyword arguments if kw_splat is non zero" do + a_proc = -> *x, **y { + res = x.map { |i| i + 1 } + y.each { |k, v| res << k; res << v } + res + } + @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3] + end + end + describe "rb_block_proc" do it "converts the implicit block into a proc" do proc = @s.rb_block_proc { 1+1 } diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb index b0f8a1f891..25a43d8908 100644 --- a/spec/ruby/optional/capi/object_spec.rb +++ b/spec/ruby/optional/capi/object_spec.rb @@ -1,4 +1,5 @@ require_relative 'spec_helper' +require_relative 'fixtures/object' load_extension("object") @@ -983,5 +984,24 @@ describe "CApiObject" do @o.speced_allocator?(parent).should == true end end + + describe "rb_ivar_foreach" do + it "calls the callback function for each instance variable on an object" do + o = CApiObjectSpecs::IVars.new + ary = @o.rb_ivar_foreach(o) + ary.should == [:@a, 3, :@b, 7, :@c, 4] + end + + it "calls the callback function for each cvar and ivar on a class" do + ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars) + ary.should == [:__classpath__, 'CApiObjectSpecs::CVars', :@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz] + end + + it "calls the callback function for each cvar and ivar on a module" do + ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars) + ary.should == [:__classpath__, 'CApiObjectSpecs::MVars', :@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz] + end + + end end end diff --git a/spec/ruby/optional/capi/shared/rbasic.rb b/spec/ruby/optional/capi/shared/rbasic.rb index 105408ec3d..99c2044bd7 100644 --- a/spec/ruby/optional/capi/shared/rbasic.rb +++ b/spec/ruby/optional/capi/shared/rbasic.rb @@ -8,9 +8,16 @@ describe :rbasic, shared: true do it "reports the appropriate FREEZE flag for the object when reading" do obj, _ = @data.call - (@specs.get_flags(obj) & @freeze).should == 0 + initial = @specs.get_flags(obj) obj.freeze - (@specs.get_flags(obj) & @freeze).should == @freeze + @specs.get_flags(obj).should == @freeze | initial + end + + it "supports setting the FREEZE flag" do + obj, _ = @data.call + initial = @specs.get_flags(obj) + @specs.set_flags(obj, @freeze | initial).should == @freeze | initial + obj.should.frozen? end it "supports retrieving the (meta)class" do diff --git a/spec/ruby/spec_helper.rb b/spec/ruby/spec_helper.rb index f92d316c2a..3404521c03 100644 --- a/spec/ruby/spec_helper.rb +++ b/spec/ruby/spec_helper.rb @@ -27,7 +27,8 @@ unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb end end -ruby_version_is ""..."2.7" do +# Compare with SpecVersion directly here so it works even with --unguarded +if VersionGuard::FULL_RUBY_VERSION < SpecVersion.new('2.7') abort "This version of ruby/spec requires Ruby 2.7+" end |