diff options
Diffstat (limited to 'spec/ruby/core/io/read_spec.rb')
-rw-r--r-- | spec/ruby/core/io/read_spec.rb | 180 |
1 files changed, 152 insertions, 28 deletions
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index 841e693f37..eb3652e692 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -23,6 +23,15 @@ describe "IO.read" do IO.read(p) end + # https://bugs.ruby-lang.org/issues/19354 + it "accepts options as keyword arguments" do + IO.read(@fname, 3, 0, mode: "r+").should == @contents[0, 3] + + -> { + IO.read(@fname, 3, 0, {mode: "r+"}) + }.should raise_error(ArgumentError, /wrong number of arguments/) + end + it "accepts an empty options Hash" do IO.read(@fname, **{}).should == @contents end @@ -55,6 +64,33 @@ describe "IO.read" do IO.read(@fname, mode: "a+").should == @contents end + platform_is_not :windows do + ruby_version_is ""..."3.3" do + it "uses an :open_args option" do + string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}]) + string.encoding.should == Encoding::US_ASCII + + string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}]) + string.encoding.should == Encoding::UTF_8 + end + end + end + + it "disregards other options if :open_args is given" do + string = IO.read(@fname,mode: "w", encoding: Encoding::UTF_32LE, open_args: ["r", encoding: Encoding::UTF_8]) + string.encoding.should == Encoding::UTF_8 + end + + it "doesn't require mode to be specified in :open_args" do + string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII}]) + string.encoding.should == Encoding::US_ASCII + end + + it "doesn't require mode to be specified in :open_args even if flags option passed" do + string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII, flags: File::CREAT}]) + string.encoding.should == Encoding::US_ASCII + end + it "treats second nil argument as no length limit" do IO.read(@fname, nil).should == @contents IO.read(@fname, nil, 5).should == IO.read(@fname, @contents.length, 5) @@ -77,6 +113,15 @@ describe "IO.read" do IO.read(@fname, 1, 10).should == nil end + it "returns an empty string when reading zero bytes" do + IO.read(@fname, 0).should == '' + end + + it "returns a String in BINARY when passed a size" do + IO.read(@fname, 1).encoding.should == Encoding::BINARY + IO.read(@fname, 0).encoding.should == Encoding::BINARY + end + it "raises an Errno::ENOENT when the requested file does not exist" do rm_r @fname -> { IO.read @fname }.should raise_error(Errno::ENOENT) @@ -90,9 +135,18 @@ describe "IO.read" do -> { IO.read @fname, -1 }.should raise_error(ArgumentError) end - it "raises an Errno::EINVAL when not passed a valid offset" do - -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) - -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) + ruby_version_is ''...'3.3' do + it "raises an Errno::EINVAL when not passed a valid offset" do + -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) + -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) + end + end + + ruby_version_is '3.3' do + it "raises an ArgumentError when not passed a valid offset" do + -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError) + -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError) + end end it "uses the external encoding specified via the :external_encoding option" do @@ -104,6 +158,14 @@ describe "IO.read" do str = IO.read(@fname, encoding: Encoding::ISO_8859_1) str.encoding.should == Encoding::ISO_8859_1 end + + platform_is :windows do + it "reads the file in text mode" do + # 0x1A is CTRL+Z and is EOF in Windows text mode. + File.binwrite(@fname, "\x1Abbb") + IO.read(@fname).should.empty? + end + end end describe "IO.read from a pipe" do @@ -112,12 +174,19 @@ describe "IO.read from a pipe" do platform_is :windows do cmd = "|cmd.exe /C echo hello" end - IO.read(cmd).should == "hello\n" + + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + IO.read(cmd).should == "hello\n" + end end platform_is_not :windows do it "opens a pipe to a fork if the rest is -" do - str = IO.read("|-") + str = nil + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + str = IO.read("|-") + end + if str # parent str.should == "hello from child\n" else #child @@ -132,13 +201,18 @@ describe "IO.read from a pipe" do platform_is :windows do cmd = "|cmd.exe /C echo hello" end - IO.read(cmd, 1).should == "h" + + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + IO.read(cmd, 1).should == "h" + end end platform_is_not :windows do it "raises Errno::ESPIPE if passed an offset" do -> { - IO.read("|sh -c 'echo hello'", 1, 1) + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + IO.read("|sh -c 'echo hello'", 1, 1) + end }.should raise_error(Errno::ESPIPE) end end @@ -149,11 +223,23 @@ quarantine! do # The process tried to write to a nonexistent pipe. # once https://bugs.ruby-lang.org/issues/12230 is fixed. it "raises Errno::EINVAL if passed an offset" do -> { - IO.read("|cmd.exe /C echo hello", 1, 1) + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + IO.read("|cmd.exe /C echo hello", 1, 1) + end }.should raise_error(Errno::EINVAL) end end end + + ruby_version_is "3.3" do + # https://bugs.ruby-lang.org/issues/19630 + it "warns about deprecation given a path with a pipe" do + cmd = "|echo ok" + -> { + IO.read(cmd) + }.should complain(/IO process creation with a leading '\|'/) + end + end end describe "IO.read on an empty file" do @@ -197,21 +283,55 @@ describe "IO#read" do @io.read(4).should == '7890' end + it "treats first nil argument as no length limit" do + @io.read(nil).should == @contents + end + + it "raises an ArgumentError when not passed a valid length" do + -> { @io.read(-1) }.should raise_error(ArgumentError) + end + it "clears the output buffer if there is nothing to read" do @io.pos = 10 - buf = 'non-empty string' + buf = +'non-empty string' @io.read(10, buf).should == nil buf.should == '' + + buf = +'non-empty string' + + @io.read(nil, buf).should == "" + + buf.should == '' + + buf = +'non-empty string' + + @io.read(0, buf).should == "" + + buf.should == '' + end + + it "raise FrozenError if the output buffer is frozen" do + @io.read + -> { @io.read(0, 'frozen-string'.freeze) }.should raise_error(FrozenError) + -> { @io.read(1, 'frozen-string'.freeze) }.should raise_error(FrozenError) + -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError) + end + + ruby_bug "", ""..."3.3" do + it "raise FrozenError if the output buffer is frozen (2)" do + @io.read + -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError) + end end it "consumes zero bytes when reading zero bytes" do @io.read(0).should == '' @io.pos.should == 0 - @io.getc.chr.should == '1' + @io.getc.should == '1' end it "is at end-of-file when everything has been read" do @@ -224,46 +344,53 @@ describe "IO#read" do end it "places the specified number of bytes in the buffer" do - buf = "" + buf = +"" @io.read 5, buf buf.should == "12345" end it "expands the buffer when too small" do - buf = "ABCDE" + buf = +"ABCDE" @io.read nil, buf buf.should == @contents end it "overwrites the buffer" do - buf = "ABCDEFGHIJ" + buf = +"ABCDEFGHIJ" @io.read nil, buf buf.should == @contents end it "truncates the buffer when too big" do - buf = "ABCDEFGHIJKLMNO" + buf = +"ABCDEFGHIJKLMNO" @io.read nil, buf buf.should == @contents @io.rewind - buf = "ABCDEFGHIJKLMNO" + buf = +"ABCDEFGHIJKLMNO" @io.read 5, buf buf.should == @contents[0..4] end it "returns the given buffer" do - buf = "" + buf = +"" @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" + buf = +"ABCDE" obj = mock("buff") obj.should_receive(:to_str).any_number_of_times.and_return(buf) @@ -304,6 +431,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 @@ -384,13 +514,6 @@ describe "IO#read in binary mode" do xE2 = [226].pack('C*') result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) end - - it "does not transcode file contents when an internal encoding is specified" do - result = File.open(@name, "r:binary:utf-8") { |f| f.read }.chomp - result.encoding.should == Encoding::BINARY - xE2 = [226].pack('C*') - result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) - end end describe "IO#read in text mode" do @@ -465,13 +588,13 @@ describe :io_read_internal_encoding, shared: true do describe "when passed nil for limit" do it "sets the buffer to a transcoded String" do - result = @io.read(nil, buf = "") + result = @io.read(nil, buf = +"") buf.should equal(result) buf.should == "ありがとう\n" end it "sets the buffer's encoding to the internal encoding" do - buf = "".force_encoding Encoding::ISO_8859_1 + buf = "".dup.force_encoding Encoding::ISO_8859_1 @io.read(nil, buf) buf.encoding.should equal(Encoding::UTF_8) end @@ -485,17 +608,18 @@ describe :io_read_size_internal_encoding, shared: true do it "returns a String in BINARY when passed a size" do @io.read(4).encoding.should equal(Encoding::BINARY) + @io.read(0).encoding.should equal(Encoding::BINARY) end it "does not change the buffer's encoding when passed a limit" do - buf = "".force_encoding Encoding::ISO_8859_1 + buf = "".dup.force_encoding Encoding::ISO_8859_1 @io.read(4, buf) buf.should == [164, 162, 164, 234].pack('C*').force_encoding(Encoding::ISO_8859_1) buf.encoding.should equal(Encoding::ISO_8859_1) end it "truncates the buffer but does not change the buffer's encoding when no data remains" do - buf = "abc".force_encoding Encoding::ISO_8859_1 + buf = "abc".dup.force_encoding Encoding::ISO_8859_1 @io.read @io.read(1, buf).should be_nil |