diff options
Diffstat (limited to 'spec/ruby/library/stringio/shared')
| -rw-r--r-- | spec/ruby/library/stringio/shared/codepoints.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each.rb | 100 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each_byte.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each_char.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/getc.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/gets.rb | 249 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/isatty.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/read.rb | 36 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/readchar.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/sysread.rb | 4 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/write.rb | 74 |
11 files changed, 443 insertions, 32 deletions
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb index 9d84aa4919..25333bb0fd 100644 --- a/spec/ruby/library/stringio/shared/codepoints.rb +++ b/spec/ruby/library/stringio/shared/codepoints.rb @@ -27,7 +27,7 @@ describe :stringio_codepoints, shared: true do @io.close_read -> { @enum.to_a }.should raise_error(IOError) - io = StringIO.new("xyz", "w") + io = StringIO.new(+"xyz", "w") -> { io.send(@method).to_a }.should raise_error(IOError) end diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb index 14b0a013b3..626b41a4d3 100644 --- a/spec/ruby/library/stringio/shared/each.rb +++ b/spec/ruby/library/stringio/shared/each.rb @@ -36,11 +36,11 @@ describe :stringio_each_separator, shared: true do seen.should == ["2 1 2 1 2"] end - it "yields each paragraph when passed an empty String as separator" do + it "yields each paragraph with all separation characters when passed an empty String as separator" do seen = [] io = StringIO.new("para1\n\npara2\n\n\npara3") io.send(@method, "") {|s| seen << s} - seen.should == ["para1\n\n", "para2\n\n", "para3"] + seen.should == ["para1\n\n", "para2\n\n\n", "para3"] end end @@ -96,7 +96,7 @@ end describe :stringio_each_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("a b c d e", "w") + io = StringIO.new(+"a b c d e", "w") -> { io.send(@method) { |b| b } }.should raise_error(IOError) io = StringIO.new("a b c d e") @@ -112,4 +112,98 @@ describe :stringio_each_chomp, shared: true do io.send(@method, chomp: true) {|s| seen << s } seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] end + + it "returns each line with removed newline characters when called without block" do + seen = [] + io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end") + enum = io.send(@method, chomp: true) + enum.each {|s| seen << s } + seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] + end +end + +describe :stringio_each_separator_and_chomp, shared: true do + it "yields each line with removed separator to the passed block" do + seen = [] + io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") + io.send(@method, "|", chomp: true) {|s| seen << s } + seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] + end + + it "returns each line with removed separator when called without block" do + seen = [] + io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") + enum = io.send(@method, "|", chomp: true) + enum.each {|s| seen << s } + seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] + end +end + +describe :stringio_each_limit, shared: true do + before :each do + @io = StringIO.new("a b c d e\n1 2 3 4 5") + end + + it "returns the data read until the limit is met" do + seen = [] + @io.send(@method, 4) { |s| seen << s } + seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] + end +end + +describe :stringio_each_separator_and_limit, shared: true do + before :each do + @io = StringIO.new("this>is>an>example") + end + + it "returns the data read until the limit is consumed or the separator is met" do + @io.send(@method, '>', 8) { |s| break s }.should == "this>" + @io.send(@method, '>', 2) { |s| break s }.should == "is" + @io.send(@method, '>', 10) { |s| break s }.should == ">" + @io.send(@method, '>', 6) { |s| break s }.should == "an>" + @io.send(@method, '>', 5) { |s| break s }.should == "examp" + end + + it "truncates the multi-character separator at the end to meet the limit" do + @io.send(@method, "is>an", 7) { |s| break s }.should == "this>is" + end + + it "does not change $_" do + $_ = "test" + @io.send(@method, '>', 8) { |s| s } + $_.should == "test" + end + + it "updates self's lineno by one" do + @io.send(@method, '>', 3) { |s| break s } + @io.lineno.should eql(1) + + @io.send(@method, '>', 3) { |s| break s } + @io.lineno.should eql(2) + + @io.send(@method, '>', 3) { |s| break s } + @io.lineno.should eql(3) + end + + it "tries to convert the passed separator to a String using #to_str" do # TODO + obj = mock('to_str') + obj.should_receive(:to_str).and_return('>') + + seen = [] + @io.send(@method, obj, 5) { |s| seen << s } + seen.should == ["this>", "is>", "an>", "examp", "le"] + end + + it "does not raise TypeError if passed separator is nil" do + @io.send(@method, nil, 5) { |s| break s }.should == "this>" + end + + it "tries to convert the passed limit to an Integer using #to_int" do # TODO + obj = mock('to_int') + obj.should_receive(:to_int).and_return(5) + + seen = [] + @io.send(@method, '>', obj) { |s| seen << s } + seen.should == ["this>", "is>", "an>", "examp", "le"] + end end diff --git a/spec/ruby/library/stringio/shared/each_byte.rb b/spec/ruby/library/stringio/shared/each_byte.rb index 56734ff99d..b51fa38f2f 100644 --- a/spec/ruby/library/stringio/shared/each_byte.rb +++ b/spec/ruby/library/stringio/shared/each_byte.rb @@ -38,7 +38,7 @@ end describe :stringio_each_byte_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("xyz", "w") + io = StringIO.new(+"xyz", "w") -> { io.send(@method) { |b| b } }.should raise_error(IOError) io = StringIO.new("xyz") diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb index bcdac53282..197237c1c8 100644 --- a/spec/ruby/library/stringio/shared/each_char.rb +++ b/spec/ruby/library/stringio/shared/each_char.rb @@ -26,7 +26,7 @@ end describe :stringio_each_char_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("xyz", "w") + io = StringIO.new(+"xyz", "w") -> { io.send(@method) { |b| b } }.should raise_error(IOError) io = StringIO.new("xyz") diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb index 6318bcc30f..ba65040bce 100644 --- a/spec/ruby/library/stringio/shared/getc.rb +++ b/spec/ruby/library/stringio/shared/getc.rb @@ -33,7 +33,7 @@ end describe :stringio_getc_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("xyz", "w") + io = StringIO.new(+"xyz", "w") -> { io.send(@method) }.should raise_error(IOError) io = StringIO.new("xyz") diff --git a/spec/ruby/library/stringio/shared/gets.rb b/spec/ruby/library/stringio/shared/gets.rb new file mode 100644 index 0000000000..8396b161f1 --- /dev/null +++ b/spec/ruby/library/stringio/shared/gets.rb @@ -0,0 +1,249 @@ +describe :stringio_gets_separator, shared: true do + describe "when passed [separator]" do + before :each do + @io = StringIO.new("this>is>an>example") + end + + it "returns the data read till the next occurrence of the passed separator" do + @io.send(@method, ">").should == "this>" + @io.send(@method, ">").should == "is>" + @io.send(@method, ">").should == "an>" + @io.send(@method, ">").should == "example" + end + + it "sets $_ to the read content" do + @io.send(@method, ">") + $_.should == "this>" + @io.send(@method, ">") + $_.should == "is>" + @io.send(@method, ">") + $_.should == "an>" + @io.send(@method, ">") + $_.should == "example" + end + + it "accepts string as separator" do + @io.send(@method, "is>") + $_.should == "this>" + @io.send(@method, "an>") + $_.should == "is>an>" + @io.send(@method, "example") + $_.should == "example" + end + + it "updates self's lineno by one" do + @io.send(@method, ">") + @io.lineno.should eql(1) + + @io.send(@method, ">") + @io.lineno.should eql(2) + + @io.send(@method, ">") + @io.lineno.should eql(3) + end + + it "returns the next paragraph when the passed separator is an empty String" do + io = StringIO.new("this is\n\nan example") + io.send(@method, "").should == "this is\n\n" + io.send(@method, "").should == "an example" + end + + it "returns the remaining content starting at the current position when passed nil" do + io = StringIO.new("this is\n\nan example") + io.pos = 5 + io.send(@method, nil).should == "is\n\nan example" + end + + it "tries to convert the passed separator to a String using #to_str" do + obj = mock('to_str') + obj.should_receive(:to_str).and_return(">") + @io.send(@method, obj).should == "this>" + end + end +end + +describe :stringio_gets_limit, shared: true do + describe "when passed [limit]" do + before :each do + @io = StringIO.new("this>is>an>example") + end + + it "returns the data read until the limit is met" do + @io.send(@method, 4).should == "this" + @io.send(@method, 3).should == ">is" + @io.send(@method, 5).should == ">an>e" + @io.send(@method, 6).should == "xample" + end + + it "sets $_ to the read content" do + @io.send(@method, 4) + $_.should == "this" + @io.send(@method, 3) + $_.should == ">is" + @io.send(@method, 5) + $_.should == ">an>e" + @io.send(@method, 6) + $_.should == "xample" + end + + it "updates self's lineno by one" do + @io.send(@method, 3) + @io.lineno.should eql(1) + + @io.send(@method, 3) + @io.lineno.should eql(2) + + @io.send(@method, 3) + @io.lineno.should eql(3) + end + + it "tries to convert the passed limit to an Integer using #to_int" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(4) + @io.send(@method, obj).should == "this" + end + + it "returns a blank string when passed a limit of 0" do + @io.send(@method, 0).should == "" + end + + it "ignores it when passed a negative limit" do + @io.send(@method, -4).should == "this>is>an>example" + end + end +end + +describe :stringio_gets_separator_and_limit, shared: true do + describe "when passed [separator] and [limit]" do + before :each do + @io = StringIO.new("this>is>an>example") + end + + it "returns the data read until the limit is consumed or the separator is met" do + @io.send(@method, '>', 8).should == "this>" + @io.send(@method, '>', 2).should == "is" + @io.send(@method, '>', 10).should == ">" + @io.send(@method, '>', 6).should == "an>" + @io.send(@method, '>', 5).should == "examp" + end + + it "truncates the multi-character separator at the end to meet the limit" do + @io.send(@method, "is>an", 7).should == "this>is" + end + + it "sets $_ to the read content" do + @io.send(@method, '>', 8) + $_.should == "this>" + @io.send(@method, '>', 2) + $_.should == "is" + @io.send(@method, '>', 10) + $_.should == ">" + @io.send(@method, '>', 6) + $_.should == "an>" + @io.send(@method, '>', 5) + $_.should == "examp" + end + + it "updates self's lineno by one" do + @io.send(@method, '>', 3) + @io.lineno.should eql(1) + + @io.send(@method, '>', 3) + @io.lineno.should eql(2) + + @io.send(@method, '>', 3) + @io.lineno.should eql(3) + end + + it "tries to convert the passed separator to a String using #to_str" do + obj = mock('to_str') + obj.should_receive(:to_str).and_return('>') + @io.send(@method, obj, 5).should == "this>" + end + + it "does not raise TypeError if passed separator is nil" do + @io.send(@method, nil, 5).should == "this>" + end + + it "tries to convert the passed limit to an Integer using #to_int" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(5) + @io.send(@method, '>', obj).should == "this>" + end + end +end + +describe :stringio_gets_no_argument, shared: true do + describe "when passed no argument" do + before :each do + @io = StringIO.new("this is\nan example\nfor StringIO#gets") + end + + it "returns the data read till the next occurrence of $/ or till eof" do + @io.send(@method).should == "this is\n" + + begin + old_sep = $/ + suppress_warning {$/ = " "} + @io.send(@method).should == "an " + @io.send(@method).should == "example\nfor " + @io.send(@method).should == "StringIO#gets" + ensure + suppress_warning {$/ = old_sep} + end + end + + it "sets $_ to the read content" do + @io.send(@method) + $_.should == "this is\n" + @io.send(@method) + $_.should == "an example\n" + @io.send(@method) + $_.should == "for StringIO#gets" + end + + it "updates self's position" do + @io.send(@method) + @io.pos.should eql(8) + + @io.send(@method) + @io.pos.should eql(19) + + @io.send(@method) + @io.pos.should eql(36) + end + + it "updates self's lineno" do + @io.send(@method) + @io.lineno.should eql(1) + + @io.send(@method) + @io.lineno.should eql(2) + + @io.send(@method) + @io.lineno.should eql(3) + end + end +end + +describe :stringio_gets_chomp, shared: true do + describe "when passed [chomp]" do + it "returns the data read without a trailing newline character" do + io = StringIO.new("this>is>an>example\n") + io.send(@method, chomp: true).should == "this>is>an>example" + end + end +end + +describe :stringio_gets_write_only, shared: true do + describe "when in write-only mode" do + it "raises an IOError" do + io = StringIO.new(+"xyz", "w") + -> { io.send(@method) }.should raise_error(IOError) + + io = StringIO.new("xyz") + io.close_read + -> { io.send(@method) }.should raise_error(IOError) + end + end +end diff --git a/spec/ruby/library/stringio/shared/isatty.rb b/spec/ruby/library/stringio/shared/isatty.rb index 3da5999953..c9e7ee7321 100644 --- a/spec/ruby/library/stringio/shared/isatty.rb +++ b/spec/ruby/library/stringio/shared/isatty.rb @@ -1,5 +1,5 @@ describe :stringio_isatty, shared: true do it "returns false" do - StringIO.new('tty').send(@method).should be_false + StringIO.new("tty").send(@method).should be_false end end diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb index c60677bba7..22f76b0fb0 100644 --- a/spec/ruby/library/stringio/shared/read.rb +++ b/spec/ruby/library/stringio/shared/read.rb @@ -5,19 +5,37 @@ describe :stringio_read, shared: true do it "returns the passed buffer String" do # Note: Rubinius bug: - # @io.send(@method, 7, buffer = "").should equal(buffer) - ret = @io.send(@method, 7, buffer = "") + # @io.send(@method, 7, buffer = +"").should equal(buffer) + ret = @io.send(@method, 7, buffer = +"") ret.should equal(buffer) end it "reads length bytes and writes them to the buffer String" do - @io.send(@method, 7, buffer = "") + @io.send(@method, 7, buffer = +"").should.equal?(buffer) buffer.should == "example" end + guard -> { StringIO::VERSION < "3.1.2" } do + it "does not preserve the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.send(@method, 7, buffer) + + buffer.encoding.should_not == Encoding::ISO_8859_1 + end + end + + guard -> { StringIO::VERSION >= "3.1.2" } do + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @io.send(@method, 7, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + end + it "tries to convert the passed buffer Object to a String using #to_str" do obj = mock("to_str") - obj.should_receive(:to_str).and_return(buffer = "") + obj.should_receive(:to_str).and_return(buffer = +"") @io.send(@method, 7, obj) buffer.should == "example" @@ -75,7 +93,7 @@ end describe :stringio_read_no_arguments, shared: true do before :each do - @io = StringIO.new("example") + @io = StringIO.new(+"example") end it "reads the whole content starting from the current position" do @@ -89,6 +107,12 @@ describe :stringio_read_no_arguments, shared: true do @io.send(@method) @io.pos.should eql(7) end + + it "correctly update the current position in bytes when multi-byte characters are used" do + @io.print("example\u03A3") # Overwrite the original string with 8 characters containing 9 bytes. + @io.send(@method) + @io.pos.should eql(9) + end end describe :stringio_read_nil, shared: true do @@ -111,7 +135,7 @@ end describe :stringio_read_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("test", "w") + io = StringIO.new(+"test", "w") -> { io.send(@method) }.should raise_error(IOError) io = StringIO.new("test") diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb index 4248e75420..72d7446c36 100644 --- a/spec/ruby/library/stringio/shared/readchar.rb +++ b/spec/ruby/library/stringio/shared/readchar.rb @@ -19,7 +19,7 @@ end describe :stringio_readchar_not_readable, shared: true do it "raises an IOError" do - io = StringIO.new("a b c d e", "w") + io = StringIO.new(+"a b c d e", "w") -> { io.send(@method) }.should raise_error(IOError) io = StringIO.new("a b c d e") diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb index 3376bd9907..3e23fbc233 100644 --- a/spec/ruby/library/stringio/shared/sysread.rb +++ b/spec/ruby/library/stringio/shared/sysread.rb @@ -1,4 +1,4 @@ -describe :stringio_sysread_length, :shared => true do +describe :stringio_sysread_length, shared: true do before :each do @io = StringIO.new("example") end @@ -10,6 +10,6 @@ describe :stringio_sysread_length, :shared => true do it "raises an EOFError when passed length > 0 and no data remains" do @io.read.should == "example" - -> { @io.sysread(1) }.should raise_error(EOFError) + -> { @io.send(@method, 1) }.should raise_error(EOFError) end end diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb index 080729217b..4661658baf 100644 --- a/spec/ruby/library/stringio/shared/write.rb +++ b/spec/ruby/library/stringio/shared/write.rb @@ -1,6 +1,6 @@ describe :stringio_write, shared: true do before :each do - @io = StringIO.new('12345') + @io = StringIO.new(+'12345') end it "tries to convert the passed Object to a String using #to_s" do @@ -13,7 +13,7 @@ end describe :stringio_write_string, shared: true do before :each do - @io = StringIO.new('12345') + @io = StringIO.new(+'12345') end # TODO: RDoc says that #write appends at the current position. @@ -45,27 +45,71 @@ describe :stringio_write_string, shared: true do @io.pos.should eql(4) end - ruby_version_is ""..."2.7" do - it "taints self's String when the passed argument is tainted" do - @io.send(@method, "test".taint) - @io.string.tainted?.should be_true - end + it "handles concurrent writes correctly" do + @io = StringIO.new + n = 8 + go = false + threads = n.times.map { |i| + Thread.new { + Thread.pass until go + @io.write i.to_s + } + } + go = true + threads.each(&:join) + @io.string.size.should == n.times.map(&:to_s).join.size end - ruby_version_is ""..."3.0" do - it "does not taint self when the passed argument is tainted" do - @io.send(@method, "test".taint) - @io.tainted?.should be_false - end + it "handles writing non-ASCII UTF-8 after seek" do + @io.binmode + @io << "\x80" + @io.pos = 0 + @io << "\x81" + @io.string.should == "\x812345".b + end + + it "handles writing with position < buffer size" do + @io.pos = 2 + @io.write "abc" + @io.string.should == "12abc" + + @io.pos = 2 + @io.write "de" + @io.string.should == "12dec" + + @io.pos = 2 + @io.write "fghi" + @io.string.should == "12fghi" + end + + it "transcodes the given string when the external encoding is set and neither is BINARY" do + utf8_str = "hello" + io = StringIO.new.set_encoding(Encoding::UTF_16BE) + io.external_encoding.should == Encoding::UTF_16BE + + io.send(@method, utf8_str) + + expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello" + io.string.bytes.should == expected + end + + it "does not transcode the given string when the external encoding is set and the string encoding is BINARY" do + str = "été_".b + io = StringIO.new.set_encoding(Encoding::UTF_16BE) + io.external_encoding.should == Encoding::UTF_16BE + + io.send(@method, str) + + io.string.bytes.should == str.bytes end end describe :stringio_write_not_writable, shared: true do it "raises an IOError" do - io = StringIO.new("test", "r") + io = StringIO.new(+"test", "r") -> { io.send(@method, "test") }.should raise_error(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write -> { io.send(@method, "test") }.should raise_error(IOError) end @@ -73,7 +117,7 @@ end describe :stringio_write_append, shared: true do before :each do - @io = StringIO.new("example", "a") + @io = StringIO.new(+"example", "a") end it "appends the passed argument to the end of self" do |
