diff options
Diffstat (limited to 'spec/ruby/library/stringio')
62 files changed, 1505 insertions, 1014 deletions
diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb index d0cf5550cd..c21ba00508 100644 --- a/spec/ruby/library/stringio/append_spec.rb +++ b/spec/ruby/library/stringio/append_spec.rb @@ -3,11 +3,11 @@ require_relative 'fixtures/classes' describe "StringIO#<< when passed [Object]" do before :each do - @io = StringIO.new("example") + @io = StringIO.new(+"example") end it "returns self" do - (@io << "just testing").should equal(@io) + (@io << "just testing").should.equal?(@io) end it "writes the passed argument onto self" do @@ -29,23 +29,9 @@ describe "StringIO#<< when passed [Object]" do @io.string.should == "example\000\000\000\000\000\000\000\000just testing" end - ruby_version_is ""..."2.7" do - it "taints self's String when the passed argument is tainted" do - (@io << "test".taint) - @io.string.tainted?.should be_true - end - end - - ruby_version_is ""..."3.0" do - it "does not taint self when the passed argument is tainted" do - (@io << "test".taint) - @io.tainted?.should be_false - end - end - it "updates self's position" do @io << "test" - @io.pos.should eql(4) + @io.pos.should.eql?(4) end it "tries to convert the passed argument to a String using #to_s" do @@ -58,18 +44,18 @@ end describe "StringIO#<< when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io << "test" }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io << "test" }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io << "test" }.should raise_error(IOError) + -> { io << "test" }.should.raise(IOError) end end describe "StringIO#<< when in append mode" 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, ignoring current position" do @@ -83,6 +69,6 @@ describe "StringIO#<< when in append mode" do it "correctly updates self's position" do @io << ", testing" - @io.pos.should eql(16) + @io.pos.should.eql?(16) end end diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb index 853d9c9bd6..bc7ccda0a2 100644 --- a/spec/ruby/library/stringio/binmode_spec.rb +++ b/spec/ruby/library/stringio/binmode_spec.rb @@ -3,8 +3,8 @@ require_relative 'fixtures/classes' describe "StringIO#binmode" do it "returns self" do - io = StringIO.new("example") - io.binmode.should equal(io) + io = StringIO.new(+"example") + io.binmode.should.equal?(io) end it "changes external encoding to BINARY" do diff --git a/spec/ruby/library/stringio/bytes_spec.rb b/spec/ruby/library/stringio/bytes_spec.rb deleted file mode 100644 index 4ef7a490a5..0000000000 --- a/spec/ruby/library/stringio/bytes_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require_relative '../../spec_helper' -require 'stringio' -require_relative 'shared/each_byte' - -ruby_version_is ''...'3.0' do - describe "StringIO#bytes" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_byte, :bytes - end - - describe "StringIO#bytes when self is not readable" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_byte_not_readable, :bytes - end -end diff --git a/spec/ruby/library/stringio/chars_spec.rb b/spec/ruby/library/stringio/chars_spec.rb deleted file mode 100644 index 58cba77634..0000000000 --- a/spec/ruby/library/stringio/chars_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require_relative '../../spec_helper' -require 'stringio' -require_relative 'shared/each_char' - -ruby_version_is ''...'3.0' do - describe "StringIO#chars" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_char, :chars - end - - describe "StringIO#chars when self is not readable" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_char_not_readable, :chars - end -end diff --git a/spec/ruby/library/stringio/close_read_spec.rb b/spec/ruby/library/stringio/close_read_spec.rb index 80bd547e85..dd46a927be 100644 --- a/spec/ruby/library/stringio/close_read_spec.rb +++ b/spec/ruby/library/stringio/close_read_spec.rb @@ -3,16 +3,16 @@ require_relative 'fixtures/classes' describe "StringIO#close_read" do before :each do - @io = StringIO.new("example") + @io = StringIO.new(+"example") end it "returns nil" do - @io.close_read.should be_nil + @io.close_read.should == nil end it "prevents further reading" do @io.close_read - -> { @io.read(1) }.should raise_error(IOError) + -> { @io.read(1) }.should.raise(IOError) end it "allows further writing" do @@ -21,8 +21,8 @@ describe "StringIO#close_read" do end it "raises an IOError when in write-only mode" do - io = StringIO.new("example", "w") - -> { io.close_read }.should raise_error(IOError) + io = StringIO.new(+"example", "w") + -> { io.close_read }.should.raise(IOError) io = StringIO.new("example") io.close_read diff --git a/spec/ruby/library/stringio/close_spec.rb b/spec/ruby/library/stringio/close_spec.rb index 520a8de782..6febd14a26 100644 --- a/spec/ruby/library/stringio/close_spec.rb +++ b/spec/ruby/library/stringio/close_spec.rb @@ -7,17 +7,17 @@ describe "StringIO#close" do end it "returns nil" do - @io.close.should be_nil + @io.close.should == nil end it "prevents further reading and/or writing" do @io.close - -> { @io.read(1) }.should raise_error(IOError) - -> { @io.write('x') }.should raise_error(IOError) + -> { @io.read(1) }.should.raise(IOError) + -> { @io.write('x') }.should.raise(IOError) end it "does not raise anything when self was already closed" do @io.close - -> { @io.close }.should_not raise_error(IOError) + -> { @io.close }.should_not.raise(IOError) end end diff --git a/spec/ruby/library/stringio/close_write_spec.rb b/spec/ruby/library/stringio/close_write_spec.rb index 1a4cfa113e..b74b996166 100644 --- a/spec/ruby/library/stringio/close_write_spec.rb +++ b/spec/ruby/library/stringio/close_write_spec.rb @@ -3,16 +3,16 @@ require_relative 'fixtures/classes' describe "StringIO#close_write" do before :each do - @io = StringIO.new("example") + @io = StringIO.new(+"example") end it "returns nil" do - @io.close_write.should be_nil + @io.close_write.should == nil end it "prevents further writing" do @io.close_write - -> { @io.write('x') }.should raise_error(IOError) + -> { @io.write('x') }.should.raise(IOError) end it "allows further reading" do @@ -21,10 +21,10 @@ describe "StringIO#close_write" do end it "raises an IOError when in read-only mode" do - io = StringIO.new("example", "r") - -> { io.close_write }.should raise_error(IOError) + io = StringIO.new(+"example", "r") + -> { io.close_write }.should.raise(IOError) - io = StringIO.new("example") + io = StringIO.new(+"example") io.close_write io.close_write.should == nil end diff --git a/spec/ruby/library/stringio/closed_read_spec.rb b/spec/ruby/library/stringio/closed_read_spec.rb index cb4267ac98..2e3813b1bc 100644 --- a/spec/ruby/library/stringio/closed_read_spec.rb +++ b/spec/ruby/library/stringio/closed_read_spec.rb @@ -3,10 +3,10 @@ require_relative 'fixtures/classes' describe "StringIO#closed_read?" do it "returns true if self is not readable" do - io = StringIO.new("example", "r+") + io = StringIO.new(+"example", "r+") io.close_write - io.closed_read?.should be_false + io.closed_read?.should == false io.close_read - io.closed_read?.should be_true + io.closed_read?.should == true end end diff --git a/spec/ruby/library/stringio/closed_spec.rb b/spec/ruby/library/stringio/closed_spec.rb index ca8a2232a8..647fe445da 100644 --- a/spec/ruby/library/stringio/closed_spec.rb +++ b/spec/ruby/library/stringio/closed_spec.rb @@ -3,14 +3,14 @@ require_relative 'fixtures/classes' describe "StringIO#closed?" do it "returns true if self is completely closed" do - io = StringIO.new("example", "r+") + io = StringIO.new(+"example", "r+") io.close_read - io.closed?.should be_false + io.closed?.should == false io.close_write - io.closed?.should be_true + io.closed?.should == true - io = StringIO.new("example", "r+") + io = StringIO.new(+"example", "r+") io.close - io.closed?.should be_true + io.closed?.should == true end end diff --git a/spec/ruby/library/stringio/closed_write_spec.rb b/spec/ruby/library/stringio/closed_write_spec.rb index 5c111affd8..339691cd82 100644 --- a/spec/ruby/library/stringio/closed_write_spec.rb +++ b/spec/ruby/library/stringio/closed_write_spec.rb @@ -3,10 +3,10 @@ require_relative 'fixtures/classes' describe "StringIO#closed_write?" do it "returns true if self is not writable" do - io = StringIO.new("example", "r+") + io = StringIO.new(+"example", "r+") io.close_read - io.closed_write?.should be_false + io.closed_write?.should == false io.close_write - io.closed_write?.should be_true + io.closed_write?.should == true end end diff --git a/spec/ruby/library/stringio/codepoints_spec.rb b/spec/ruby/library/stringio/codepoints_spec.rb deleted file mode 100644 index ceaadefc32..0000000000 --- a/spec/ruby/library/stringio/codepoints_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/codepoints' - -ruby_version_is ''...'3.0' do - # See redmine #1667 - describe "StringIO#codepoints" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_codepoints, :codepoints - end -end diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb index 1389408399..4ac0db7c45 100644 --- a/spec/ruby/library/stringio/each_line_spec.rb +++ b/spec/ruby/library/stringio/each_line_spec.rb @@ -17,3 +17,11 @@ end describe "StringIO#each_line when passed chomp" do it_behaves_like :stringio_each_chomp, :each_line end + +describe "StringIO#each_line when passed limit" do + it_behaves_like :stringio_each_limit, :each_line +end + +describe "StringIO#each when passed separator and limit" do + it_behaves_like :stringio_each_separator_and_limit, :each_line +end diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb index a76460049b..7eb322f3ff 100644 --- a/spec/ruby/library/stringio/each_spec.rb +++ b/spec/ruby/library/stringio/each_spec.rb @@ -17,3 +17,15 @@ end describe "StringIO#each when passed chomp" do it_behaves_like :stringio_each_chomp, :each end + +describe "StringIO#each when passed chomp" do + it_behaves_like :stringio_each_separator_and_chomp, :each +end + +describe "StringIO#each when passed limit" do + it_behaves_like :stringio_each_limit, :each +end + +describe "StringIO#each when passed separator and limit" do + it_behaves_like :stringio_each_separator_and_limit, :each +end diff --git a/spec/ruby/library/stringio/fcntl_spec.rb b/spec/ruby/library/stringio/fcntl_spec.rb index a78004d868..6108130db7 100644 --- a/spec/ruby/library/stringio/fcntl_spec.rb +++ b/spec/ruby/library/stringio/fcntl_spec.rb @@ -3,6 +3,6 @@ require_relative 'fixtures/classes' describe "StringIO#fcntl" do it "raises a NotImplementedError" do - -> { StringIO.new("boom").fcntl }.should raise_error(NotImplementedError) + -> { StringIO.new("boom").fcntl }.should.raise(NotImplementedError) end end diff --git a/spec/ruby/library/stringio/fileno_spec.rb b/spec/ruby/library/stringio/fileno_spec.rb index eea03a5af3..f5d1e83776 100644 --- a/spec/ruby/library/stringio/fileno_spec.rb +++ b/spec/ruby/library/stringio/fileno_spec.rb @@ -1,9 +1,8 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/each' +require 'stringio' describe "StringIO#fileno" do it "returns nil" do - StringIO.new("nuffin").fileno.should be_nil + StringIO.new("nuffin").fileno.should == nil end end diff --git a/spec/ruby/library/stringio/fixtures/classes.rb b/spec/ruby/library/stringio/fixtures/classes.rb index bb8dc354cc..832c5457d7 100644 --- a/spec/ruby/library/stringio/fixtures/classes.rb +++ b/spec/ruby/library/stringio/fixtures/classes.rb @@ -4,12 +4,12 @@ class StringSubclass < String; end module StringIOSpecs def self.build - str = <<-EOS + str = <<-EOS each peach pear plum - EOS + EOS StringIO.new(str) end end diff --git a/spec/ruby/library/stringio/flush_spec.rb b/spec/ruby/library/stringio/flush_spec.rb index 17a16dfdd5..48be44773c 100644 --- a/spec/ruby/library/stringio/flush_spec.rb +++ b/spec/ruby/library/stringio/flush_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#flush" do it "returns self" do - io = StringIO.new("flush") - io.flush.should equal(io) + io = StringIO.new(+"flush") + io.flush.should.equal?(io) end end diff --git a/spec/ruby/library/stringio/fsync_spec.rb b/spec/ruby/library/stringio/fsync_spec.rb index 8fb2b59a24..30fae15c8e 100644 --- a/spec/ruby/library/stringio/fsync_spec.rb +++ b/spec/ruby/library/stringio/fsync_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#fsync" do it "returns zero" do - io = StringIO.new("fsync") - io.fsync.should eql(0) + io = StringIO.new(+"fsync") + io.fsync.should.eql?(0) end end diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb index 97429e6a29..5dc572fba5 100644 --- a/spec/ruby/library/stringio/gets_spec.rb +++ b/spec/ruby/library/stringio/gets_spec.rb @@ -1,246 +1,61 @@ require_relative '../../spec_helper' require "stringio" +require_relative "shared/gets" -describe "StringIO#gets 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.gets(">").should == "this>" - @io.gets(">").should == "is>" - @io.gets(">").should == "an>" - @io.gets(">").should == "example" - end - - it "sets $_ to the read content" do - @io.gets(">") - $_.should == "this>" - @io.gets(">") - $_.should == "is>" - @io.gets(">") - $_.should == "an>" - @io.gets(">") - $_.should == "example" - @io.gets(">") - $_.should be_nil - end - - it "accepts string as separator" do - @io.gets("is>") - $_.should == "this>" - @io.gets("an>") - $_.should == "is>an>" - @io.gets("example") - $_.should == "example" - @io.gets("ple") - $_.should be_nil - end - - it "updates self's lineno by one" do - @io.gets(">") - @io.lineno.should eql(1) +describe "StringIO#gets" do + describe "when passed [separator]" do + it_behaves_like :stringio_gets_separator, :gets - @io.gets(">") - @io.lineno.should eql(2) + it "returns nil if self is at the end" do + @io = StringIO.new("this>is>an>example") - @io.gets(">") - @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.gets("").should == "this is\n\n" - io.gets("").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.gets(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.gets(obj).should == "this>" - end -end - -describe "StringIO#gets 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.gets.should == "this is\n" - - begin - old_sep = $/ - suppress_warning {$/ = " "} - @io.gets.should == "an " - @io.gets.should == "example\nfor " - @io.gets.should == "StringIO#gets" - ensure - suppress_warning {$/ = old_sep} + @io.pos = 36 + @io.gets(">").should == nil + @io.gets(">").should == nil end end - it "sets $_ to the read content" do - @io.gets - $_.should == "this is\n" - @io.gets - $_.should == "an example\n" - @io.gets - $_.should == "for StringIO#gets" - @io.gets - $_.should be_nil - end - - it "updates self's position" do - @io.gets - @io.pos.should eql(8) - - @io.gets - @io.pos.should eql(19) - - @io.gets - @io.pos.should eql(36) - end - - it "updates self's lineno" do - @io.gets - @io.lineno.should eql(1) - - @io.gets - @io.lineno.should eql(2) - - @io.gets - @io.lineno.should eql(3) - end - - it "returns nil if self is at the end" do - @io.pos = 36 - @io.gets.should be_nil - @io.gets.should be_nil - end -end - -describe "StringIO#gets 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.gets(4).should == "this" - @io.gets(3).should == ">is" - @io.gets(5).should == ">an>e" - @io.gets(6).should == "xample" - end + describe "when passed [limit]" do + it_behaves_like :stringio_gets_limit, :gets - it "sets $_ to the read content" do - @io.gets(4) - $_.should == "this" - @io.gets(3) - $_.should == ">is" - @io.gets(5) - $_.should == ">an>e" - @io.gets(6) - $_.should == "xample" - @io.gets(3) - $_.should be_nil - end + it "returns nil if self is at the end" do + @io = StringIO.new("this>is>an>example") - it "updates self's lineno by one" do - @io.gets(3) - @io.lineno.should eql(1) - - @io.gets(3) - @io.lineno.should eql(2) - - @io.gets(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.gets(obj).should == "this" - end - - it "returns a blank string when passed a limit of 0" do - @io.gets(0).should == "" - end -end - -describe "StringIO#gets 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.gets('>', 8).should == "this>" - @io.gets('>', 2).should == "is" - @io.gets('>', 10).should == ">" - @io.gets('>', 6).should == "an>" - @io.gets('>', 5).should == "examp" - end - - it "sets $_ to the read content" do - @io.gets('>', 8) - $_.should == "this>" - @io.gets('>', 2) - $_.should == "is" - @io.gets('>', 10) - $_.should == ">" - @io.gets('>', 6) - $_.should == "an>" - @io.gets('>', 5) - $_.should == "examp" + @io.pos = 36 + @io.gets(3).should == nil + @io.gets(3).should == nil + end end - it "updates self's lineno by one" do - @io.gets('>', 3) - @io.lineno.should eql(1) + describe "when passed [separator] and [limit]" do + it_behaves_like :stringio_gets_separator_and_limit, :gets - @io.gets('>', 3) - @io.lineno.should eql(2) + it "returns nil if self is at the end" do + @io = StringIO.new("this>is>an>example") - @io.gets('>', 3) - @io.lineno.should eql(3) + @io.pos = 36 + @io.gets(">", 3).should == nil + @io.gets(">", 3).should == nil + end 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.gets(obj, 5).should == "this>" - end + describe "when passed no argument" do + it_behaves_like :stringio_gets_no_argument, :gets - it "does not raise TypeError if passed separator is nil" do - @io.gets(nil, 5).should == "this>" - end + it "returns nil if self is at the end" do + @io = StringIO.new("this>is>an>example") - 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.gets('>', obj).should == "this>" + @io.pos = 36 + @io.gets.should == nil + @io.gets.should == nil + end end -end - -describe "StringIO#gets when in write-only mode" do - it "raises an IOError" do - io = StringIO.new("xyz", "w") - -> { io.gets }.should raise_error(IOError) - io = StringIO.new("xyz") - io.close_read - -> { io.gets }.should raise_error(IOError) + describe "when passed [chomp]" do + it_behaves_like :stringio_gets_chomp, :gets end -end -describe "StringIO#gets when passed [chomp]" do - it "returns the data read without a trailing newline character" do - io = StringIO.new("this>is>an>example\n") - io.gets(chomp: true).should == "this>is>an>example" + describe "when in write-only mode" do + it_behaves_like :stringio_gets_write_only, :gets end end diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb index 1e8096e3bb..413e0aacc0 100644 --- a/spec/ruby/library/stringio/initialize_spec.rb +++ b/spec/ruby/library/stringio/initialize_spec.rb @@ -8,127 +8,147 @@ describe "StringIO#initialize when passed [Object, mode]" do it "uses the passed Object as the StringIO backend" do @io.send(:initialize, str = "example", "r") - @io.string.should equal(str) + @io.string.should.equal?(str) end it "sets the mode based on the passed mode" do io = StringIO.allocate - io.send(:initialize, "example", "r") - io.closed_read?.should be_false - io.closed_write?.should be_true + io.send(:initialize, +"example", "r") + io.closed_read?.should == false + io.closed_write?.should == true io = StringIO.allocate - io.send(:initialize, "example", "rb") - io.closed_read?.should be_false - io.closed_write?.should be_true + io.send(:initialize, +"example", "rb") + io.closed_read?.should == false + io.closed_write?.should == true io = StringIO.allocate - io.send(:initialize, "example", "r+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "r+") + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "rb+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "rb+") + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "w") - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", "w") + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "wb") - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", "wb") + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "w+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "w+") + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "wb+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "wb+") + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "a") - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", "a") + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "ab") - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", "ab") + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "a+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "a+") + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", "ab+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", "ab+") + io.closed_read?.should == false + io.closed_write?.should == false end it "allows passing the mode as an Integer" do io = StringIO.allocate - io.send(:initialize, "example", IO::RDONLY) - io.closed_read?.should be_false - io.closed_write?.should be_true + io.send(:initialize, +"example", IO::RDONLY) + io.closed_read?.should == false + io.closed_write?.should == true io = StringIO.allocate - io.send(:initialize, "example", IO::RDWR) - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::RDWR) + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", IO::WRONLY) - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::WRONLY) + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", IO::WRONLY | IO::TRUNC) - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::WRONLY | IO::TRUNC) + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", IO::RDWR | IO::TRUNC) - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::RDWR | IO::TRUNC) + io.closed_read?.should == false + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", IO::WRONLY | IO::APPEND) - io.closed_read?.should be_true - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::WRONLY | IO::APPEND) + io.closed_read?.should == true + io.closed_write?.should == false io = StringIO.allocate - io.send(:initialize, "example", IO::RDWR | IO::APPEND) - io.closed_read?.should be_false - io.closed_write?.should be_false + io.send(:initialize, +"example", IO::RDWR | IO::APPEND) + io.closed_read?.should == false + io.closed_write?.should == false end it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do io = StringIO.allocate - -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should raise_error(FrozenError) + -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should.raise(FrozenError) end it "tries to convert the passed mode to a String using #to_str" do obj = mock('to_str') obj.should_receive(:to_str).and_return("r") - @io.send(:initialize, "example", obj) + @io.send(:initialize, +"example", obj) - @io.closed_read?.should be_false - @io.closed_write?.should be_true + @io.closed_read?.should == false + @io.closed_write?.should == true end it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do (str = "example").freeze - -> { @io.send(:initialize, str, "r+") }.should raise_error(Errno::EACCES) - -> { @io.send(:initialize, str, "w") }.should raise_error(Errno::EACCES) - -> { @io.send(:initialize, str, "a") }.should raise_error(Errno::EACCES) + -> { @io.send(:initialize, str, "r+") }.should.raise(Errno::EACCES) + -> { @io.send(:initialize, str, "w") }.should.raise(Errno::EACCES) + -> { @io.send(:initialize, str, "a") }.should.raise(Errno::EACCES) + end + + it "truncates all the content if passed w mode" do + io = StringIO.allocate + source = +"example".encode(Encoding::ISO_8859_1); + + io.send(:initialize, source, "w") + + io.string.should.empty? + io.string.encoding.should == Encoding::ISO_8859_1 + end + + it "truncates all the content if passed IO::TRUNC mode" do + io = StringIO.allocate + source = +"example".encode(Encoding::ISO_8859_1); + + io.send(:initialize, source, IO::TRUNC) + + io.string.should.empty? + io.string.encoding.should == Encoding::ISO_8859_1 end end @@ -139,13 +159,19 @@ describe "StringIO#initialize when passed [Object]" do it "uses the passed Object as the StringIO backend" do @io.send(:initialize, str = "example") - @io.string.should equal(str) + @io.string.should.equal?(str) end - it "sets the mode to read-write" do - @io.send(:initialize, "example") - @io.closed_read?.should be_false - @io.closed_write?.should be_false + it "sets the mode to read-write if the string is mutable" do + @io.send(:initialize, +"example") + @io.closed_read?.should == false + @io.closed_write?.should == false + end + + it "sets the mode to read if the string is frozen" do + @io.send(:initialize, -"example") + @io.closed_read?.should == false + @io.closed_write?.should == true end it "tries to convert the passed Object to a String using #to_str" do @@ -158,8 +184,93 @@ describe "StringIO#initialize when passed [Object]" do it "automatically sets the mode to read-only when passed a frozen string" do (str = "example").freeze @io.send(:initialize, str) - @io.closed_read?.should be_false - @io.closed_write?.should be_true + @io.closed_read?.should == false + @io.closed_write?.should == true + end +end + +# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb) +describe "StringIO#initialize when passed keyword arguments" do + it "sets the mode based on the passed :mode option" do + io = StringIO.new("example", mode: "r") + io.closed_read?.should == false + io.closed_write?.should == true + end + + it "accepts a mode argument set to nil with a valid :mode option" do + @io = StringIO.new(+'', nil, mode: "w") + @io.write("foo").should == 3 + end + + it "accepts a mode argument with a :mode option set to nil" do + @io = StringIO.new(+'', "w", mode: nil) + @io.write("foo").should == 3 + end + + it "sets binmode from :binmode option" do + @io = StringIO.new(+'', 'w', binmode: true) + @io.external_encoding.to_s.should == "ASCII-8BIT" # #binmode? isn't implemented in StringIO + end + + it "does not set binmode from false :binmode" do + @io = StringIO.new(+'', 'w', binmode: false) + @io.external_encoding.to_s.should == "UTF-8" # #binmode? isn't implemented in StringIO + end +end + +# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb) +describe "StringIO#initialize when passed keyword arguments and error happens" do + it "raises an error if passed encodings two ways" do + -> { + @io = StringIO.new(+'', 'w:ISO-8859-1', encoding: 'ISO-8859-1') + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1') + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1') + }.should.raise(ArgumentError) + end + + it "raises an error if passed matching binary/text mode two ways" do + -> { + @io = StringIO.new(+'', "wb", binmode: true) + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', "wt", textmode: true) + }.should.raise(ArgumentError) + + -> { + @io = StringIO.new(+'', "wb", textmode: false) + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', "wt", binmode: false) + }.should.raise(ArgumentError) + end + + it "raises an error if passed conflicting binary/text mode two ways" do + -> { + @io = StringIO.new(+'', "wb", binmode: false) + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', "wt", textmode: false) + }.should.raise(ArgumentError) + + -> { + @io = StringIO.new(+'', "wb", textmode: true) + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', "wt", binmode: true) + }.should.raise(ArgumentError) + end + + it "raises an error when trying to set both binmode and textmode" do + -> { + @io = StringIO.new(+'', "w", textmode: true, binmode: true) + }.should.raise(ArgumentError) + -> { + @io = StringIO.new(+'', File::Constants::WRONLY, textmode: true, binmode: true) + }.should.raise(ArgumentError) end end @@ -169,13 +280,13 @@ describe "StringIO#initialize when passed no arguments" do end it "is private" do - StringIO.should have_private_instance_method(:initialize) + StringIO.private_instance_methods(false).should.include?(:initialize) end it "sets the mode to read-write" do - @io.send(:initialize, "example") - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.send(:initialize) + @io.closed_read?.should == false + @io.closed_write?.should == false end it "uses an empty String as the StringIO backend" do @@ -204,19 +315,14 @@ describe "StringIO#initialize sets" do end it "the encoding to the encoding of the String when passed a String" do - s = ''.force_encoding(Encoding::EUC_JP) + s = ''.dup.force_encoding(Encoding::EUC_JP) io = StringIO.new(s) io.string.encoding.should == Encoding::EUC_JP end - guard_not -> { # [Bug #16497] - stringio_version = StringIO.const_defined?(:VERSION) ? StringIO::VERSION : "0.0.2" - version_is(stringio_version, "0.0.3"..."0.1.1") - } do - it "the #external_encoding to the encoding of the String when passed a String" do - s = ''.force_encoding(Encoding::EUC_JP) - io = StringIO.new(s) - io.external_encoding.should == Encoding::EUC_JP - end + it "the #external_encoding to the encoding of the String when passed a String" do + s = ''.dup.force_encoding(Encoding::EUC_JP) + io = StringIO.new(s) + io.external_encoding.should == Encoding::EUC_JP end end diff --git a/spec/ruby/library/stringio/inspect_spec.rb b/spec/ruby/library/stringio/inspect_spec.rb index 7c02f8d360..962d858e48 100644 --- a/spec/ruby/library/stringio/inspect_spec.rb +++ b/spec/ruby/library/stringio/inspect_spec.rb @@ -9,7 +9,7 @@ describe "StringIO#inspect" do it "does not include the contents" do io = StringIO.new("contents") - io.inspect.should_not include("contents") + io.inspect.should_not.include?("contents") end it "uses the regular Object#inspect without any instance variable" do diff --git a/spec/ruby/library/stringio/lineno_spec.rb b/spec/ruby/library/stringio/lineno_spec.rb index c620a1a686..a96dc05927 100644 --- a/spec/ruby/library/stringio/lineno_spec.rb +++ b/spec/ruby/library/stringio/lineno_spec.rb @@ -10,7 +10,7 @@ describe "StringIO#lineno" do @io.gets @io.gets @io.gets - @io.lineno.should eql(3) + @io.lineno.should.eql?(3) end end @@ -21,10 +21,10 @@ describe "StringIO#lineno=" do it "sets the current line number, but has no impact on the position" do @io.lineno = 3 - @io.pos.should eql(0) + @io.pos.should.eql?(0) @io.gets.should == "this\n" - @io.lineno.should eql(4) - @io.pos.should eql(5) + @io.lineno.should.eql?(4) + @io.pos.should.eql?(5) end end diff --git a/spec/ruby/library/stringio/lines_spec.rb b/spec/ruby/library/stringio/lines_spec.rb deleted file mode 100644 index 42d11772ae..0000000000 --- a/spec/ruby/library/stringio/lines_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require_relative '../../spec_helper' -require 'stringio' -require_relative 'shared/each' - -ruby_version_is ''...'3.0' do - describe "StringIO#lines when passed a separator" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_separator, :lines - end - - describe "StringIO#lines when passed no arguments" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_no_arguments, :lines - end - - describe "StringIO#lines when self is not readable" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_not_readable, :lines - end - - describe "StringIO#lines when passed chomp" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - end - - after :each do - $VERBOSE = @verbose - end - - it_behaves_like :stringio_each_chomp, :lines - end -end diff --git a/spec/ruby/library/stringio/new_spec.rb b/spec/ruby/library/stringio/new_spec.rb new file mode 100644 index 0000000000..ec4b32aa11 --- /dev/null +++ b/spec/ruby/library/stringio/new_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../spec_helper' +require 'stringio' + +describe "StringIO.new" do + it "does not use the given block and warns to use StringIO::open" do + -> { + StringIO.new { raise } + }.should complain(/warning: StringIO::new\(\) does not take block; use StringIO::open\(\) instead/) + end +end diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb index acab6e9056..23c7b34e09 100644 --- a/spec/ruby/library/stringio/open_spec.rb +++ b/spec/ruby/library/stringio/open_spec.rb @@ -4,173 +4,177 @@ require 'stringio' describe "StringIO.open when passed [Object, mode]" do it "uses the passed Object as the StringIO backend" do io = StringIO.open(str = "example", "r") - io.string.should equal(str) + io.string.should.equal?(str) end it "returns the blocks return value when yielding" do - ret = StringIO.open("example", "r") { :test } - ret.should equal(:test) + ret = StringIO.open(+"example", "r") { :test } + ret.should.equal?(:test) end it "yields self to the passed block" do io = nil - StringIO.open("example", "r") { |strio| io = strio } - io.should be_kind_of(StringIO) + StringIO.open(+"example", "r") { |strio| io = strio } + io.should.is_a?(StringIO) end it "closes self after yielding" do io = nil - StringIO.open("example", "r") { |strio| io = strio } - io.closed?.should be_true + StringIO.open(+"example", "r") { |strio| io = strio } + io.closed?.should == true end it "even closes self when an exception is raised while yielding" do io = nil begin - StringIO.open("example", "r") do |strio| + StringIO.open(+"example", "r") do |strio| io = strio raise "Error" end rescue end - io.closed?.should be_true + io.closed?.should == true end it "sets self's string to nil after yielding" do io = nil - StringIO.open("example", "r") { |strio| io = strio } - io.string.should be_nil + StringIO.open(+"example", "r") { |strio| io = strio } + io.string.should == nil end it "even sets self's string to nil when an exception is raised while yielding" do io = nil begin - StringIO.open("example", "r") do |strio| + StringIO.open(+"example", "r") do |strio| io = strio raise "Error" end rescue end - io.string.should be_nil + io.string.should == nil end it "sets the mode based on the passed mode" do - io = StringIO.open("example", "r") - io.closed_read?.should be_false - io.closed_write?.should be_true + io = StringIO.open(+"example", "r") + io.closed_read?.should == false + io.closed_write?.should == true - io = StringIO.open("example", "rb") - io.closed_read?.should be_false - io.closed_write?.should be_true + io = StringIO.open(+"example", "rb") + io.closed_read?.should == false + io.closed_write?.should == true - io = StringIO.open("example", "r+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "r+") + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", "rb+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "rb+") + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", "w") - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", "w") + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", "wb") - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", "wb") + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", "w+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "w+") + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", "wb+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "wb+") + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", "a") - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", "a") + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", "ab") - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", "ab") + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", "a+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "a+") + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", "ab+") - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", "ab+") + io.closed_read?.should == false + io.closed_write?.should == false end it "allows passing the mode as an Integer" do - io = StringIO.open("example", IO::RDONLY) - io.closed_read?.should be_false - io.closed_write?.should be_true + io = StringIO.open(+"example", IO::RDONLY) + io.closed_read?.should == false + io.closed_write?.should == true - io = StringIO.open("example", IO::RDWR) - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::RDWR) + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", IO::WRONLY) - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::WRONLY) + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", IO::WRONLY | IO::TRUNC) - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::WRONLY | IO::TRUNC) + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", IO::RDWR | IO::TRUNC) - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::RDWR | IO::TRUNC) + io.closed_read?.should == false + io.closed_write?.should == false - io = StringIO.open("example", IO::WRONLY | IO::APPEND) - io.closed_read?.should be_true - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::WRONLY | IO::APPEND) + io.closed_read?.should == true + io.closed_write?.should == false - io = StringIO.open("example", IO::RDWR | IO::APPEND) - io.closed_read?.should be_false - io.closed_write?.should be_false + io = StringIO.open(+"example", IO::RDWR | IO::APPEND) + io.closed_read?.should == false + io.closed_write?.should == false end it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do - -> { StringIO.open("example".freeze, IO::TRUNC) }.should raise_error(FrozenError) + -> { StringIO.open("example".freeze, IO::TRUNC) }.should.raise(FrozenError) end it "tries to convert the passed mode to a String using #to_str" do obj = mock('to_str') obj.should_receive(:to_str).and_return("r") - io = StringIO.open("example", obj) + io = StringIO.open(+"example", obj) - io.closed_read?.should be_false - io.closed_write?.should be_true + io.closed_read?.should == false + io.closed_write?.should == true end it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do (str = "example").freeze - -> { StringIO.open(str, "r+") }.should raise_error(Errno::EACCES) - -> { StringIO.open(str, "w") }.should raise_error(Errno::EACCES) - -> { StringIO.open(str, "a") }.should raise_error(Errno::EACCES) + -> { StringIO.open(str, "r+") }.should.raise(Errno::EACCES) + -> { StringIO.open(str, "w") }.should.raise(Errno::EACCES) + -> { StringIO.open(str, "a") }.should.raise(Errno::EACCES) end end describe "StringIO.open when passed [Object]" do it "uses the passed Object as the StringIO backend" do io = StringIO.open(str = "example") - io.string.should equal(str) + io.string.should.equal?(str) end it "yields self to the passed block" do io = nil - ret = StringIO.open("example") { |strio| io = strio } - io.should equal(ret) + ret = StringIO.open(+"example") { |strio| io = strio } + io.should.equal?(ret) end - it "sets the mode to read-write" do - io = StringIO.open("example") - io.closed_read?.should be_false - io.closed_write?.should be_false + it "sets the mode to read-write (r+)" do + io = StringIO.open(+"example") + io.closed_read?.should == false + io.closed_write?.should == false + + io = StringIO.new(+"example") + io.printf("%d", 123) + io.string.should == "123mple" end it "tries to convert the passed Object to a String using #to_str" do @@ -183,8 +187,8 @@ describe "StringIO.open when passed [Object]" do it "automatically sets the mode to read-only when passed a frozen string" do (str = "example").freeze io = StringIO.open(str) - io.closed_read?.should be_false - io.closed_write?.should be_true + io.closed_read?.should == false + io.closed_write?.should == true end end @@ -192,13 +196,17 @@ describe "StringIO.open when passed no arguments" do it "yields self to the passed block" do io = nil ret = StringIO.open { |strio| io = strio } - io.should equal(ret) + io.should.equal?(ret) end - it "sets the mode to read-write" do + it "sets the mode to read-write (r+)" do io = StringIO.open - io.closed_read?.should be_false - io.closed_write?.should be_false + io.closed_read?.should == false + io.closed_write?.should == false + + io = StringIO.new(+"example") + io.printf("%d", 123) + io.string.should == "123mple" end it "uses an empty String as the StringIO backend" do diff --git a/spec/ruby/library/stringio/path_spec.rb b/spec/ruby/library/stringio/path_spec.rb index 1184ca523f..dcb77b1df8 100644 --- a/spec/ruby/library/stringio/path_spec.rb +++ b/spec/ruby/library/stringio/path_spec.rb @@ -3,6 +3,6 @@ require_relative 'fixtures/classes' describe "StringIO#path" do it "is not defined" do - -> { StringIO.new("path").path }.should raise_error(NoMethodError) + -> { StringIO.new("path").path }.should.raise(NoMethodError) end end diff --git a/spec/ruby/library/stringio/pid_spec.rb b/spec/ruby/library/stringio/pid_spec.rb index 08f2d7ab1a..7a729fbe41 100644 --- a/spec/ruby/library/stringio/pid_spec.rb +++ b/spec/ruby/library/stringio/pid_spec.rb @@ -3,6 +3,6 @@ require_relative 'fixtures/classes' describe "StringIO#pid" do it "returns nil" do - StringIO.new("pid").pid.should be_nil + StringIO.new("pid").pid.should == nil end end diff --git a/spec/ruby/library/stringio/pos_spec.rb b/spec/ruby/library/stringio/pos_spec.rb index 81be5f01a5..ba640f8c18 100644 --- a/spec/ruby/library/stringio/pos_spec.rb +++ b/spec/ruby/library/stringio/pos_spec.rb @@ -17,7 +17,7 @@ describe "StringIO#pos=" do end it "raises an EINVAL if given a negative argument" do - -> { @io.pos = -10 }.should raise_error(Errno::EINVAL) + -> { @io.pos = -10 }.should.raise(Errno::EINVAL) end it "updates the current byte offset after reaching EOF" do diff --git a/spec/ruby/library/stringio/print_spec.rb b/spec/ruby/library/stringio/print_spec.rb index 6ac6430900..48728e5f14 100644 --- a/spec/ruby/library/stringio/print_spec.rb +++ b/spec/ruby/library/stringio/print_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#print" do before :each do - @io = StringIO.new('example') + @io = StringIO.new(+'example') end it "prints $_ when passed no arguments" do @@ -29,7 +29,7 @@ describe "StringIO#print" do end it "returns nil" do - @io.print(1, 2, 3).should be_nil + @io.print(1, 2, 3).should == nil end it "pads self with \\000 when the current position is after the end" do @@ -52,10 +52,10 @@ describe "StringIO#print" do it "updates the current position" do @io.print(1, 2, 3) - @io.pos.should eql(3) + @io.pos.should.eql?(3) @io.print(1, 2, 3) - @io.pos.should eql(6) + @io.pos.should.eql?(6) end it "correctly updates the current position when honoring the output record separator global" do @@ -64,7 +64,7 @@ describe "StringIO#print" do begin @io.print(5, 6, 7, 8) - @io.pos.should eql(5) + @io.pos.should.eql?(5) ensure suppress_warning {$\ = old_rs} end @@ -73,7 +73,7 @@ end describe "StringIO#print when in append mode" 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 @@ -86,17 +86,17 @@ describe "StringIO#print when in append mode" do it "correctly updates self's position" do @io.print(", testing") - @io.pos.should eql(16) + @io.pos.should.eql?(16) end end describe "StringIO#print when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io.print("test") }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.print("test") }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.print("test") }.should raise_error(IOError) + -> { io.print("test") }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb index 9dd1a3b410..ae7e0af729 100644 --- a/spec/ruby/library/stringio/printf_spec.rb +++ b/spec/ruby/library/stringio/printf_spec.rb @@ -4,17 +4,17 @@ require_relative '../../core/kernel/shared/sprintf' describe "StringIO#printf" do before :each do - @io = StringIO.new('example') + @io = StringIO.new() end it "returns nil" do - @io.printf("%d %04x", 123, 123).should be_nil + @io.printf("%d %04x", 123, 123).should == nil end it "pads self with \\000 when the current position is after the end" do - @io.pos = 10 + @io.pos = 3 @io.printf("%d", 123) - @io.string.should == "example\000\000\000123" + @io.string.should == "\000\000\000123" end it "performs format conversion" do @@ -24,10 +24,10 @@ describe "StringIO#printf" do it "updates the current position" do @io.printf("%d %04x", 123, 123) - @io.pos.should eql(8) + @io.pos.should.eql?(8) @io.printf("%d %04x", 123, 123) - @io.pos.should eql(16) + @io.pos.should.eql?(16) end describe "formatting" do @@ -39,9 +39,30 @@ describe "StringIO#printf" do end end +describe "StringIO#printf when in read-write mode" do + before :each do + @io = StringIO.new(+"example", "r+") + end + + it "starts from the beginning" do + @io.printf("%s", "abcdefghijk") + @io.string.should == "abcdefghijk" + end + + it "does not truncate existing string" do + @io.printf("%s", "abc") + @io.string.should == "abcmple" + end + + it "correctly updates self's position" do + @io.printf("%s", "abc") + @io.pos.should.eql?(3) + end +end + describe "StringIO#printf when in append mode" 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 @@ -54,17 +75,17 @@ describe "StringIO#printf when in append mode" do it "correctly updates self's position" do @io.printf("%d %04x", 123, 123) - @io.pos.should eql(15) + @io.pos.should.eql?(15) end end describe "StringIO#printf when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io.printf("test") }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.printf("test") }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.printf("test") }.should raise_error(IOError) + -> { io.printf("test") }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb index 223b3523e5..742f8623eb 100644 --- a/spec/ruby/library/stringio/putc_spec.rb +++ b/spec/ruby/library/stringio/putc_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#putc when passed [String]" do before :each do - @io = StringIO.new('example') + @io = StringIO.new(+'example') end it "overwrites the character at the current position" do @@ -22,7 +22,7 @@ describe "StringIO#putc when passed [String]" do it "returns the passed String" do str = "test" - @io.putc(str).should equal(str) + @io.putc(str).should.equal?(str) end it "correctly updates the current position" do @@ -35,11 +35,26 @@ describe "StringIO#putc when passed [String]" do @io.putc("t") @io.pos.should == 3 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.putc i.to_s + } + } + go = true + threads.each(&:join) + @io.string.size.should == n + end end describe "StringIO#putc when passed [Object]" do before :each do - @io = StringIO.new('example') + @io = StringIO.new(+'example') end it "it writes the passed Integer % 256 to self" do @@ -64,13 +79,13 @@ describe "StringIO#putc when passed [Object]" do end it "raises a TypeError when the passed argument can't be coerced to Integer" do - -> { @io.putc(Object.new) }.should raise_error(TypeError) + -> { @io.putc(Object.new) }.should.raise(TypeError) end end describe "StringIO#putc when in append mode" do it "appends to the end of self" do - io = StringIO.new("test", "a") + io = StringIO.new(+"test", "a") io.putc(?t) io.string.should == "testt" end @@ -78,11 +93,11 @@ end describe "StringIO#putc when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io.putc(?a) }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.putc(?a) }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.putc("t") }.should raise_error(IOError) + -> { io.putc("t") }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb index a9f289a5a5..ebe74d4a45 100644 --- a/spec/ruby/library/stringio/puts_spec.rb +++ b/spec/ruby/library/stringio/puts_spec.rb @@ -101,6 +101,20 @@ describe "StringIO#puts when passed 1 or more objects" do @io.puts '' @io.string.should == "\n" end + + it "handles concurrent writes correctly" do + n = 8 + go = false + threads = n.times.map { |i| + Thread.new { + Thread.pass until go + @io.puts i + } + } + go = true + threads.each(&:join) + @io.string.size.should == n.times.map { |i| "#{i}\n" }.join.size + end end describe "StringIO#puts when passed no arguments" do @@ -109,7 +123,7 @@ describe "StringIO#puts when passed no arguments" do end it "returns nil" do - @io.puts.should be_nil + @io.puts.should == nil end it "prints a newline" do @@ -131,7 +145,7 @@ end describe "StringIO#puts when in append mode" 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 @@ -144,24 +158,24 @@ describe "StringIO#puts when in append mode" do it "correctly updates self's position" do @io.puts(", testing") - @io.pos.should eql(17) + @io.pos.should.eql?(17) end end describe "StringIO#puts when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io.puts }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.puts }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.puts }.should raise_error(IOError) + -> { io.puts }.should.raise(IOError) end end describe "StringIO#puts when passed an encoded string" do it "stores the bytes unmodified" do - io = StringIO.new("") + io = StringIO.new(+"") io.puts "\x00\x01\x02" io.puts "æåø" diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb index 2a8f926bd0..38ae7541ca 100644 --- a/spec/ruby/library/stringio/read_nonblock_spec.rb +++ b/spec/ruby/library/stringio/read_nonblock_spec.rb @@ -5,10 +5,21 @@ require_relative 'shared/sysread' describe "StringIO#read_nonblock when passed length, buffer" do it_behaves_like :stringio_read, :read_nonblock + + it "accepts :exception option" do + io = StringIO.new("example") + io.read_nonblock(3, buffer = +"", exception: true) + buffer.should == "exa" + end end describe "StringIO#read_nonblock when passed length" do it_behaves_like :stringio_read_length, :read_nonblock + + it "accepts :exception option" do + io = StringIO.new("example") + io.read_nonblock(3, exception: true).should == "exa" + end end describe "StringIO#read_nonblock when passed nil" do @@ -29,12 +40,12 @@ describe "StringIO#read_nonblock" do context "when exception option is set to false" do context "when the end is reached" do it "returns nil" do - stringio = StringIO.new('') + stringio = StringIO.new(+'') stringio << "hello" stringio.rewind stringio.read_nonblock(5).should == "hello" - stringio.read_nonblock(5, exception: false).should be_nil + stringio.read_nonblock(5, exception: false).should == nil end end end diff --git a/spec/ruby/library/stringio/read_spec.rb b/spec/ruby/library/stringio/read_spec.rb index 52ab3dcf47..9a2086a682 100644 --- a/spec/ruby/library/stringio/read_spec.rb +++ b/spec/ruby/library/stringio/read_spec.rb @@ -39,7 +39,7 @@ describe "StringIO#read when passed [length]" do it "returns nil when self's position is at the end" do @io.pos = 7 - @io.read(10).should be_nil + @io.read(10).should == nil end it "returns an empty String when length is 0" do @@ -53,10 +53,10 @@ describe "StringIO#read when passed length and a buffer" do end it "reads [length] characters into the buffer" do - buf = "foo" + buf = +"foo" result = @io.read(10, buf) buf.should == "abcdefghij" - result.should equal(buf) + result.should.equal?(buf) end end diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb index 94b67bc92d..3f026080e2 100644 --- a/spec/ruby/library/stringio/readline_spec.rb +++ b/spec/ruby/library/stringio/readline_spec.rb @@ -1,130 +1,58 @@ require_relative '../../spec_helper' +require "stringio" require_relative 'fixtures/classes' +require_relative "shared/gets" +describe "StringIO#readline" do + describe "when passed [separator]" do + it_behaves_like :stringio_gets_separator, :readline -describe "StringIO#readline 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.readline(">").should == "this>" - @io.readline(">").should == "is>" - @io.readline(">").should == "an>" - @io.readline(">").should == "example" - end - - it "sets $_ to the read content" do - @io.readline(">") - $_.should == "this>" - @io.readline(">") - $_.should == "is>" - @io.readline(">") - $_.should == "an>" - @io.readline(">") - $_.should == "example" - end - - it "updates self's lineno by one" do - @io.readline(">") - @io.lineno.should eql(1) - - @io.readline(">") - @io.lineno.should eql(2) - - @io.readline(">") - @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.readline("").should == "this is\n\n" - io.readline("").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.readline(nil).should == "is\n\nan example" - end + it "raises an IOError if self is at the end" do + @io = StringIO.new("this>is>an>example") - 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.readline(obj).should == "this>" + @io.pos = 36 + -> { @io.readline(">") }.should.raise(IOError) + end end -end -describe "StringIO#readline when passed no argument" do - before :each do - @io = StringIO.new("this is\nan example\nfor StringIO#readline") - end + describe "when passed [limit]" do + it_behaves_like :stringio_gets_limit, :readline - it "returns the data read till the next occurrence of $/ or till eof" do - @io.readline.should == "this is\n" + it "raises an IOError if self is at the end" do + @io = StringIO.new("this>is>an>example") - begin - old_sep = $/ - suppress_warning {$/ = " "} - @io.readline.should == "an " - @io.readline.should == "example\nfor " - @io.readline.should == "StringIO#readline" - ensure - suppress_warning {$/ = old_sep} + @io.pos = 36 + -> { @io.readline(3) }.should.raise(IOError) end end - it "sets $_ to the read content" do - @io.readline - $_.should == "this is\n" - @io.readline - $_.should == "an example\n" - @io.readline - $_.should == "for StringIO#readline" - end - - it "updates self's position" do - @io.readline - @io.pos.should eql(8) + describe "when passed [separator] and [limit]" do + it_behaves_like :stringio_gets_separator_and_limit, :readline - @io.readline - @io.pos.should eql(19) + it "raises an IOError if self is at the end" do + @io = StringIO.new("this>is>an>example") - @io.readline - @io.pos.should eql(40) + @io.pos = 36 + -> { @io.readline(">", 3) }.should.raise(IOError) + end end - it "updates self's lineno" do - @io.readline - @io.lineno.should eql(1) + describe "when passed no argument" do + it_behaves_like :stringio_gets_no_argument, :readline - @io.readline - @io.lineno.should eql(2) + it "raises an IOError if self is at the end" do + @io = StringIO.new("this>is>an>example") - @io.readline - @io.lineno.should eql(3) - end - - it "raises an IOError if self is at the end" do - @io.pos = 40 - -> { @io.readline }.should raise_error(IOError) + @io.pos = 36 + -> { @io.readline }.should.raise(IOError) + end end -end - -describe "StringIO#readline when in write-only mode" do - it "raises an IOError" do - io = StringIO.new("xyz", "w") - -> { io.readline }.should raise_error(IOError) - io = StringIO.new("xyz") - io.close_read - -> { io.readline }.should raise_error(IOError) + describe "when passed [chomp]" do + it_behaves_like :stringio_gets_chomp, :readline end -end -describe "StringIO#readline when passed [chomp]" do - it "returns the data read without a trailing newline character" do - io = StringIO.new("this>is>an>example\n") - io.readline(chomp: true).should == "this>is>an>example" + describe "when in write-only mode" do + it_behaves_like :stringio_gets_write_only, :readline end end diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb index 4b007787e2..821a8169e7 100644 --- a/spec/ruby/library/stringio/readlines_spec.rb +++ b/spec/ruby/library/stringio/readlines_spec.rb @@ -12,12 +12,12 @@ describe "StringIO#readlines when passed [separator]" do it "updates self's position based on the number of read bytes" do @io.readlines(">") - @io.pos.should eql(18) + @io.pos.should.eql?(18) end it "updates self's lineno based on the number of read lines" do @io.readlines(">") - @io.lineno.should eql(4) + @io.lineno.should.eql?(4) end it "does not change $_" do @@ -61,12 +61,12 @@ describe "StringIO#readlines when passed no argument" do it "updates self's position based on the number of read bytes" do @io.readlines - @io.pos.should eql(41) + @io.pos.should.eql?(41) end it "updates self's lineno based on the number of read lines" do @io.readlines - @io.lineno.should eql(3) + @io.lineno.should.eql?(3) end it "does not change $_" do @@ -83,12 +83,12 @@ end describe "StringIO#readlines when in write-only mode" do it "raises an IOError" do - io = StringIO.new("xyz", "w") - -> { io.readlines }.should raise_error(IOError) + io = StringIO.new(+"xyz", "w") + -> { io.readlines }.should.raise(IOError) io = StringIO.new("xyz") io.close_read - -> { io.readlines }.should raise_error(IOError) + -> { io.readlines }.should.raise(IOError) end end @@ -98,3 +98,21 @@ describe "StringIO#readlines when passed [chomp]" do io.readlines(chomp: true).should == ["this>is", "an>example"] end end + +describe "StringIO#readlines when passed [limit]" 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 + @io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] + end + + it "raises ArgumentError when limit is 0" do + -> { @io.readlines(0) }.should.raise(ArgumentError) + end + + it "ignores it when the limit is negative" do + @io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"] + end +end diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb index 2601fe8c42..e05d9bded4 100644 --- a/spec/ruby/library/stringio/readpartial_spec.rb +++ b/spec/ruby/library/stringio/readpartial_spec.rb @@ -3,20 +3,14 @@ require_relative 'fixtures/classes' describe "StringIO#readpartial" do before :each do - @string = StringIO.new('Stop, look, listen') + @string = StringIO.new(+'Stop, look, listen') end after :each do @string.close unless @string.closed? end - it "raises IOError on closed stream" do - @string.close - -> { @string.readpartial(10) }.should raise_error(IOError) - end - it "reads at most the specified number of bytes" do - # buffered read @string.read(1).should == 'S' # return only specified number, not the whole buffer @@ -30,6 +24,14 @@ describe "StringIO#readpartial" do @string.readpartial(3).should == ", l" end + it "reads after ungetc with multibyte characters in the buffer" do + @string = StringIO.new(+"∂φ/∂x = gaîté") + c = @string.getc + @string.ungetc(c) + @string.readpartial(3).should == "\xE2\x88\x82".b + @string.readpartial(3).should == "\xCF\x86/".b + end + it "reads after ungetc without data in the buffer" do @string = StringIO.new @string.write("f").should == 1 @@ -48,33 +50,53 @@ describe "StringIO#readpartial" do end it "discards the existing buffer content upon successful read" do - buffer = "existing" + buffer = +"existing" @string.readpartial(11, buffer) buffer.should == "Stop, look," end it "raises EOFError on EOF" do @string.readpartial(18).should == 'Stop, look, listen' - -> { @string.readpartial(10) }.should raise_error(EOFError) + -> { @string.readpartial(10) }.should.raise(EOFError) end it "discards the existing buffer content upon error" do - buffer = 'hello' + buffer = +'hello' @string.readpartial(100) - -> { @string.readpartial(1, buffer) }.should raise_error(EOFError) - buffer.should be_empty + -> { @string.readpartial(1, buffer) }.should.raise(EOFError) + buffer.should.empty? end it "raises IOError if the stream is closed" do @string.close - -> { @string.readpartial(1) }.should raise_error(IOError) + -> { @string.readpartial(1) }.should.raise(IOError, "not opened for reading") end it "raises ArgumentError if the negative argument is provided" do - -> { @string.readpartial(-1) }.should raise_error(ArgumentError) + -> { @string.readpartial(-1) }.should.raise(ArgumentError, "negative length -1 given") end it "immediately returns an empty string if the length argument is 0" do @string.readpartial(0).should == "" end + + it "raises IOError if the stream is closed and the length argument is 0" do + @string.close + -> { @string.readpartial(0) }.should.raise(IOError, "not opened for reading") + end + + it "clears and returns the given buffer if the length argument is 0" do + buffer = +"existing content" + @string.readpartial(0, buffer).should == buffer + buffer.should == "" + end + + version_is StringIO::VERSION, "3.1.2" do # ruby_version_is "3.4" + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @string.readpartial(10, buffer) + + buffer.encoding.should == Encoding::ISO_8859_1 + end + end end diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb index 6752cf9970..3d4ae3a698 100644 --- a/spec/ruby/library/stringio/reopen_spec.rb +++ b/spec/ruby/library/stringio/reopen_spec.rb @@ -8,50 +8,39 @@ describe "StringIO#reopen when passed [Object, Integer]" do it "reopens self with the passed Object in the passed mode" do @io.reopen("reopened", IO::RDONLY) - @io.closed_read?.should be_false - @io.closed_write?.should be_true + @io.closed_read?.should == false + @io.closed_write?.should == true @io.string.should == "reopened" - @io.reopen("reopened, twice", IO::WRONLY) - @io.closed_read?.should be_true - @io.closed_write?.should be_false + @io.reopen(+"reopened, twice", IO::WRONLY) + @io.closed_read?.should == true + @io.closed_write?.should == false @io.string.should == "reopened, twice" - @io.reopen("reopened, another time", IO::RDWR) - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.reopen(+"reopened, another time", IO::RDWR) + @io.closed_read?.should == false + @io.closed_write?.should == false @io.string.should == "reopened, another time" end - ruby_version_is ""..."3.0" do - # NOTE: WEIRD! - it "does not taint self when the passed Object was tainted" do - @io.reopen("reopened".taint, IO::RDONLY) - @io.tainted?.should be_false - - @io.reopen("reopened".taint, IO::WRONLY) - @io.tainted?.should be_false - end - end - it "tries to convert the passed Object to a String using #to_str" do obj = mock("to_str") - obj.should_receive(:to_str).and_return("to_str") + obj.should_receive(:to_str).and_return(+"to_str") @io.reopen(obj, IO::RDWR) @io.string.should == "to_str" end it "raises a TypeError when the passed Object can't be converted to a String" do - -> { @io.reopen(Object.new, IO::RDWR) }.should raise_error(TypeError) + -> { @io.reopen(Object.new, IO::RDWR) }.should.raise(TypeError) end it "raises an Errno::EACCES when trying to reopen self with a frozen String in write-mode" do - -> { @io.reopen("burn".freeze, IO::WRONLY) }.should raise_error(Errno::EACCES) - -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should raise_error(Errno::EACCES) + -> { @io.reopen("burn".freeze, IO::WRONLY) }.should.raise(Errno::EACCES) + -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should.raise(Errno::EACCES) end it "raises a FrozenError when trying to reopen self with a frozen String in truncate-mode" do - -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should raise_error(FrozenError) + -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should.raise(FrozenError) end it "does not raise IOError when passed a frozen String in read-mode" do @@ -67,42 +56,31 @@ describe "StringIO#reopen when passed [Object, Object]" do it "reopens self with the passed Object in the passed mode" do @io.reopen("reopened", "r") - @io.closed_read?.should be_false - @io.closed_write?.should be_true + @io.closed_read?.should == false + @io.closed_write?.should == true @io.string.should == "reopened" - @io.reopen("reopened, twice", "r+") - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.reopen(+"reopened, twice", "r+") + @io.closed_read?.should == false + @io.closed_write?.should == false @io.string.should == "reopened, twice" - @io.reopen("reopened, another", "w+") - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.reopen(+"reopened, another", "w+") + @io.closed_read?.should == false + @io.closed_write?.should == false @io.string.should == "" - @io.reopen("reopened, another time", "r+") - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.reopen(+"reopened, another time", "r+") + @io.closed_read?.should == false + @io.closed_write?.should == false @io.string.should == "reopened, another time" end it "truncates the passed String when opened in truncate mode" do - @io.reopen(str = "reopened", "w") + @io.reopen(str = +"reopened", "w") str.should == "" end - ruby_version_is ""..."3.0" do - # NOTE: WEIRD! - it "does not taint self when the passed Object was tainted" do - @io.reopen("reopened".taint, "r") - @io.tainted?.should be_false - - @io.reopen("reopened".taint, "w") - @io.tainted?.should be_false - end - end - it "tries to convert the passed Object to a String using #to_str" do obj = mock("to_str") obj.should_receive(:to_str).and_return("to_str") @@ -111,35 +89,35 @@ describe "StringIO#reopen when passed [Object, Object]" do end it "raises a TypeError when the passed Object can't be converted to a String using #to_str" do - -> { @io.reopen(Object.new, "r") }.should raise_error(TypeError) + -> { @io.reopen(Object.new, "r") }.should.raise(TypeError) end it "resets self's position to 0" do @io.read(5) - @io.reopen("reopened") - @io.pos.should eql(0) + @io.reopen(+"reopened") + @io.pos.should.eql?(0) end it "resets self's line number to 0" do @io.gets - @io.reopen("reopened") - @io.lineno.should eql(0) + @io.reopen(+"reopened") + @io.lineno.should.eql?(0) end it "tries to convert the passed mode Object to an Integer using #to_str" do obj = mock("to_str") obj.should_receive(:to_str).and_return("r") @io.reopen("reopened", obj) - @io.closed_read?.should be_false - @io.closed_write?.should be_true + @io.closed_read?.should == false + @io.closed_write?.should == true @io.string.should == "reopened" end it "raises an Errno::EACCES error when trying to reopen self with a frozen String in write-mode" do - -> { @io.reopen("burn".freeze, 'w') }.should raise_error(Errno::EACCES) - -> { @io.reopen("burn".freeze, 'w+') }.should raise_error(Errno::EACCES) - -> { @io.reopen("burn".freeze, 'a') }.should raise_error(Errno::EACCES) - -> { @io.reopen("burn".freeze, "r+") }.should raise_error(Errno::EACCES) + -> { @io.reopen("burn".freeze, 'w') }.should.raise(Errno::EACCES) + -> { @io.reopen("burn".freeze, 'w+') }.should.raise(Errno::EACCES) + -> { @io.reopen("burn".freeze, 'a') }.should.raise(Errno::EACCES) + -> { @io.reopen("burn".freeze, "r+") }.should.raise(Errno::EACCES) end it "does not raise IOError if a frozen string is passed in read mode" do @@ -156,32 +134,24 @@ describe "StringIO#reopen when passed [String]" do it "reopens self with the passed String in read-write mode" do @io.close - @io.reopen("reopened") + @io.reopen(+"reopened") - @io.closed_write?.should be_false - @io.closed_read?.should be_false + @io.closed_write?.should == false + @io.closed_read?.should == false @io.string.should == "reopened" end - ruby_version_is ""..."3.0" do - # NOTE: WEIRD! - it "does not taint self when the passed Object was tainted" do - @io.reopen("reopened".taint) - @io.tainted?.should be_false - end - end - it "resets self's position to 0" do @io.read(5) - @io.reopen("reopened") - @io.pos.should eql(0) + @io.reopen(+"reopened") + @io.pos.should.eql?(0) end it "resets self's line number to 0" do @io.gets - @io.reopen("reopened") - @io.lineno.should eql(0) + @io.reopen(+"reopened") + @io.lineno.should.eql?(0) end end @@ -191,29 +161,21 @@ describe "StringIO#reopen when passed [Object]" do end it "raises a TypeError when passed an Object that can't be converted to a StringIO" do - -> { @io.reopen(Object.new) }.should raise_error(TypeError) + -> { @io.reopen(Object.new) }.should.raise(TypeError) end it "does not try to convert the passed Object to a String using #to_str" do obj = mock("not to_str") obj.should_not_receive(:to_str) - -> { @io.reopen(obj) }.should raise_error(TypeError) + -> { @io.reopen(obj) }.should.raise(TypeError) end it "tries to convert the passed Object to a StringIO using #to_strio" do obj = mock("to_strio") - obj.should_receive(:to_strio).and_return(StringIO.new("to_strio")) + obj.should_receive(:to_strio).and_return(StringIO.new(+"to_strio")) @io.reopen(obj) @io.string.should == "to_strio" end - - # NOTE: WEIRD! - ruby_version_is ""..."2.7" do - it "taints self when the passed Object was tainted" do - @io.reopen(StringIO.new("reopened").taint) - @io.tainted?.should be_true - end - end end describe "StringIO#reopen when passed no arguments" do @@ -224,20 +186,20 @@ describe "StringIO#reopen when passed no arguments" do it "resets self's mode to read-write" do @io.close @io.reopen - @io.closed_read?.should be_false - @io.closed_write?.should be_false + @io.closed_read?.should == false + @io.closed_write?.should == false end it "resets self's position to 0" do @io.read(5) @io.reopen - @io.pos.should eql(0) + @io.pos.should.eql?(0) end it "resets self's line number to 0" do @io.gets @io.reopen - @io.lineno.should eql(0) + @io.lineno.should.eql?(0) end end @@ -246,49 +208,40 @@ end # for details. describe "StringIO#reopen" do before :each do - @io = StringIO.new('hello','a') + @io = StringIO.new(+'hello', 'a') end # TODO: find out if this is really a bug it "reopens a stream when given a String argument" do - @io.reopen('goodbye').should == @io + @io.reopen(+'goodbye').should == @io @io.string.should == 'goodbye' @io << 'x' @io.string.should == 'xoodbye' end it "reopens a stream in append mode when flagged as such" do - @io.reopen('goodbye', 'a').should == @io + @io.reopen(+'goodbye', 'a').should == @io @io.string.should == 'goodbye' @io << 'x' @io.string.should == 'goodbyex' end it "reopens and truncate when reopened in write mode" do - @io.reopen('goodbye', 'wb').should == @io + @io.reopen(+'goodbye', 'wb').should == @io @io.string.should == '' @io << 'x' @io.string.should == 'x' end it "truncates the given string, not a copy" do - str = 'goodbye' + str = +'goodbye' @io.reopen(str, 'w') @io.string.should == '' str.should == '' end - ruby_version_is ""..."2.7" do - it "taints self if the provided StringIO argument is tainted" do - new_io = StringIO.new("tainted") - new_io.taint - @io.reopen(new_io) - @io.should.tainted? - end - end - it "does not truncate the content even when the StringIO argument is in the truncate mode" do - orig_io = StringIO.new("Original StringIO", IO::RDWR|IO::TRUNC) + orig_io = StringIO.new(+"Original StringIO", IO::RDWR|IO::TRUNC) orig_io.write("BLAH") # make sure the content is not empty @io.reopen(orig_io) diff --git a/spec/ruby/library/stringio/rewind_spec.rb b/spec/ruby/library/stringio/rewind_spec.rb index 5f885ecf81..8c48709d89 100644 --- a/spec/ruby/library/stringio/rewind_spec.rb +++ b/spec/ruby/library/stringio/rewind_spec.rb @@ -9,7 +9,7 @@ describe "StringIO#rewind" do end it "returns 0" do - @io.rewind.should eql(0) + @io.rewind.should.eql?(0) end it "resets the position" do diff --git a/spec/ruby/library/stringio/seek_spec.rb b/spec/ruby/library/stringio/seek_spec.rb index 253b5027a9..9043e0338f 100644 --- a/spec/ruby/library/stringio/seek_spec.rb +++ b/spec/ruby/library/stringio/seek_spec.rb @@ -9,18 +9,18 @@ describe "StringIO#seek" do it "seeks from the current position when whence is IO::SEEK_CUR" do @io.pos = 1 @io.seek(1, IO::SEEK_CUR) - @io.pos.should eql(2) + @io.pos.should.eql?(2) @io.seek(-1, IO::SEEK_CUR) - @io.pos.should eql(1) + @io.pos.should.eql?(1) end it "seeks from the end of self when whence is IO::SEEK_END" do @io.seek(3, IO::SEEK_END) - @io.pos.should eql(11) # Outside of the StringIO's content + @io.pos.should.eql?(11) # Outside of the StringIO's content @io.seek(-2, IO::SEEK_END) - @io.pos.should eql(6) + @io.pos.should.eql?(6) end it "seeks to an absolute position when whence is IO::SEEK_SET" do @@ -33,25 +33,25 @@ describe "StringIO#seek" do end it "raises an Errno::EINVAL error on negative amounts when whence is IO::SEEK_SET" do - -> { @io.seek(-5, IO::SEEK_SET) }.should raise_error(Errno::EINVAL) + -> { @io.seek(-5, IO::SEEK_SET) }.should.raise(Errno::EINVAL) end it "raises an Errno::EINVAL error on incorrect whence argument" do - -> { @io.seek(0, 3) }.should raise_error(Errno::EINVAL) - -> { @io.seek(0, -1) }.should raise_error(Errno::EINVAL) - -> { @io.seek(0, 2**16) }.should raise_error(Errno::EINVAL) - -> { @io.seek(0, -2**16) }.should raise_error(Errno::EINVAL) + -> { @io.seek(0, 3) }.should.raise(Errno::EINVAL) + -> { @io.seek(0, -1) }.should.raise(Errno::EINVAL) + -> { @io.seek(0, 2**16) }.should.raise(Errno::EINVAL) + -> { @io.seek(0, -2**16) }.should.raise(Errno::EINVAL) end it "tries to convert the passed Object to a String using #to_int" do obj = mock("to_int") obj.should_receive(:to_int).and_return(2) @io.seek(obj) - @io.pos.should eql(2) + @io.pos.should.eql?(2) end it "raises a TypeError when the passed Object can't be converted to an Integer" do - -> { @io.seek(Object.new) }.should raise_error(TypeError) + -> { @io.seek(Object.new) }.should.raise(TypeError) end end @@ -62,6 +62,6 @@ describe "StringIO#seek when self is closed" do end it "raises an IOError" do - -> { @io.seek(5) }.should raise_error(IOError) + -> { @io.seek(5) }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb new file mode 100644 index 0000000000..b4583a7ad7 --- /dev/null +++ b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb @@ -0,0 +1,237 @@ +require 'stringio' +require_relative '../../spec_helper' + +# Should be synced with specs for IO#set_encoding_by_bom +describe "StringIO#set_encoding_by_bom" do + it "returns nil if not readable" do + io = StringIO.new("".b, "wb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + end + + it "returns the result encoding if found BOM UTF-8 sequence" do + io = StringIO.new("\u{FEFF}".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_8 + io.external_encoding.should == Encoding::UTF_8 + io.read.b.should == "".b + + io = StringIO.new("\u{FEFF}abc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_8 + io.external_encoding.should == Encoding::UTF_8 + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_16LE sequence" do + io = StringIO.new("\xFF\xFE".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFEabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_16BE sequence" do + io = StringIO.new("\xFE\xFF".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16BE + io.external_encoding.should == Encoding::UTF_16BE + io.read.b.should == "".b + + io = StringIO.new("\xFE\xFFabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16BE + io.external_encoding.should == Encoding::UTF_16BE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_32LE sequence" do + io = StringIO.new("\xFF\xFE\x00\x00".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32LE + io.external_encoding.should == Encoding::UTF_32LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFE\x00\x00abc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32LE + io.external_encoding.should == Encoding::UTF_32LE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_32BE sequence" do + io = StringIO.new("\x00\x00\xFE\xFF".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32BE + io.external_encoding.should == Encoding::UTF_32BE + io.read.b.should == "".b + + io = StringIO.new("\x00\x00\xFE\xFFabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32BE + io.external_encoding.should == Encoding::UTF_32BE + io.read.b.should == "abc".b + end + + it "returns nil if io is empty" do + io = StringIO.new("".b, "rb") + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + end + + it "returns nil if UTF-8 BOM sequence is incomplete" do + io = StringIO.new("\xEF".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF".b + + io = StringIO.new("\xEFa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEFa".b + + io = StringIO.new("\xEF\xBB".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF\xBB".b + + io = StringIO.new("\xEF\xBBa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF\xBBa".b + end + + it "returns nil if UTF-16BE BOM sequence is incomplete" do + io = StringIO.new("\xFE".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFE".b + + io = StringIO.new("\xFEa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFEa".b + end + + it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do + io = StringIO.new("\xFF".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFF".b + + io = StringIO.new("\xFFa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFFa".b + end + + it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do + io = StringIO.new("\xFF\xFE".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFE\x00".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "\x00".b + + io = StringIO.new("\xFF\xFE\x00a".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "\x00a".b + end + + it "returns nil if UTF-32BE BOM sequence is incomplete" do + io = StringIO.new("\x00".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00".b + + io = StringIO.new("\x00a".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00a".b + + io = StringIO.new("\x00\x00".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00".b + + io = StringIO.new("\x00\x00a".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00a".b + + io = StringIO.new("\x00\x00\xFE".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00\xFE".b + + io = StringIO.new("\x00\x00\xFEa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00\xFEa".b + end + + it "returns nil if found BOM sequence not provided" do + io = StringIO.new("abc".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read(3).should == "abc".b + end + + it "does not raise exception if io not in binary mode" do + io = StringIO.new("", 'r') + io.set_encoding_by_bom.should == nil + end + + it "does not raise exception if encoding already set" do + io = StringIO.new("".b, "rb") + io.set_encoding("utf-8") + io.set_encoding_by_bom.should == nil + end + + it "does not raise exception if encoding conversion is already set" do + io = StringIO.new("".b, "rb") + io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) + + io.set_encoding_by_bom.should == nil + end + + it "raises FrozenError when io is frozen" do + io = StringIO.new() + io.freeze + -> { io.set_encoding_by_bom }.should.raise(FrozenError) + end + + it "does not raise FrozenError when initial string is frozen" do + io = StringIO.new("".freeze) + io.set_encoding_by_bom.should == nil + end +end diff --git a/spec/ruby/library/stringio/set_encoding_spec.rb b/spec/ruby/library/stringio/set_encoding_spec.rb index 21d45750f3..19ca0875bf 100644 --- a/spec/ruby/library/stringio/set_encoding_spec.rb +++ b/spec/ruby/library/stringio/set_encoding_spec.rb @@ -17,4 +17,12 @@ describe "StringIO#set_encoding" do io.set_encoding Encoding::UTF_8 io.string.encoding.should == Encoding::US_ASCII end + + it "accepts a String" do + str = "".encode(Encoding::US_ASCII) + io = StringIO.new(str) + io.set_encoding("ASCII-8BIT") + io.external_encoding.should == Encoding::BINARY + str.encoding.should == Encoding::BINARY + end end diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb index 9d84aa4919..e35a02ccb4 100644 --- a/spec/ruby/library/stringio/shared/codepoints.rb +++ b/spec/ruby/library/stringio/shared/codepoints.rb @@ -6,7 +6,7 @@ describe :stringio_codepoints, shared: true do end it "returns an Enumerator" do - @enum.should be_an_instance_of(Enumerator) + @enum.should.instance_of?(Enumerator) end it "yields each codepoint code in turn" do @@ -20,15 +20,15 @@ describe :stringio_codepoints, shared: true do it "raises an error if reading invalid sequence" do @io.pos = 1 # inside of a multibyte sequence - -> { @enum.first }.should raise_error(ArgumentError) + -> { @enum.first }.should.raise(ArgumentError) end it "raises an IOError if not readable" do @io.close_read - -> { @enum.to_a }.should raise_error(IOError) + -> { @enum.to_a }.should.raise(IOError) - io = StringIO.new("xyz", "w") - -> { io.send(@method).to_a }.should raise_error(IOError) + io = StringIO.new(+"xyz", "w") + -> { io.send(@method).to_a }.should.raise(IOError) end @@ -39,7 +39,7 @@ describe :stringio_codepoints, shared: true do end it "returns self" do - @io.send(@method) {|l| l }.should equal(@io) + @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 index 14b0a013b3..04e40b6b2a 100644 --- a/spec/ruby/library/stringio/shared/each.rb +++ b/spec/ruby/library/stringio/shared/each.rb @@ -16,7 +16,7 @@ describe :stringio_each_separator, shared: true do end it "returns self" do - @io.send(@method) {|l| l }.should equal(@io) + @io.send(@method) {|l| l }.should.equal?(@io) end it "tries to convert the passed separator to a String using #to_str" do @@ -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 @@ -74,19 +74,19 @@ describe :stringio_each_no_arguments, shared: true do old_rs = $/ suppress_warning {$/ = " "} @io.send(@method) {|s| seen << s } - seen.should eql(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"]) + 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) + @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 + enum.instance_of?(Enumerator).should == true seen = [] enum.each { |b| seen << b } @@ -96,12 +96,12 @@ 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", "w") + -> { io.send(@method) { |b| b } }.should.raise(IOError) io = StringIO.new("a b c d e") io.close_read - -> { io.send(@method) { |b| b } }.should raise_error(IOError) + -> { io.send(@method) { |b| b } }.should.raise(IOError) end end @@ -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..b3939c26de 100644 --- a/spec/ruby/library/stringio/shared/each_byte.rb +++ b/spec/ruby/library/stringio/shared/each_byte.rb @@ -19,16 +19,16 @@ describe :stringio_each_byte, shared: true do @io.pos = 1000 seen = nil @io.send(@method) { |b| seen = b } - seen.should be_nil + seen.should == nil end it "returns self" do - @io.send(@method) {}.should equal(@io) + @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 + enum.instance_of?(Enumerator).should == true seen = [] enum.each { |b| seen << b } @@ -38,11 +38,11 @@ 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", "w") + -> { io.send(@method) { |b| b } }.should.raise(IOError) io = StringIO.new("xyz") io.close_read - -> { io.send(@method) { |b| b } }.should raise_error(IOError) + -> { io.send(@method) { |b| b } }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb index bcdac53282..4215a9952b 100644 --- a/spec/ruby/library/stringio/shared/each_char.rb +++ b/spec/ruby/library/stringio/shared/each_char.rb @@ -11,12 +11,12 @@ describe :stringio_each_char, shared: true do end it "returns self" do - @io.send(@method) {}.should equal(@io) + @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 + enum.instance_of?(Enumerator).should == true seen = [] enum.each { |c| seen << c } @@ -26,11 +26,11 @@ 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", "w") + -> { io.send(@method) { |b| b } }.should.raise(IOError) io = StringIO.new("xyz") io.close_read - -> { io.send(@method) { |b| b } }.should raise_error(IOError) + -> { io.send(@method) { |b| b } }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/shared/eof.rb b/spec/ruby/library/stringio/shared/eof.rb index e0368a2892..a9489581fc 100644 --- a/spec/ruby/library/stringio/shared/eof.rb +++ b/spec/ruby/library/stringio/shared/eof.rb @@ -5,20 +5,20 @@ describe :stringio_eof, shared: true do 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.send(@method).should == true @io.pos = 6 - @io.send(@method).should be_true + @io.send(@method).should == 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.send(@method).should == false @io.pos = 1 - @io.send(@method).should be_false + @io.send(@method).should == false @io.pos = 2 - @io.send(@method).should be_false + @io.send(@method).should == false end end diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb index 6318bcc30f..a146b2d4cf 100644 --- a/spec/ruby/library/stringio/shared/getc.rb +++ b/spec/ruby/library/stringio/shared/getc.rb @@ -5,39 +5,39 @@ describe :stringio_getc, shared: true do it "increases self's position by one" do @io.send(@method) - @io.pos.should eql(1) + @io.pos.should.eql?(1) @io.send(@method) - @io.pos.should eql(2) + @io.pos.should.eql?(2) @io.send(@method) - @io.pos.should eql(3) + @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 + @io.send(@method).should == nil + @io.send(@method).should == nil + @io.send(@method).should == 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.pos.should.eql?(7) @io.send(@method) - @io.pos.should eql(7) + @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", "w") + -> { io.send(@method) }.should.raise(IOError) io = StringIO.new("xyz") io.close_read - -> { io.send(@method) }.should raise_error(IOError) + -> { io.send(@method) }.should.raise(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..16039b18ef --- /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(IOError) + + io = StringIO.new("xyz") + io.close_read + -> { io.send(@method) }.should.raise(IOError) + end + end +end diff --git a/spec/ruby/library/stringio/shared/isatty.rb b/spec/ruby/library/stringio/shared/isatty.rb index 3da5999953..2b92e8d656 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 == false end end diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb index c60677bba7..6e04e75dba 100644 --- a/spec/ruby/library/stringio/shared/read.rb +++ b/spec/ruby/library/stringio/shared/read.rb @@ -5,30 +5,48 @@ 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 = "") - ret.should equal(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" 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) + -> { @io.send(@method, 7, Object.new) }.should.raise(TypeError) end it "raises a FrozenError error when passed a frozen String as buffer" do - -> { @io.send(@method, 7, "".freeze) }.should raise_error(FrozenError) + -> { @io.send(@method, 7, "".freeze) }.should.raise(FrozenError) end end @@ -48,10 +66,10 @@ describe :stringio_read_length, shared: true do it "correctly updates the position" do @io.send(@method, 3) - @io.pos.should eql(3) + @io.pos.should.eql?(3) @io.send(@method, 999) - @io.pos.should eql(7) + @io.pos.should.eql?(7) end it "tries to convert the passed length to an Integer using #to_int" do @@ -61,11 +79,11 @@ describe :stringio_read_length, shared: true do 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) + -> { @io.send(@method, Object.new) }.should.raise(TypeError) end it "raises a TypeError when the passed length is negative" do - -> { @io.send(@method, -2) }.should raise_error(ArgumentError) + -> { @io.send(@method, -2) }.should.raise(ArgumentError) end it "returns a binary String" do @@ -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 @@ -87,7 +105,13 @@ describe :stringio_read_no_arguments, shared: true do it "correctly updates the current position" do @io.send(@method) - @io.pos.should eql(7) + @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 @@ -105,17 +129,17 @@ describe :stringio_read_nil, shared: true do it "updates the current position" do @io.send(@method, nil) - @io.pos.should eql(7) + @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", "w") + -> { io.send(@method) }.should.raise(IOError) io = StringIO.new("test") io.close_read - -> { io.send(@method) }.should raise_error(IOError) + -> { io.send(@method) }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb index 4248e75420..5ac28e0743 100644 --- a/spec/ruby/library/stringio/shared/readchar.rb +++ b/spec/ruby/library/stringio/shared/readchar.rb @@ -13,17 +13,17 @@ describe :stringio_readchar, shared: true do it "raises an EOFError when self is at the end" do @io.pos = 7 - -> { @io.send(@method) }.should raise_error(EOFError) + -> { @io.send(@method) }.should.raise(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", "w") + -> { io.send(@method) }.should.raise(IOError) io = StringIO.new("a b c d e") io.close_read - -> { io.send(@method) }.should raise_error(IOError) + -> { io.send(@method) }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb index 3376bd9907..bc448d3379 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(EOFError) end end diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb index 080729217b..b6bffe7f12 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. @@ -42,38 +42,82 @@ describe :stringio_write_string, shared: true do it "updates self's position" do @io.send(@method, 'test') - @io.pos.should eql(4) + @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.send(@method, "test") }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.send(@method, "test") }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.send(@method, "test") }.should raise_error(IOError) + -> { io.send(@method, "test") }.should.raise(IOError) end 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 @@ -86,6 +130,6 @@ describe :stringio_write_append, shared: true do it "correctly updates self's position" do @io.send(@method, ", testing") - @io.pos.should eql(16) + @io.pos.should.eql?(16) end end diff --git a/spec/ruby/library/stringio/string_spec.rb b/spec/ruby/library/stringio/string_spec.rb index 1ed5233ba6..3b27243da9 100644 --- a/spec/ruby/library/stringio/string_spec.rb +++ b/spec/ruby/library/stringio/string_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' describe "StringIO#string" do it "returns the underlying string" do io = StringIO.new(str = "hello") - io.string.should equal(str) + io.string.should.equal?(str) end end @@ -15,25 +15,25 @@ describe "StringIO#string=" do it "returns the passed String" do str = "test" - (@io.string = str).should equal(str) + (@io.string = str).should.equal?(str) end it "changes the underlying string" do str = "hello" @io.string = str - @io.string.should equal(str) + @io.string.should.equal?(str) end it "resets the position" do @io.pos = 1 @io.string = "other" - @io.pos.should eql(0) + @io.pos.should.eql?(0) end it "resets the line number" do @io.lineno = 1 @io.string = "other" - @io.lineno.should eql(0) + @io.lineno.should.eql?(0) end it "tries to convert the passed Object to a String using #to_str" do @@ -45,6 +45,6 @@ describe "StringIO#string=" do end it "raises a TypeError when the passed Object can't be converted to an Integer" do - -> { @io.seek(Object.new) }.should raise_error(TypeError) + -> { @io.seek(Object.new) }.should.raise(TypeError) end end diff --git a/spec/ruby/library/stringio/stringio_spec.rb b/spec/ruby/library/stringio/stringio_spec.rb index 5ef42b3390..dee0364ab0 100644 --- a/spec/ruby/library/stringio/stringio_spec.rb +++ b/spec/ruby/library/stringio/stringio_spec.rb @@ -3,6 +3,6 @@ require "stringio" describe "StringIO" do it "includes the Enumerable module" do - StringIO.should include(Enumerable) + StringIO.should.include?(Enumerable) end end diff --git a/spec/ruby/library/stringio/sync_spec.rb b/spec/ruby/library/stringio/sync_spec.rb index e717a5697b..d7d1209047 100644 --- a/spec/ruby/library/stringio/sync_spec.rb +++ b/spec/ruby/library/stringio/sync_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#sync" do it "returns true" do - StringIO.new('').sync.should be_true + StringIO.new('').sync.should == true end end @@ -14,6 +14,6 @@ describe "StringIO#sync=" do it "does not change 'sync' status" do @io.sync = false - @io.sync.should be_true + @io.sync.should == true end end diff --git a/spec/ruby/library/stringio/sysread_spec.rb b/spec/ruby/library/stringio/sysread_spec.rb index 8f78073f42..1403dab5cb 100644 --- a/spec/ruby/library/stringio/sysread_spec.rb +++ b/spec/ruby/library/stringio/sysread_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require "stringio" require_relative 'shared/read' +require_relative 'shared/sysread' describe "StringIO#sysread when passed length, buffer" do it_behaves_like :stringio_read, :sysread @@ -32,6 +33,10 @@ describe "StringIO#sysread when passed nil" do end end +describe "StringIO#sysread when passed length" do + it_behaves_like :stringio_sysread_length, :sysread +end + describe "StringIO#sysread when passed [length]" do before :each do @io = StringIO.new("example") @@ -39,7 +44,7 @@ describe "StringIO#sysread when passed [length]" do it "raises an EOFError when self's position is at the end" do @io.pos = 7 - -> { @io.sysread(10) }.should raise_error(EOFError) + -> { @io.sysread(10) }.should.raise(EOFError) end it "returns an empty String when length is 0" do diff --git a/spec/ruby/library/stringio/truncate_spec.rb b/spec/ruby/library/stringio/truncate_spec.rb index ba910ee98c..7205261141 100644 --- a/spec/ruby/library/stringio/truncate_spec.rb +++ b/spec/ruby/library/stringio/truncate_spec.rb @@ -3,13 +3,11 @@ require "stringio" describe "StringIO#truncate when passed [length]" do before :each do - @io = StringIO.new('123456789') + @io = StringIO.new(+'123456789') end - # TODO: Report to Ruby-Core: The RDoc says it always returns 0 - it "returns the passed length" do - @io.truncate(4).should eql(4) - @io.truncate(10).should eql(10) + it "returns an Integer" do + @io.truncate(4).should.is_a?(Integer) end it "truncated the underlying string down to the passed length" do @@ -18,15 +16,15 @@ describe "StringIO#truncate when passed [length]" do end it "does not create a copy of the underlying string" do - io = StringIO.new(str = "123456789") + io = StringIO.new(str = +"123456789") io.truncate(4) - io.string.should equal(str) + io.string.should.equal?(str) end it "does not change the position" do @io.pos = 7 @io.truncate(4) - @io.pos.should eql(7) + @io.pos.should.eql?(7) end it "can grow a string to a larger size, padding it with \\000" do @@ -35,8 +33,8 @@ describe "StringIO#truncate when passed [length]" do end it "raises an Errno::EINVAL when the passed length is negative" do - -> { @io.truncate(-1) }.should raise_error(Errno::EINVAL) - -> { @io.truncate(-10) }.should raise_error(Errno::EINVAL) + -> { @io.truncate(-1) }.should.raise(Errno::EINVAL) + -> { @io.truncate(-10) }.should.raise(Errno::EINVAL) end it "tries to convert the passed length to an Integer using #to_int" do @@ -47,24 +45,18 @@ describe "StringIO#truncate when passed [length]" do @io.string.should == "1234" end - it "returns the passed length Object, NOT the result of #to_int" do - obj = mock("to_int") - obj.should_receive(:to_int).and_return(4) - @io.truncate(obj).should equal(obj) - end - it "raises a TypeError when the passed length can't be converted to an Integer" do - -> { @io.truncate(Object.new) }.should raise_error(TypeError) + -> { @io.truncate(Object.new) }.should.raise(TypeError) end end describe "StringIO#truncate when self is not writable" do it "raises an IOError" do - io = StringIO.new("test", "r") - -> { io.truncate(2) }.should raise_error(IOError) + io = StringIO.new(+"test", "r") + -> { io.truncate(2) }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.close_write - -> { io.truncate(2) }.should raise_error(IOError) + -> { io.truncate(2) }.should.raise(IOError) end end diff --git a/spec/ruby/library/stringio/ungetbyte_spec.rb b/spec/ruby/library/stringio/ungetbyte_spec.rb index 701463e621..87b27b837e 100644 --- a/spec/ruby/library/stringio/ungetbyte_spec.rb +++ b/spec/ruby/library/stringio/ungetbyte_spec.rb @@ -1,6 +1,42 @@ +# frozen_string_literal: false require_relative '../../spec_helper' require 'stringio' describe "StringIO#ungetbyte" do - it "needs to be reviewed for spec completeness" + it "ungets a single byte from a string starting with a single byte character" do + str = 'This is a simple string.' + io = StringIO.new("#{str}") + c = io.getc + c.should == 'T' + io.ungetbyte(83) + io.string.should == 'Shis is a simple string.' + end + + it "ungets a single byte from a string in the middle of a multibyte character" do + str = "\u01a9" + io = StringIO.new(str) + b = io.getbyte + b.should == 0xc6 # First byte of UTF-8 encoding of \u01a9 + io.ungetbyte(0xce) # First byte of UTF-8 encoding of \u03a9 + io.string.should == "\u03a9" + end + + it "constrains the value of a numeric argument to a single byte" do + str = 'This is a simple string.' + io = StringIO.new("#{str}") + c = io.getc + c.should == 'T' + io.ungetbyte(83 | 0xff00) + io.string.should == 'Shis is a simple string.' + end + + it "ungets the bytes of a string if given a string as an argument" do + str = "\u01a9" + io = StringIO.new(str) + b = io.getbyte + b.should == 0xc6 # First byte of UTF-8 encoding of \u01a9 + io.ungetbyte("\u01a9") + io.string.bytes.should == [198, 169, 169] + end + end diff --git a/spec/ruby/library/stringio/ungetc_spec.rb b/spec/ruby/library/stringio/ungetc_spec.rb index 91ef2100a1..8753ac9666 100644 --- a/spec/ruby/library/stringio/ungetc_spec.rb +++ b/spec/ruby/library/stringio/ungetc_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "StringIO#ungetc when passed [char]" do before :each do - @io = StringIO.new('1234') + @io = StringIO.new(+'1234') end it "writes the passed char before the current position" do @@ -14,13 +14,13 @@ describe "StringIO#ungetc when passed [char]" do it "returns nil" do @io.pos = 1 - @io.ungetc(?A).should be_nil + @io.ungetc(?A).should == nil end it "decreases the current position by one" do @io.pos = 2 @io.ungetc(?A) - @io.pos.should eql(1) + @io.pos.should.eql?(1) end it "pads with \\000 when the current position is after the end" do @@ -39,20 +39,20 @@ describe "StringIO#ungetc when passed [char]" do end it "raises a TypeError when the passed length can't be converted to an Integer or String" do - -> { @io.ungetc(Object.new) }.should raise_error(TypeError) + -> { @io.ungetc(Object.new) }.should.raise(TypeError) end end describe "StringIO#ungetc when self is not readable" do it "raises an IOError" do - io = StringIO.new("test", "w") + io = StringIO.new(+"test", "w") io.pos = 1 - -> { io.ungetc(?A) }.should raise_error(IOError) + -> { io.ungetc(?A) }.should.raise(IOError) - io = StringIO.new("test") + io = StringIO.new(+"test") io.pos = 1 io.close_read - -> { io.ungetc(?A) }.should raise_error(IOError) + -> { io.ungetc(?A) }.should.raise(IOError) end end @@ -60,13 +60,13 @@ end # # describe "StringIO#ungetc when self is not writable" do # it "raises an IOError" do -# io = StringIO.new("test", "r") +# io = StringIO.new(+"test", "r") # io.pos = 1 -# lambda { io.ungetc(?A) }.should raise_error(IOError) +# lambda { io.ungetc(?A) }.should.raise(IOError) # -# io = StringIO.new("test") +# io = StringIO.new(+"test") # io.pos = 1 # io.close_write -# lambda { io.ungetc(?A) }.should raise_error(IOError) +# lambda { io.ungetc(?A) }.should.raise(IOError) # end # end diff --git a/spec/ruby/library/stringio/write_nonblock_spec.rb b/spec/ruby/library/stringio/write_nonblock_spec.rb index 4f4c5039fe..b48ef6698a 100644 --- a/spec/ruby/library/stringio/write_nonblock_spec.rb +++ b/spec/ruby/library/stringio/write_nonblock_spec.rb @@ -8,6 +8,12 @@ end describe "StringIO#write_nonblock when passed [String]" do it_behaves_like :stringio_write_string, :write_nonblock + + it "accepts :exception option" do + io = StringIO.new(+"12345", "a") + io.write_nonblock("67890", exception: true) + io.string.should == "1234567890" + end end describe "StringIO#write_nonblock when self is not writable" do |
