diff options
Diffstat (limited to 'spec/ruby/library/stringio/shared')
| -rw-r--r-- | spec/ruby/library/stringio/shared/codepoints.rb | 45 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each.rb | 209 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each_byte.rb | 48 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/each_char.rb | 36 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/eof.rb | 24 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/getc.rb | 43 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/gets.rb | 249 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/isatty.rb | 5 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/length.rb | 5 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/read.rb | 145 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/readchar.rb | 29 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/sysread.rb | 15 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/tell.rb | 12 | ||||
| -rw-r--r-- | spec/ruby/library/stringio/shared/write.rb | 135 |
14 files changed, 1000 insertions, 0 deletions
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb new file mode 100644 index 0000000000..25333bb0fd --- /dev/null +++ b/spec/ruby/library/stringio/shared/codepoints.rb @@ -0,0 +1,45 @@ +# -*- encoding: utf-8 -*- +describe :stringio_codepoints, shared: true do + before :each do + @io = StringIO.new("∂φ/∂x = gaîté") + @enum = @io.send(@method) + end + + it "returns an Enumerator" do + @enum.should be_an_instance_of(Enumerator) + end + + it "yields each codepoint code in turn" do + @enum.to_a.should == [8706, 966, 47, 8706, 120, 32, 61, 32, 103, 97, 238, 116, 233] + end + + it "yields each codepoint starting from the current position" do + @io.pos = 15 + @enum.to_a.should == [238, 116, 233] + end + + it "raises an error if reading invalid sequence" do + @io.pos = 1 # inside of a multibyte sequence + -> { @enum.first }.should raise_error(ArgumentError) + end + + it "raises an IOError if not readable" do + @io.close_read + -> { @enum.to_a }.should raise_error(IOError) + + io = StringIO.new(+"xyz", "w") + -> { io.send(@method).to_a }.should raise_error(IOError) + end + + + it "calls the given block" do + r = [] + @io.send(@method){|c| r << c } + r.should == [8706, 966, 47, 8706, 120, 32, 61, 32, 103, 97, 238, 116, 233] + end + + it "returns self" do + @io.send(@method) {|l| l }.should equal(@io) + end + +end diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb new file mode 100644 index 0000000000..626b41a4d3 --- /dev/null +++ b/spec/ruby/library/stringio/shared/each.rb @@ -0,0 +1,209 @@ +describe :stringio_each_separator, shared: true do + before :each do + @io = StringIO.new("a b c d e\n1 2 3 4 5") + end + + it "uses the passed argument as the line separator" do + seen = [] + @io.send(@method, " ") {|s| seen << s} + seen.should == ["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"] + end + + it "does not change $_" do + $_ = "test" + @io.send(@method, " ") { |s| s} + $_.should == "test" + end + + it "returns self" do + @io.send(@method) {|l| l }.should equal(@io) + end + + it "tries to convert the passed separator to a String using #to_str" do + obj = mock("to_str") + obj.stub!(:to_str).and_return(" ") + + seen = [] + @io.send(@method, obj) { |l| seen << l } + seen.should == ["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"] + end + + it "yields self's content starting from the current position when the passed separator is nil" do + seen = [] + io = StringIO.new("1 2 1 2 1 2") + io.pos = 2 + io.send(@method, nil) {|s| seen << s} + seen.should == ["2 1 2 1 2"] + end + + 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\n", "para3"] + end +end + +describe :stringio_each_no_arguments, shared: true do + before :each do + @io = StringIO.new("a b c d e\n1 2 3 4 5") + end + + it "yields each line to the passed block" do + seen = [] + @io.send(@method) {|s| seen << s } + seen.should == ["a b c d e\n", "1 2 3 4 5"] + end + + it "yields each line starting from the current position" do + seen = [] + @io.pos = 4 + @io.send(@method) {|s| seen << s } + seen.should == ["c d e\n", "1 2 3 4 5"] + end + + it "does not change $_" do + $_ = "test" + @io.send(@method) { |s| s} + $_.should == "test" + end + + it "uses $/ as the default line separator" do + seen = [] + begin + old_rs = $/ + suppress_warning {$/ = " "} + @io.send(@method) {|s| seen << s } + seen.should eql(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"]) + ensure + suppress_warning {$/ = old_rs} + end + end + + it "returns self" do + @io.send(@method) {|l| l }.should equal(@io) + end + + it "returns an Enumerator when passed no block" do + enum = @io.send(@method) + enum.instance_of?(Enumerator).should be_true + + seen = [] + enum.each { |b| seen << b } + seen.should == ["a b c d e\n", "1 2 3 4 5"] + end +end + +describe :stringio_each_not_readable, shared: true do + it "raises an IOError" do + 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") + io.close_read + -> { io.send(@method) { |b| b } }.should raise_error(IOError) + end +end + +describe :stringio_each_chomp, shared: true do + it "yields each line with removed newline characters to the passed block" do + seen = [] + io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end") + 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 new file mode 100644 index 0000000000..b51fa38f2f --- /dev/null +++ b/spec/ruby/library/stringio/shared/each_byte.rb @@ -0,0 +1,48 @@ +describe :stringio_each_byte, shared: true do + before :each do + @io = StringIO.new("xyz") + end + + it "yields each character code in turn" do + seen = [] + @io.send(@method) { |b| seen << b } + seen.should == [120, 121, 122] + end + + it "updates the position before each yield" do + seen = [] + @io.send(@method) { |b| seen << @io.pos } + seen.should == [1, 2, 3] + end + + it "does not yield if the current position is out of bounds" do + @io.pos = 1000 + seen = nil + @io.send(@method) { |b| seen = b } + seen.should be_nil + end + + it "returns self" do + @io.send(@method) {}.should equal(@io) + end + + it "returns an Enumerator when passed no block" do + enum = @io.send(@method) + enum.instance_of?(Enumerator).should be_true + + seen = [] + enum.each { |b| seen << b } + seen.should == [120, 121, 122] + end +end + +describe :stringio_each_byte_not_readable, shared: true do + it "raises an IOError" do + io = StringIO.new(+"xyz", "w") + -> { io.send(@method) { |b| b } }.should raise_error(IOError) + + io = StringIO.new("xyz") + io.close_read + -> { io.send(@method) { |b| b } }.should raise_error(IOError) + end +end diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb new file mode 100644 index 0000000000..197237c1c8 --- /dev/null +++ b/spec/ruby/library/stringio/shared/each_char.rb @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +describe :stringio_each_char, shared: true do + before :each do + @io = StringIO.new("xyz äöü") + end + + it "yields each character code in turn" do + seen = [] + @io.send(@method) { |c| seen << c } + seen.should == ["x", "y", "z", " ", "ä", "ö", "ü"] + end + + it "returns self" do + @io.send(@method) {}.should equal(@io) + end + + it "returns an Enumerator when passed no block" do + enum = @io.send(@method) + enum.instance_of?(Enumerator).should be_true + + seen = [] + enum.each { |c| seen << c } + seen.should == ["x", "y", "z", " ", "ä", "ö", "ü"] + end +end + +describe :stringio_each_char_not_readable, shared: true do + it "raises an IOError" do + io = StringIO.new(+"xyz", "w") + -> { io.send(@method) { |b| b } }.should raise_error(IOError) + + io = StringIO.new("xyz") + io.close_read + -> { io.send(@method) { |b| b } }.should raise_error(IOError) + end +end diff --git a/spec/ruby/library/stringio/shared/eof.rb b/spec/ruby/library/stringio/shared/eof.rb new file mode 100644 index 0000000000..e0368a2892 --- /dev/null +++ b/spec/ruby/library/stringio/shared/eof.rb @@ -0,0 +1,24 @@ +describe :stringio_eof, shared: true do + before :each do + @io = StringIO.new("eof") + end + + it "returns true when self's position is greater than or equal to self's size" do + @io.pos = 3 + @io.send(@method).should be_true + + @io.pos = 6 + @io.send(@method).should be_true + end + + it "returns false when self's position is less than self's size" do + @io.pos = 0 + @io.send(@method).should be_false + + @io.pos = 1 + @io.send(@method).should be_false + + @io.pos = 2 + @io.send(@method).should be_false + end +end diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb new file mode 100644 index 0000000000..ba65040bce --- /dev/null +++ b/spec/ruby/library/stringio/shared/getc.rb @@ -0,0 +1,43 @@ +describe :stringio_getc, shared: true do + before :each do + @io = StringIO.new("example") + end + + it "increases self's position by one" do + @io.send(@method) + @io.pos.should eql(1) + + @io.send(@method) + @io.pos.should eql(2) + + @io.send(@method) + @io.pos.should eql(3) + end + + it "returns nil when called at the end of self" do + @io.pos = 7 + @io.send(@method).should be_nil + @io.send(@method).should be_nil + @io.send(@method).should be_nil + end + + it "does not increase self's position when called at the end of file" do + @io.pos = 7 + @io.send(@method) + @io.pos.should eql(7) + + @io.send(@method) + @io.pos.should eql(7) + end +end + +describe :stringio_getc_not_readable, shared: true 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 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 new file mode 100644 index 0000000000..c9e7ee7321 --- /dev/null +++ b/spec/ruby/library/stringio/shared/isatty.rb @@ -0,0 +1,5 @@ +describe :stringio_isatty, shared: true do + it "returns false" do + StringIO.new("tty").send(@method).should be_false + end +end diff --git a/spec/ruby/library/stringio/shared/length.rb b/spec/ruby/library/stringio/shared/length.rb new file mode 100644 index 0000000000..60a4eb1bdd --- /dev/null +++ b/spec/ruby/library/stringio/shared/length.rb @@ -0,0 +1,5 @@ +describe :stringio_length, shared: true do + it "returns the length of the wrapped string" do + StringIO.new("example").send(@method).should == 7 + end +end diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb new file mode 100644 index 0000000000..22f76b0fb0 --- /dev/null +++ b/spec/ruby/library/stringio/shared/read.rb @@ -0,0 +1,145 @@ +describe :stringio_read, shared: true do + before :each do + @io = StringIO.new("example") + end + + it "returns the passed buffer String" do + # Note: Rubinius bug: + # @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 = +"").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 = +"") + + @io.send(@method, 7, obj) + buffer.should == "example" + end + + it "raises a TypeError when the passed buffer Object can't be converted to a String" do + -> { @io.send(@method, 7, Object.new) }.should raise_error(TypeError) + end + + it "raises a FrozenError error when passed a frozen String as buffer" do + -> { @io.send(@method, 7, "".freeze) }.should raise_error(FrozenError) + end +end + +describe :stringio_read_length, shared: true do + before :each do + @io = StringIO.new("example") + end + + it "reads length bytes from the current position and returns them" do + @io.pos = 3 + @io.send(@method, 4).should == "mple" + end + + it "reads at most the whole content" do + @io.send(@method, 999).should == "example" + end + + it "correctly updates the position" do + @io.send(@method, 3) + @io.pos.should eql(3) + + @io.send(@method, 999) + @io.pos.should eql(7) + end + + it "tries to convert the passed length to an Integer using #to_int" do + obj = mock("to_int") + obj.should_receive(:to_int).and_return(7) + @io.send(@method, obj).should == "example" + end + + it "raises a TypeError when the passed length can't be converted to an Integer" do + -> { @io.send(@method, Object.new) }.should raise_error(TypeError) + end + + it "raises a TypeError when the passed length is negative" do + -> { @io.send(@method, -2) }.should raise_error(ArgumentError) + end + + it "returns a binary String" do + @io.send(@method, 4).encoding.should == Encoding::BINARY + end +end + +describe :stringio_read_no_arguments, shared: true do + before :each do + @io = StringIO.new(+"example") + end + + it "reads the whole content starting from the current position" do + @io.send(@method).should == "example" + + @io.pos = 3 + @io.send(@method).should == "mple" + end + + it "correctly updates the current position" 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 + before :each do + @io = StringIO.new("example") + end + + it "returns the remaining content from the current position" do + @io.send(@method, nil).should == "example" + + @io.pos = 4 + @io.send(@method, nil).should == "ple" + end + + it "updates the current position" do + @io.send(@method, nil) + @io.pos.should eql(7) + end +end + +describe :stringio_read_not_readable, shared: true do + it "raises an IOError" do + io = StringIO.new(+"test", "w") + -> { io.send(@method) }.should raise_error(IOError) + + io = StringIO.new("test") + io.close_read + -> { io.send(@method) }.should raise_error(IOError) + end +end diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb new file mode 100644 index 0000000000..72d7446c36 --- /dev/null +++ b/spec/ruby/library/stringio/shared/readchar.rb @@ -0,0 +1,29 @@ +describe :stringio_readchar, shared: true do + before :each do + @io = StringIO.new("example") + end + + it "correctly updates the current position" do + @io.send(@method) + @io.pos.should == 1 + + @io.send(@method) + @io.pos.should == 2 + end + + it "raises an EOFError when self is at the end" do + @io.pos = 7 + -> { @io.send(@method) }.should raise_error(EOFError) + end +end + +describe :stringio_readchar_not_readable, shared: true do + it "raises an IOError" do + io = StringIO.new(+"a b c d e", "w") + -> { io.send(@method) }.should raise_error(IOError) + + io = StringIO.new("a b c d e") + io.close_read + -> { io.send(@method) }.should raise_error(IOError) + end +end diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb new file mode 100644 index 0000000000..3e23fbc233 --- /dev/null +++ b/spec/ruby/library/stringio/shared/sysread.rb @@ -0,0 +1,15 @@ +describe :stringio_sysread_length, shared: true do + before :each do + @io = StringIO.new("example") + end + + it "returns an empty String when passed 0 and no data remains" do + @io.send(@method, 8).should == "example" + @io.send(@method, 0).should == "" + end + + it "raises an EOFError when passed length > 0 and no data remains" do + @io.read.should == "example" + -> { @io.send(@method, 1) }.should raise_error(EOFError) + end +end diff --git a/spec/ruby/library/stringio/shared/tell.rb b/spec/ruby/library/stringio/shared/tell.rb new file mode 100644 index 0000000000..852c51c192 --- /dev/null +++ b/spec/ruby/library/stringio/shared/tell.rb @@ -0,0 +1,12 @@ +describe :stringio_tell, shared: true do + before :each do + @io = StringIOSpecs.build + end + + it "returns the current byte offset" do + @io.getc + @io.send(@method).should == 1 + @io.read(7) + @io.send(@method).should == 8 + end +end diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb new file mode 100644 index 0000000000..4661658baf --- /dev/null +++ b/spec/ruby/library/stringio/shared/write.rb @@ -0,0 +1,135 @@ +describe :stringio_write, shared: true do + before :each do + @io = StringIO.new(+'12345') + end + + it "tries to convert the passed Object to a String using #to_s" do + obj = mock("to_s") + obj.should_receive(:to_s).and_return("to_s") + @io.send(@method, obj) + @io.string.should == "to_s5" + end +end + +describe :stringio_write_string, shared: true do + before :each do + @io = StringIO.new(+'12345') + end + + # TODO: RDoc says that #write appends at the current position. + it "writes the passed String at the current buffer position" do + @io.pos = 2 + @io.send(@method, 'x').should == 1 + @io.string.should == '12x45' + @io.send(@method, 7).should == 1 + @io.string.should == '12x75' + end + + it "pads self with \\000 when the current position is after the end" do + @io.pos = 8 + @io.send(@method, 'x') + @io.string.should == "12345\000\000\000x" + @io.send(@method, 9) + @io.string.should == "12345\000\000\000x9" + end + + it "returns the number of bytes written" do + @io.send(@method, '').should == 0 + @io.send(@method, nil).should == 0 + str = "1" * 100 + @io.send(@method, str).should == 100 + end + + it "updates self's position" do + @io.send(@method, 'test') + @io.pos.should eql(4) + 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 + + 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.send(@method, "test") }.should raise_error(IOError) + + io = StringIO.new(+"test") + io.close_write + -> { io.send(@method, "test") }.should raise_error(IOError) + end +end + +describe :stringio_write_append, shared: true do + before :each do + @io = StringIO.new(+"example", "a") + end + + it "appends the passed argument to the end of self" do + @io.send(@method, ", just testing") + @io.string.should == "example, just testing" + + @io.send(@method, " and more testing") + @io.string.should == "example, just testing and more testing" + end + + it "correctly updates self's position" do + @io.send(@method, ", testing") + @io.pos.should eql(16) + end +end |
