summaryrefslogtreecommitdiff
path: root/spec/ruby/core/io/gets_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/io/gets_spec.rb')
-rw-r--r--spec/ruby/core/io/gets_spec.rb117
1 files changed, 72 insertions, 45 deletions
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index 6e0518b512..ce3ee73b94 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/gets_ascii', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/gets_ascii'
describe "IO#gets" do
it_behaves_like :io_gets_ascii, :gets
@@ -24,13 +24,19 @@ describe "IO#gets" do
end
end
+ it "sets $_ to nil after the last line has been read" do
+ while @io.gets
+ end
+ $_.should == nil
+ end
+
it "returns nil if called at the end of the stream" do
IOSpecs.lines.length.times { @io.gets }
@io.gets.should == nil
end
it "raises IOError on closed stream" do
- lambda { IOSpecs.closed_io.gets }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.gets }.should.raise(IOError)
end
describe "with no separator" do
@@ -38,12 +44,6 @@ describe "IO#gets" do
IOSpecs.lines.each { |line| line.should == @io.gets }
end
- it "returns tainted strings" do
- while line = @io.gets
- line.tainted?.should == true
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets
@io.lineno.should == @count += 1
@@ -62,12 +62,6 @@ describe "IO#gets" do
@io.gets(nil).should == IOSpecs.lines.join("")
end
- it "returns tainted strings" do
- while line = @io.gets(nil)
- line.tainted?.should == true
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets(nil)
@io.lineno.should == @count += 1
@@ -96,12 +90,6 @@ describe "IO#gets" do
@io.gets.should == IOSpecs.lines[4]
end
- it "returns tainted strings" do
- while line = @io.gets("")
- line.tainted?.should == true
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets("")
@io.lineno.should == @count += 1
@@ -120,12 +108,6 @@ describe "IO#gets" do
@io.gets("la linea").should == "Voici la ligne une.\nQui \303\250 la linea"
end
- it "returns tainted strings" do
- while line = @io.gets("la")
- line.tainted?.should == true
- end
- end
-
it "updates lineno with each invocation" do
while (@io.gets("la"))
@io.lineno.should == @count += 1
@@ -137,15 +119,50 @@ describe "IO#gets" do
$..should == @count += 1
end
end
- end
- ruby_version_is "2.4" do
- describe "when passed chomp" do
- it "returns the first line without a trailing newline character" do
- @io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
+ describe "that consists of multiple bytes" do
+ platform_is_not :windows do
+ it "should match the separator even if the buffer is filled over successive reads" do
+ IO.pipe do |read, write|
+
+ # Write part of the string with the separator split between two write calls. We want
+ # the read to intertwine such that when the read starts the full data isn't yet
+ # available in the buffer.
+ write.write("Aquí está la línea tres\r\n")
+
+ t = Thread.new do
+ # Continue reading until the separator is encountered or the pipe is closed.
+ read.gets("\r\n\r\n")
+ end
+
+ # Write the other half of the separator, which should cause the `gets` call to now
+ # match. Explicitly close the pipe for good measure so a bug in `gets` doesn't block forever.
+ Thread.pass until t.stop?
+
+ write.write("\r\nelse\r\n\r\n")
+ write.close
+
+ t.value.bytes.should == "Aquí está la línea tres\r\n\r\n".bytes
+ read.read(8).bytes.should == "else\r\n\r\n".bytes
+ end
+ end
end
end
end
+
+ describe "when passed chomp" do
+ it "returns the first line without a trailing newline character" do
+ @io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
+ end
+
+ it "raises exception when options passed as Hash" do
+ -> { @io.gets({ chomp: true }) }.should.raise(TypeError)
+
+ -> {
+ @io.gets("\n", 1, { chomp: true })
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
end
describe "IO#gets" do
@@ -158,11 +175,11 @@ describe "IO#gets" do
end
it "raises an IOError if the stream is opened for append only" do
- lambda { File.open(@name, fmode("a:utf-8")) { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "a:utf-8") { |f| f.gets } }.should.raise(IOError)
end
it "raises an IOError if the stream is opened for writing only" do
- lambda { File.open(@name, fmode("w:utf-8")) { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "w:utf-8") { |f| f.gets } }.should.raise(IOError)
end
end
@@ -170,7 +187,7 @@ describe "IO#gets" do
before :each do
@name = tmp("io_gets")
touch(@name) { |f| f.write "one\n\ntwo\n\nthree\nfour\n" }
- @io = new_io @name, fmode("r:utf-8")
+ @io = new_io @name, "r:utf-8"
end
after :each do
@@ -226,6 +243,16 @@ describe "IO#gets" do
it "reads all bytes when pass a separator and reading more than all bytes" do
@io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n"
end
+
+ it "returns empty string when 0 passed as a limit" do
+ @io.gets(0).should == ""
+ @io.gets(nil, 0).should == ""
+ @io.gets("", 0).should == ""
+ end
+
+ it "does not accept limit that doesn't fit in a C off_t" do
+ -> { @io.gets(2**128) }.should.raise(RangeError)
+ end
end
describe "IO#gets" do
@@ -234,7 +261,7 @@ describe "IO#gets" do
# create data "朝日" + "\xE3\x81" * 100 to avoid utf-8 conflicts
data = "朝日" + ([227,129].pack('C*') * 100).force_encoding('utf-8')
touch(@name) { |f| f.write data }
- @io = new_io @name, fmode("r:utf-8")
+ @io = new_io @name, "r:utf-8"
end
after :each do
@@ -297,25 +324,25 @@ describe "IO#gets" do
end
it "overwrites the default external encoding with the IO object's own external encoding" do
- Encoding.default_external = Encoding::ASCII_8BIT
+ Encoding.default_external = Encoding::BINARY
Encoding.default_internal = Encoding::UTF_8
@io = new_io @name, 'r'
@io.set_encoding Encoding::IBM866
@io.gets.encoding.should == Encoding::UTF_8
end
- it "ignores the internal encoding if the default external encoding is ASCII-8BIT" do
- Encoding.default_external = Encoding::ASCII_8BIT
+ it "ignores the internal encoding if the default external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
Encoding.default_internal = Encoding::UTF_8
@io = new_io @name, 'r'
- @io.gets.encoding.should == Encoding::ASCII_8BIT
+ @io.gets.encoding.should == Encoding::BINARY
end
- it "transcodes to internal encoding if the IO object's external encoding is ASCII-8BIT" do
- Encoding.default_external = Encoding::ASCII_8BIT
+ it "ignores the internal encoding if the IO object's external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
Encoding.default_internal = Encoding::UTF_8
@io = new_io @name, 'r'
- @io.set_encoding Encoding::ASCII_8BIT, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::UTF_8
+ @io.set_encoding Encoding::BINARY, Encoding::UTF_8
+ @io.gets.encoding.should == Encoding::BINARY
end
end