Skip to content

Commit

Permalink
IO#gets should have same result regardless of #peek availability (c…
Browse files Browse the repository at this point in the history
…rystal-lang#13882)

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>
  • Loading branch information
compumike and Sija authored Oct 12, 2023
1 parent 8cd1481 commit 4867d81
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
34 changes: 34 additions & 0 deletions spec/std/io/io_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,40 @@ describe IO do
io.gets(chomp: false).should be_nil
end

it "does gets with empty string (no peek)" do
io = SimpleIOMemory.new("")
io.gets(chomp: true).should be_nil
end

it "does gets with empty string (with peek)" do
io = IO::Memory.new("")
io.gets(chomp: true).should be_nil
end

it "does gets with \\n (no peek)" do
io = SimpleIOMemory.new("\n")
io.gets(chomp: true).should eq("")
io.gets(chomp: true).should be_nil
end

it "does gets with \\n (with peek)" do
io = IO::Memory.new("\n")
io.gets(chomp: true).should eq("")
io.gets(chomp: true).should be_nil
end

it "does gets with \\r\\n (no peek)" do
io = SimpleIOMemory.new("\r\n")
io.gets(chomp: true).should eq("")
io.gets(chomp: true).should be_nil
end

it "does gets with \\r\\n (with peek)" do
io = IO::Memory.new("\r\n")
io.gets(chomp: true).should eq("")
io.gets(chomp: true).should be_nil
end

it "does gets with big line" do
big_line = "a" * 20_000
io = SimpleIOMemory.new("#{big_line}\nworld\n")
Expand Down
10 changes: 7 additions & 3 deletions src/io.cr
Original file line number Diff line number Diff line change
Expand Up @@ -752,11 +752,12 @@ abstract class IO

private def gets_slow(delimiter : Char, limit, chomp)
buffer = String::Builder.new
gets_slow(delimiter, limit, chomp, buffer)
buffer.empty? ? nil : buffer.to_s
bytes_read = gets_slow(delimiter, limit, chomp, buffer)
buffer.to_s if bytes_read
end

private def gets_slow(delimiter : Char, limit, chomp, buffer : String::Builder) : Nil
private def gets_slow(delimiter : Char, limit, chomp, buffer : String::Builder) : Bool
bytes_read = false
chomp_rn = delimiter == '\n' && chomp

while true
Expand All @@ -766,6 +767,7 @@ abstract class IO
end

char, char_bytesize = info
bytes_read = true

# Consider the case of \r\n when the delimiter is \n and chomp = true
if chomp_rn && char == '\r'
Expand Down Expand Up @@ -801,6 +803,8 @@ abstract class IO
break if char_bytesize >= limit
limit -= char_bytesize
end

bytes_read
end

# Reads until *delimiter* is found or the end of the `IO` is reached.
Expand Down

0 comments on commit 4867d81

Please sign in to comment.