diff --git a/core/io/binmode_spec.rb b/core/io/binmode_spec.rb index 8117229c9..cc31fa381 100644 --- a/core/io/binmode_spec.rb +++ b/core/io/binmode_spec.rb @@ -31,6 +31,19 @@ @io.binmode @io.internal_encoding.should == nil end + + it "disables newline conversion for reading" do + data = "line1\r\nline2\r\n" + + @io = new_io(@name, "wb") + @io.write(data) + @io.close + + @io = new_io(@name, "rt") + @io.set_encoding("utf-8:ISO-8859-1", newline: :universal) + @io.binmode + @io.read.should == data + end end describe "IO#binmode?" do diff --git a/core/io/getbyte_spec.rb b/core/io/getbyte_spec.rb index 668d81519..246633e0e 100644 --- a/core/io/getbyte_spec.rb +++ b/core/io/getbyte_spec.rb @@ -25,6 +25,22 @@ it "raises an IOError on closed stream" do -> { IOSpecs.closed_io.getbyte }.should.raise(IOError) end + + it "reads after ungetc without character conversion" do + @io.set_encoding("utf-8") + c = @io.getc + @io.ungetc(c) + @io.getbyte.should == 86 + end + + it "raises an exception after ungetc with character conversion" do + @io.set_encoding("utf-8:utf-16be") + c = @io.getc + @io.ungetc(c) + -> do + @io.getbyte + end.should.raise(IOError, "byte oriented read for character buffered IO") + end end describe "IO#getbyte" do diff --git a/core/io/internal_encoding_spec.rb b/core/io/internal_encoding_spec.rb index 9963a93f3..c0bd86785 100644 --- a/core/io/internal_encoding_spec.rb +++ b/core/io/internal_encoding_spec.rb @@ -93,6 +93,27 @@ @io = new_io @name, "#{@object}:binary" @io.internal_encoding.should == nil end + + it "returns nil when the external encoding is BINARY and internal encoding is set" do + @io = new_io @name, "#{@object}:binary:ibm437" + @io.internal_encoding.should == nil + end + + ruby_version_is ""..."3.3" do + it "returns the value set by #set_encoding when the external encoding is BINARY" do + @io = new_io @name, @object + @io.set_encoding(Encoding::BINARY, Encoding::IBM437) + @io.internal_encoding.should.equal?(Encoding::IBM437) + end + end + + ruby_version_is "3.3" do + it "ignores the value set by #set_encoding when the external encoding is BINARY and returns nil" do + @io = new_io @name, @object + @io.set_encoding(Encoding::BINARY, Encoding::IBM437) + @io.internal_encoding.should == nil + end + end end end diff --git a/core/io/pwrite_spec.rb b/core/io/pwrite_spec.rb index c318d551b..1fbbbd6ed 100644 --- a/core/io/pwrite_spec.rb +++ b/core/io/pwrite_spec.rb @@ -59,6 +59,14 @@ }.should.raise(NoMethodError, /undefined method [`']to_s'/) end + platform_is_not :windows do + it "raises a Errno::EINVAL if the offset is invalid" do + -> { + @file.pwrite("foo", -1) + }.should.raise(Errno::EINVAL) + end + end + it "raises a TypeError if the offset cannot be converted to an Integer" do -> { @file.pwrite("foo", Object.new) diff --git a/core/io/read_nonblock_spec.rb b/core/io/read_nonblock_spec.rb index 511cf0326..c63289dc5 100644 --- a/core/io/read_nonblock_spec.rb +++ b/core/io/read_nonblock_spec.rb @@ -66,14 +66,16 @@ @read.read_nonblock(3).should == "bar" end - it "raises an exception after ungetc with data in the buffer and character conversion enabled" do + it "raises an exception after ungetc with 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(IOError) + -> do + @read.read_nonblock(3) + end.should.raise(IOError, "byte oriented read for character buffered IO") end it "returns less data if that is all that is available" do @@ -137,6 +139,14 @@ -> { @read.read_nonblock(5) }.should.raise(EOFError) end + ruby_bug "#18421", ""..."3.0.4" do + it "clears and returns the given buffer if the length argument is 0" do + buffer = String.new("existing content") + @read.read_nonblock(0, buffer).should == buffer + buffer.should == "" + end + end + it "preserves the encoding of the given buffer" do buffer = ''.encode(Encoding::ISO_8859_1) @write.write("abc") diff --git a/core/io/read_spec.rb b/core/io/read_spec.rb index 0c165814c..6d146c1ff 100644 --- a/core/io/read_spec.rb +++ b/core/io/read_spec.rb @@ -672,6 +672,12 @@ @io.read.encoding.should.equal?(Encoding::EUC_JP) end + it "reads after ungetc" do + c = @io.getc + @io.ungetc(c) + @io.read(2).should == [164, 162].pack('C*').force_encoding(Encoding::BINARY) + end + it_behaves_like :io_read_size_internal_encoding, nil end @@ -680,6 +686,14 @@ @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp:utf-8" end + it "raises an exception after ungetc" do + c = @io.getc + @io.ungetc(c) + -> do + @io.read(2) + end.should.raise(IOError, "byte oriented read for character buffered IO") + end + it_behaves_like :io_read_internal_encoding, nil it_behaves_like :io_read_size_internal_encoding, nil end @@ -689,6 +703,14 @@ @io = IOSpecs.io_fixture "read_euc_jp.txt", mode: "r:euc-jp:utf-8" end + it "raises an exception after ungetc" do + c = @io.getc + @io.ungetc(c) + -> do + @io.read(2) + end.should.raise(IOError, "byte oriented read for character buffered IO") + end + it_behaves_like :io_read_internal_encoding, nil it_behaves_like :io_read_size_internal_encoding, nil end @@ -701,6 +723,14 @@ @io = IOSpecs.io_fixture "read_euc_jp.txt", options end + it "raises an exception after ungetc" do + c = @io.getc + @io.ungetc(c) + -> do + @io.read(2) + end.should.raise(IOError, "byte oriented read for character buffered IO") + end + it_behaves_like :io_read_internal_encoding, nil it_behaves_like :io_read_size_internal_encoding, nil end @@ -711,6 +741,14 @@ @io = IOSpecs.io_fixture "read_euc_jp.txt", options end + it "raises an exception after ungetc" do + c = @io.getc + @io.ungetc(c) + -> do + @io.read(2) + end.should.raise(IOError, "byte oriented read for character buffered IO") + end + it_behaves_like :io_read_internal_encoding, nil it_behaves_like :io_read_size_internal_encoding, nil end diff --git a/core/io/readbyte_spec.rb b/core/io/readbyte_spec.rb index 07da1da91..5a425b994 100644 --- a/core/io/readbyte_spec.rb +++ b/core/io/readbyte_spec.rb @@ -21,4 +21,20 @@ @io.readbyte end.should.raise EOFError end + + it "reads after ungetc without character conversion" do + @io.set_encoding("utf-8") + c = @io.getc + @io.ungetc(c) + @io.readbyte.should == ?r.getbyte(0) + end + + it "raises an exception after ungetc with character conversion" do + @io.set_encoding("utf-8:utf-16be") + c = @io.getc + @io.ungetc(c) + -> do + @io.readbyte + end.should.raise(IOError, "byte oriented read for character buffered IO") + end end diff --git a/core/io/readpartial_spec.rb b/core/io/readpartial_spec.rb index d3f5545c8..b96e10be4 100644 --- a/core/io/readpartial_spec.rb +++ b/core/io/readpartial_spec.rb @@ -58,6 +58,16 @@ @rd.readpartial(2).should == "b" end + it "raises an exception after ungetc with character conversion enabled" do + @wr.write("foobar") + @rd.set_encoding('utf-8', 'ascii') + c = @rd.getc + @rd.ungetc(c) + -> do + @rd.readpartial(3) + end.should.raise(IOError, "byte oriented read for character buffered IO") + end + it "discards the existing buffer content upon successful read" do buffer = +"existing content" @wr.write("hello world") diff --git a/core/io/reopen_spec.rb b/core/io/reopen_spec.rb index 3b972d897..8d2e3b30c 100644 --- a/core/io/reopen_spec.rb +++ b/core/io/reopen_spec.rb @@ -57,6 +57,10 @@ @io.close -> { @io.reopen(STDOUT) }.should.raise(IOError) end + + it "raises ArgumentError when too many arguments are given" do + -> { @io.reopen(@other_name, "r", "excess argument") }.should.raise(ArgumentError) + end end describe "IO#reopen with a String" do @@ -170,6 +174,53 @@ @io.reopen(@other_name) File.should.exist?(@other_name) end + + it "opens the file in read mode if the IO is read-only" do + touch(@name) { |f| f.write "original data" } + touch(@other_name) { |f| f.write "new data" } + @io = new_io @name, "r" + + @io.reopen(@other_name) + -> { @io.write("overwrite content") }.should.raise(IOError) + @io.read.should == "new data" + end + + it "opens the file in write mode if the IO is write-only" do + touch(@name) { |f| f.write "original data" } + touch(@other_name) { |f| f.write "new data" } + @io = new_io @name, "w" + + @io.reopen(@other_name) + -> { @io.read }.should.raise(IOError) + @io.write("overwrite content").should == 17 + @io.close + File.read(@other_name).should == "overwrite content" + end + + it "opens the file in read-write mode if the IO is read-write" do + touch(@name) { |f| f.write "original data" } + touch(@other_name) { |f| f.write "new data" } + @io = new_io @name, "r+" + + @io.reopen(@other_name) + @io.read.should == "new data" + @io.rewind + @io.write("overwrite content").should == 17 + @io.close + File.read(@other_name).should == "overwrite content" + end + + it "opens the file in append mode if the IO appends" do + touch(@name) { |f| f.write "original data" } + touch(@other_name) { |f| f.write "new data" } + @io = new_io @name, "a" + + @io.reopen(@other_name) + -> { @io.read }.should.raise(IOError) + @io.write("overwrite content").should == 17 + @io.close + File.read(@other_name).should == "new dataoverwrite content" + end end describe "IO#reopen with a String" do diff --git a/core/io/seek_spec.rb b/core/io/seek_spec.rb index d6e553bae..9d42e3a5c 100644 --- a/core/io/seek_spec.rb +++ b/core/io/seek_spec.rb @@ -77,6 +77,19 @@ value[-1].should == @io.read[0] end + ruby_bug "#20919", "" ... "3.4" do + it "clears the character buffer" do + @io.ungetc("a") + @io.seek(1, IO::SEEK_SET) + @io.getc.should == "o" + + @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16LE) + @io.ungetc("a".encode(Encoding::UTF_16LE)) + @io.seek(1, IO::SEEK_SET) + @io.getc.should == "o".encode(Encoding::UTF_16LE) + end + end + platform_is :darwin do it "supports seek offsets greater than 2^32" do begin diff --git a/core/io/set_encoding_spec.rb b/core/io/set_encoding_spec.rb index 237251de5..3e89eb306 100644 --- a/core/io/set_encoding_spec.rb +++ b/core/io/set_encoding_spec.rb @@ -1,5 +1,94 @@ require_relative '../../spec_helper' +describe :io_set_encoding_common, shared: true do + describe "when Encoding.default_external is not binary and Encoding.default_internal is not nil" do + it "sets the encodings to the current Encoding defaults" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ISO_8859_1 + Encoding.default_internal = Encoding::ISO_8859_2 + + @io.set_encoding nil, nil + + @io.external_encoding.should.equal?(Encoding::ISO_8859_1) + @io.internal_encoding.should.equal?(Encoding::ISO_8859_2) + end + + it "prevents the encodings from changing when Encoding defaults are changed" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ISO_8859_1 + Encoding.default_internal = Encoding::ISO_8859_2 + + @io.set_encoding nil, nil + + Encoding.default_external = Encoding::IBM437 + Encoding.default_internal = Encoding::IBM866 + + @io.external_encoding.should.equal?(Encoding::ISO_8859_1) + @io.internal_encoding.should.equal?(Encoding::ISO_8859_2) + end + end +end + +describe :io_set_encoding_readonly, shared: true do + describe "when Encoding.default_external is binary" do + it "prevents the #internal_encoding from changing when Encoding.default_internal is changed" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ASCII_8BIT + Encoding.default_internal = Encoding::ISO_8859_2 + + @io.set_encoding nil, nil + + Encoding.default_internal = Encoding::IBM437 + + @io.internal_encoding.should == nil + end + + it "allows the #external_encoding to change when Encoding.default_external is changed" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ASCII_8BIT + Encoding.default_internal = Encoding::ISO_8859_2 + + @io.set_encoding nil, nil + + Encoding.default_external = Encoding::IBM437 + + @io.external_encoding.should.equal?(Encoding::IBM437) + end + end + + describe "when Encoding.default_internal is nil" do + it "prevents the #internal_encoding from changing when Encoding.default_internal is changed" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ISO_8859_1 + Encoding.default_internal = nil + + @io.set_encoding nil, nil + + Encoding.default_internal = Encoding::IBM437 + + @io.internal_encoding.should == nil + end + + it "allows the #external_encoding to change when Encoding.default_external is changed" do + @io = new_io @name, "#{@object}" + + Encoding.default_external = Encoding::ISO_8859_1 + Encoding.default_internal = nil + + @io.set_encoding nil, nil + + Encoding.default_external = Encoding::IBM437 + + @io.external_encoding.should.equal?(Encoding::IBM437) + end + end +end + describe :io_set_encoding_write, shared: true do it "sets the encodings to nil when they were set previously" do @io = new_io @name, "#{@object}:ibm437:ibm866" @@ -26,23 +115,28 @@ @io = new_io @name, "#{@object}:utf-8:us-ascii" @io.set_encoding nil, nil - Encoding.default_external = Encoding::IBM437 - Encoding.default_internal = Encoding::IBM866 + Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = nil + + @io.set_encoding nil, nil @io.external_encoding.should == nil @io.internal_encoding.should == nil end - it "sets the encodings to the current Encoding defaults" do - @io = new_io @name, @object + it "prevents the encodings from changing when Encoding defaults are changed" do + @io = new_io @name, "#{@object}:utf-8:us-ascii" - Encoding.default_external = Encoding::IBM437 - Encoding.default_internal = Encoding::IBM866 + Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = nil @io.set_encoding nil, nil - @io.external_encoding.should == Encoding::IBM437 - @io.internal_encoding.should == Encoding::IBM866 + Encoding.default_external = Encoding::IBM437 + Encoding.default_internal = Encoding::IBM866 + + @io.external_encoding.should == nil + @io.internal_encoding.should == nil end end @@ -68,63 +162,44 @@ end describe "with 'r' mode" do - it "sets the encodings to the current Encoding defaults" do - @io = new_io @name, "r" + it_behaves_like :io_set_encoding_common, nil, "r" - Encoding.default_external = Encoding::IBM437 - Encoding.default_internal = Encoding::IBM866 - - @io.set_encoding nil, nil - @io.external_encoding.should.equal?(Encoding::IBM437) - @io.internal_encoding.should.equal?(Encoding::IBM866) - end - - it "prevents the #internal_encoding from changing when Encoding.default_internal is changed" do - @io = new_io @name, "r" - @io.set_encoding nil, nil - - Encoding.default_internal = Encoding::IBM437 - - @io.internal_encoding.should == nil - end - - it "allows the #external_encoding to change when Encoding.default_external is changed" do - @io = new_io @name, "r" - @io.set_encoding nil, nil - - Encoding.default_external = Encoding::IBM437 - - @io.external_encoding.should.equal?(Encoding::IBM437) - end + it_behaves_like :io_set_encoding_readonly, nil, "r" end describe "with 'rb' mode" do - it "returns Encoding.default_external" do - @io = new_io @name, "rb" - @io.external_encoding.should.equal?(Encoding::BINARY) + it_behaves_like :io_set_encoding_common, nil, "rb" - @io.set_encoding nil, nil - @io.external_encoding.should.equal?(Encoding.default_external) - end + it_behaves_like :io_set_encoding_readonly, nil, "rb" end describe "with 'r+' mode" do + it_behaves_like :io_set_encoding_common, nil, "r+" + it_behaves_like :io_set_encoding_write, nil, "r+" end describe "with 'w' mode" do + it_behaves_like :io_set_encoding_common, nil, "w" + it_behaves_like :io_set_encoding_write, nil, "w" end describe "with 'w+' mode" do + it_behaves_like :io_set_encoding_common, nil, "w+" + it_behaves_like :io_set_encoding_write, nil, "w+" end describe "with 'a' mode" do + it_behaves_like :io_set_encoding_common, nil, "a" + it_behaves_like :io_set_encoding_write, nil, "a" end describe "with 'a+' mode" do + it_behaves_like :io_set_encoding_common, nil, "a+" + it_behaves_like :io_set_encoding_write, nil, "a+" end @@ -203,6 +278,17 @@ @io.internal_encoding.should == Encoding::UTF_16BE end + it "sets the internal encoding to nil when passed '-' as the second argument" do + default_internal = Encoding.default_internal + Encoding.default_internal = Encoding::UTF_16BE + + @io.set_encoding("utf-8", "-") + @io.external_encoding.should == Encoding::UTF_8 + @io.internal_encoding.should == nil + ensure + Encoding.default_internal = default_internal + end + it "calls #to_str to convert an abject to a String" do obj = mock("io_set_encoding") obj.should_receive(:to_str).and_return("utf-8:utf-16be") @@ -235,4 +321,114 @@ it "raises ArgumentError when too many arguments are given" do -> { @io.set_encoding(1, 2, 3) }.should.raise(ArgumentError) end + + it "raises ArgumentError when argument is not ASCII compatible" do + -> { @io.set_encoding("utf-8".encode(Encoding::UTF_16BE)) }.should.raise(ArgumentError) + end + + it "raises TypeError when the first argument is nil and the second is not nil" do + -> { @io.set_encoding(nil, Encoding::UTF_8) }.should.raise(TypeError) + end + + it "raises ArgumentError when newline decorator has invalid value" do + -> { + @io.set_encoding("utf-8", newline: :invalid) + }.should.raise(ArgumentError, "unexpected value for newline option: invalid") + -> { + @io.set_encoding("utf-8", newline: "invalid") + }.should.raise(ArgumentError, "unexpected value for newline option") + end + + it "raises ArgumentError when ASCII incompatible encoding is used with readable stream without binmode or character conversion" do + default_external = Encoding.default_external + + io = new_io @name, "r" + + -> { + io.set_encoding(Encoding::UTF_16BE) + }.should.raise(ArgumentError, "ASCII incompatible encoding needs binmode") + + Encoding.default_external = Encoding::UTF_16BE + + -> { + io.set_encoding(nil) + }.should.raise(ArgumentError, "ASCII incompatible encoding needs binmode") + ensure + io.close + Encoding.default_external = default_external + end + + it "sets the external encoding when ASCII incompatible encoding is used with binmode" do + io = new_io @name, "r" + io.binmode + + io.set_encoding(Encoding::UTF_16BE) + io.external_encoding.should == Encoding::UTF_16BE + + default_external = Encoding.default_external + Encoding.default_external = Encoding::UTF_16BE + + io.set_encoding(nil) + io.external_encoding.should == Encoding::UTF_16BE + ensure + io.close + Encoding.default_external = default_external + end + + it "sets the external and internal encodings when ASCII incompatible encoding is used with character conversion" do + io = new_io @name, "r" + + io.set_encoding(Encoding::UTF_16BE, Encoding::UTF_16LE) + io.external_encoding.should == Encoding::UTF_16BE + io.internal_encoding.should == Encoding::UTF_16LE + ensure + io.close + end + + it "sets the external encoding when ASCII incompatible encoding is used with a write-only stream" do + default_external = Encoding.default_external + + @io.set_encoding(Encoding::UTF_16BE) + @io.external_encoding.should == Encoding::UTF_16BE + + Encoding.default_external = Encoding::UTF_16BE + + @io.set_encoding(nil) + @io.external_encoding.should == nil + ensure + Encoding.default_external = default_external + end + + ruby_version_is "3.2" do + it "raises ArgumentError when newline decorator provided in binary mode" do + @io.binmode + -> { + @io.set_encoding("utf-8", newline: :lf) + }.should.raise(ArgumentError, "newline decorator with binary mode") + end + end + + ruby_version_is "" ... "3.3" do + it "sets the internal encoding to nil when the second argument is nil" do + @io.set_encoding(Encoding::UTF_8, nil) + @io.internal_encoding.should == nil + end + end + + ruby_version_is "3.3" do + it "sets the internal encoding to Encoding.default_internal when the second argument is nil" do + default_internal = Encoding.default_internal + Encoding.default_internal = Encoding::UTF_16BE + + @io.set_encoding(Encoding::UTF_8, nil) + @io.internal_encoding.should == Encoding::UTF_16BE + ensure + Encoding.default_internal = default_internal + end + end + + it "raises Argument error when given 2 arguments and an encoding name containing a null byte" do + -> { @io.set_encoding(Encoding::UTF_8, "null\0byte") }.should.raise(ArgumentError) + -> { @io.set_encoding("null\0byte", Encoding::UTF_8) }.should.raise(ArgumentError) + end end diff --git a/core/io/sysread_spec.rb b/core/io/sysread_spec.rb index 078e97934..69e6f7a1a 100644 --- a/core/io/sysread_spec.rb +++ b/core/io/sysread_spec.rb @@ -52,7 +52,17 @@ it "raises an error when called after buffered reads" do @file.readline - -> { @file.sysread(5) }.should.raise(IOError) + -> do + @file.sysread(5) + end.should.raise(IOError, "sysread for buffered IO") + end + + it "raises an error when called with a non-empty character buffer" do + @file.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) + @file.ungetc("a".encode(Encoding::UTF_16BE)) + -> do + @file.sysread(5) + end.should.raise(IOError, "byte oriented read for character buffered IO") end it "reads normally even when called immediately after a buffered IO#read" do diff --git a/core/io/sysseek_spec.rb b/core/io/sysseek_spec.rb index e513d189a..ba24a1822 100644 --- a/core/io/sysseek_spec.rb +++ b/core/io/sysseek_spec.rb @@ -28,7 +28,17 @@ it "raises an error when called after buffered reads" do @io.readline - -> { @io.sysseek(-5, IO::SEEK_CUR) }.should.raise(IOError) + -> do + @io.sysseek(-5, IO::SEEK_CUR) + end.should.raise(IOError, "sysseek for buffered IO") + end + + it "raises an error when called with a non-empty character buffer" do + @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) + @io.ungetc("a".encode(Encoding::UTF_16BE)) + -> do + @io.sysseek(-5, IO::SEEK_CUR) + end.should.raise(IOError, "sysseek for buffered IO") end it "seeks normally even when called immediately after a buffered IO#read" do diff --git a/core/io/syswrite_spec.rb b/core/io/syswrite_spec.rb index 8bf61a27c..1cf28dae6 100644 --- a/core/io/syswrite_spec.rb +++ b/core/io/syswrite_spec.rb @@ -60,19 +60,42 @@ end describe "IO#syswrite on a pipe" do - it "returns the written bytes if the fd is in nonblock mode and write would block" do + before do require 'io/nonblock' - r, w = IO.pipe - begin - w.nonblock = true - larger_than_pipe_capacity = 2 * 1024 * 1024 - written = w.syswrite("a"*larger_than_pipe_capacity) - written.should > 0 - written.should < larger_than_pipe_capacity - ensure - w.close - r.close + @read, @write = IO.pipe + end + + after do + @read.close + @write.close + end + + ruby_version_is ""..."3.2" do + platform_is_not :windows do + it "raises Errno::EAGAIN when the write would block" do + @write.nonblock = true + -> { + loop { @write.syswrite('a' * 10_000) } + }.should.raise(Errno::EAGAIN) + end end + + platform_is :windows do + it "raises Errno::EWOULDBLOCK when the write would block" do + @write.nonblock = true + -> { + loop { @write.syswrite('a' * 10_000) } + }.should.raise(Errno::EWOULDBLOCK) + end + end + end + + it "returns the written bytes if the fd is in nonblock mode and write would block" do + @write.nonblock = true + larger_than_pipe_capacity = 2 * 1024 * 1024 + written = @write.syswrite("a"*larger_than_pipe_capacity) + written.should > 0 + written.should < larger_than_pipe_capacity end end diff --git a/core/io/write_spec.rb b/core/io/write_spec.rb index 469f9a89e..463e73e0a 100644 --- a/core/io/write_spec.rb +++ b/core/io/write_spec.rb @@ -140,6 +140,36 @@ File.binread(@filename).bytes.should == [0x61, 0x00, 0x00, 0x00, 0xC4, 0x85] end end + + it "writes binary data if encoding is ASCII-8BIT" do + File.open(@filename, "w:ascii-8bit") do |file| + file.write('Hëllö'.encode('ISO-8859-1')) + end + ë = ([235].pack('U')).encode('ISO-8859-1') + ö = ([246].pack('U')).encode('ISO-8859-1') + res = "H#{ë}ll#{ö}" + File.binread(@filename).should == res.force_encoding(Encoding::BINARY) + end + + it "writes binary data with newline conversion if no encoding is given" do + File.open(@filename, "w", newline: :crlf) do |file| + file.write("Hëllö\n".encode('ISO-8859-1')) + end + ë = ([235].pack('U')).encode('ISO-8859-1') + ö = ([246].pack('U')).encode('ISO-8859-1') + res = "H#{ë}ll#{ö}\r\n" + File.binread(@filename).should == res.force_encoding(Encoding::BINARY) + end + + it "writes binary data with newline conversion if encoding is ASCII-8BIT" do + File.open(@filename, "w:ascii-8bit", newline: :crlf) do |file| + file.write("Hëllö\n".encode('ISO-8859-1')) + end + ë = ([235].pack('U')).encode('ISO-8859-1') + ö = ([246].pack('U')).encode('ISO-8859-1') + res = "H#{ë}ll#{ö}\r\n" + File.binread(@filename).should == res.force_encoding(Encoding::BINARY) + end end describe "IO.write" do