Skip to content

Commit 216ba23

Browse files
committed
Fix StringIO#{gets, readline} when it is called with both separator and limit to truncate the separator if the limit is exceeded
1 parent a65bde3 commit 216ba23

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Compatibility:
2323
* Fix `Kernel#raise` and don't override `cause` at exception re-raising (#3831, @andrykonchin).
2424
* Return a pointer with `#type_size` of 1 for `Pointer#read_pointer` (@eregon).
2525
* Fix `rb_str_locktmp()` and `rb_str_unlocktmp()` to raise `FrozenError` when string argument is frozen (#3752, @andrykonchin).
26+
* Fix `StringIO#{gets,readline}` when it is called with both separator and limit to truncate the separator if the limit is exceeded (#3856, @andrykonchin).
2627

2728
Performance:
2829

lib/truffle/stringio.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ def yaml_initialize(type, val)
779779
end
780780
else
781781
if stop = Primitive.find_string(string, sep, pos)
782-
if limit && stop - pos >= limit
782+
if limit && stop - pos + sep.bytesize >= limit
783783
stop = pos + limit
784784
else
785785
stop += sep.bytesize

spec/ruby/library/stringio/gets_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@
190190
@io.gets('>', 5).should == "examp"
191191
end
192192

193+
it "truncates the multi-character separator at the end to meet the limit" do
194+
@io.gets("is>an", 7).should == "this>is"
195+
end
196+
193197
it "sets $_ to the read content" do
194198
@io.gets('>', 8)
195199
$_.should == "this>"

spec/ruby/library/stringio/readline_spec.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,61 @@
148148
@io.readline(-4).should == "this>is>an>example"
149149
end
150150
end
151+
152+
describe "StringIO#readline when passed [separator] and [limit]" do
153+
before :each do
154+
@io = StringIO.new("this>is>an>example")
155+
end
156+
157+
it "returns the data read until the limit is consumed or the separator is met" do
158+
@io.readline('>', 8).should == "this>"
159+
@io.readline('>', 2).should == "is"
160+
@io.readline('>', 10).should == ">"
161+
@io.readline('>', 6).should == "an>"
162+
@io.readline('>', 5).should == "examp"
163+
end
164+
165+
it "truncates the multi-character separator at the end to meet the limit" do
166+
@io.readline("is>an", 7).should == "this>is"
167+
end
168+
169+
it "sets $_ to the read content" do
170+
@io.readline('>', 8)
171+
$_.should == "this>"
172+
@io.readline('>', 2)
173+
$_.should == "is"
174+
@io.readline('>', 10)
175+
$_.should == ">"
176+
@io.readline('>', 6)
177+
$_.should == "an>"
178+
@io.readline('>', 5)
179+
$_.should == "examp"
180+
end
181+
182+
it "updates self's lineno by one" do
183+
@io.readline('>', 3)
184+
@io.lineno.should eql(1)
185+
186+
@io.readline('>', 3)
187+
@io.lineno.should eql(2)
188+
189+
@io.readline('>', 3)
190+
@io.lineno.should eql(3)
191+
end
192+
193+
it "tries to convert the passed separator to a String using #to_str" do
194+
obj = mock('to_str')
195+
obj.should_receive(:to_str).and_return('>')
196+
@io.readline(obj, 5).should == "this>"
197+
end
198+
199+
it "does not raise TypeError if passed separator is nil" do
200+
@io.readline(nil, 5).should == "this>"
201+
end
202+
203+
it "tries to convert the passed limit to an Integer using #to_int" do
204+
obj = mock('to_int')
205+
obj.should_receive(:to_int).and_return(5)
206+
@io.readline('>', obj).should == "this>"
207+
end
208+
end

0 commit comments

Comments
 (0)