summaryrefslogtreecommitdiff
path: root/spec/ruby/core/io/read_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/io/read_spec.rb')
-rw-r--r--spec/ruby/core/io/read_spec.rb265
1 files changed, 188 insertions, 77 deletions
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 28cab13340..dd787c9b60 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(ArgumentError, /wrong number of arguments/)
+ end
+
it "accepts an empty options Hash" do
IO.read(@fname, **{}).should == @contents
end
@@ -36,11 +45,11 @@ describe "IO.read" do
end
it "raises an IOError if the options Hash specifies write mode" do
- -> { IO.read(@fname, 3, 0, mode: "w") }.should raise_error(IOError)
+ -> { IO.read(@fname, 3, 0, mode: "w") }.should.raise(IOError)
end
it "raises an IOError if the options Hash specifies append only mode" do
- -> { IO.read(@fname, mode: "a") }.should raise_error(IOError)
+ -> { IO.read(@fname, mode: "a") }.should.raise(IOError)
end
it "reads the file if the options Hash includes read mode" do
@@ -55,6 +64,24 @@ describe "IO.read" do
IO.read(@fname, mode: "a+").should == @contents
end
+ platform_is_not :windows do
+ 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,22 +104,31 @@ 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)
+ -> { IO.read @fname }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when not passed a String type" do
- -> { IO.read nil }.should raise_error(TypeError)
+ -> { IO.read nil }.should.raise(TypeError)
end
it "raises an ArgumentError when not passed a valid length" do
- -> { IO.read @fname, -1 }.should raise_error(ArgumentError)
+ -> { IO.read @fname, -1 }.should.raise(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)
+ it "raises an ArgumentError when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should.raise(ArgumentError)
+ -> { IO.read @fname, -1, -1 }.should.raise(ArgumentError)
end
it "uses the external encoding specified via the :external_encoding option" do
@@ -114,55 +150,79 @@ describe "IO.read" do
end
end
-describe "IO.read from a pipe" do
- it "runs the rest as a subprocess and returns the standard output" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
+ruby_version_is ""..."4.0" do
+ describe "IO.read from a pipe" do
+ it "runs the rest as a subprocess and returns the standard output" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
+ end
+
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd).should == "hello\n"
+ end
end
- IO.read(cmd).should == "hello\n"
- end
- platform_is_not :windows do
- it "opens a pipe to a fork if the rest is -" do
- str = IO.read("|-")
- if str # parent
- str.should == "hello from child\n"
- else #child
- puts "hello from child"
- exit!
+ platform_is_not :windows do
+ it "opens a pipe to a fork if the rest is -" do
+ 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
+ puts "hello from child"
+ exit!
+ end
end
end
- end
- it "reads only the specified number of bytes requested" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
+ it "reads only the specified number of bytes requested" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
+ end
+
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd, 1).should == "h"
+ end
end
- IO.read(cmd, 1).should == "h"
- end
- platform_is_not :windows do
- it "raises Errno::ESPIPE if passed an offset" do
- -> {
- IO.read("|sh -c 'echo hello'", 1, 1)
- }.should raise_error(Errno::ESPIPE)
+ platform_is_not :windows do
+ it "raises Errno::ESPIPE if passed an offset" do
+ -> {
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read("|sh -c 'echo hello'", 1, 1)
+ end
+ }.should.raise(Errno::ESPIPE)
+ end
end
- end
-quarantine! do # The process tried to write to a nonexistent pipe.
- platform_is :windows do
- # TODO: It should raise Errno::ESPIPE on Windows as well
- # once https://bugs.ruby-lang.org/issues/12230 is fixed.
- it "raises Errno::EINVAL if passed an offset" do
+ quarantine! do # The process tried to write to a nonexistent pipe.
+ platform_is :windows do
+ # TODO: It should raise Errno::ESPIPE on Windows as well
+ # once https://bugs.ruby-lang.org/issues/12230 is fixed.
+ it "raises Errno::EINVAL if passed an offset" do
+ -> {
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read("|cmd.exe /C echo hello", 1, 1)
+ end
+ }.should.raise(Errno::EINVAL)
+ end
+ end
+ end
+
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation" do
+ cmd = "|echo ok"
-> {
- IO.read("|cmd.exe /C echo hello", 1, 1)
- }.should raise_error(Errno::EINVAL)
+ IO.read(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
end
end
end
-end
describe "IO.read on an empty file" do
before :each do
@@ -205,21 +265,53 @@ 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(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(FrozenError)
+ -> { @io.read(1, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ -> { @io.read(nil, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ end
+
+ it "raise FrozenError if the output buffer is frozen (2)" do
+ @io.read
+ -> { @io.read(1, ''.freeze) }.should.raise(FrozenError)
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
@@ -232,50 +324,72 @@ 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 "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.read(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
+ # https://bugs.ruby-lang.org/issues/20416
+ it "does not preserve the encoding of the given buffer when max length is not provided" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.read(nil, buffer)
+
+ buffer.encoding.should_not == Encoding::ISO_8859_1
+ 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(nil, buf).should equal 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)
- @io.read(15, obj).should_not equal obj
+ @io.read(15, obj).should_not.equal? obj
buf.should == @contents
end
@@ -309,9 +423,12 @@ describe "IO#read" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.read }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.read }.should.raise(IOError)
end
+ it "raises ArgumentError when length is less than 0" do
+ -> { @io.read(-1) }.should.raise(ArgumentError)
+ end
platform_is_not :windows do
it "raises IOError when stream is closed by another thread" do
@@ -327,7 +444,7 @@ describe "IO#read" do
Thread.pass until t.stop?
r.close
t.join
- t.value.should be_kind_of(IOError)
+ t.value.should.is_a?(IOError)
w.close
end
end
@@ -392,13 +509,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
@@ -468,20 +578,20 @@ describe :io_read_internal_encoding, shared: true do
end
it "sets the String encoding to the internal encoding" do
- @io.read.encoding.should equal(Encoding::UTF_8)
+ @io.read.encoding.should.equal?(Encoding::UTF_8)
end
describe "when passed nil for limit" do
it "sets the buffer to a transcoded String" do
- result = @io.read(nil, buf = "")
- buf.should equal(result)
+ 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)
+ buf.encoding.should.equal?(Encoding::UTF_8)
end
end
end
@@ -492,23 +602,24 @@ describe :io_read_size_internal_encoding, shared: true do
end
it "returns a String in BINARY when passed a size" do
- @io.read(4).encoding.should equal(Encoding::BINARY)
+ @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)
+ 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
+ @io.read(1, buf).should == nil
buf.size.should == 0
- buf.encoding.should equal(Encoding::ISO_8859_1)
+ buf.encoding.should.equal?(Encoding::ISO_8859_1)
end
end
@@ -526,7 +637,7 @@ describe "IO#read" do
end
it "sets the String encoding to Encoding.default_external" do
- @io.read.encoding.should equal(Encoding.default_external)
+ @io.read.encoding.should.equal?(Encoding.default_external)
end
end
@@ -545,7 +656,7 @@ describe "IO#read" do
end
it "sets the String encoding to the external encoding" do
- @io.read.encoding.should equal(Encoding::EUC_JP)
+ @io.read.encoding.should.equal?(Encoding::EUC_JP)
end
it_behaves_like :io_read_size_internal_encoding, nil