Skip to content

Commit

Permalink
Fix: Honour encoding in IO::Memory#to_s (#11875)
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota authored Mar 17, 2022
1 parent 06855cd commit 03ed280
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
31 changes: 31 additions & 0 deletions spec/std/io/memory_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,37 @@ describe IO::Memory do
# Ensure that the buffer is resized, otherwise the spec doesn't work
io.@capacity.should_not eq old_capacity
end

{% if flag?(:without_iconv) %}
pending "encoding"
{% else %}
describe "encoding" do
it "returns String" do
io = IO::Memory.new
io.set_encoding "UTF-16LE"
io << "abc"
io.to_s.should eq "abc"
io.to_slice.should eq Bytes[0x61, 0, 0x62, 0, 0x63, 0]
end

it "writes to IO" do
io1 = IO::Memory.new
io1.set_encoding "UTF-32LE"

io2 = IO::Memory.new
io2.set_encoding "UTF-16LE"

io1.write_utf8 "abc😂".to_slice
io1.to_s io2
byte_slice = io2.to_slice
utf16_slice = Slice.new(byte_slice.to_unsafe.unsafe_as(Pointer(UInt16)), byte_slice.size // sizeof(UInt16))

String.from_utf16(utf16_slice).should eq "abc😂"
byte_slice.should eq Bytes[0x61, 0, 0x62, 0, 0x63, 0, 0x3D, 0xD8, 0x02, 0xDE]
utf16_slice.should eq Slice[0x0061, 0x0062, 0x0063, 0xD83D, 0xDE02]
end
end
{% end %}
end

it "reads single line content" do
Expand Down
20 changes: 18 additions & 2 deletions src/io/memory.cr
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,15 @@ class IO::Memory < IO
# io.to_s # => "123"
# ```
def to_s : String
String.new @buffer, @bytesize
if encoding = @encoding
{% if flag?(:without_iconv) %}
raise NotImplementedError.new("String.encode")
{% else %}
String.new to_slice, encoding: encoding.name, invalid: encoding.invalid
{% end %}
else
String.new @buffer, @bytesize
end
end

# Returns the underlying bytes.
Expand All @@ -427,7 +435,15 @@ class IO::Memory < IO
new_bytesize = bytesize * 2
resize_to_capacity(new_bytesize) if @capacity < new_bytesize
end
io.write(to_slice)
if encoding = @encoding
{% if flag?(:without_iconv) %}
raise NotImplementedError.new("String.encode")
{% else %}
String.encode(to_slice, encoding.name, io.encoding, io, io.@encoding.try(&.invalid))
{% end %}
else
io.write(to_slice)
end
end

private def check_writeable
Expand Down
2 changes: 1 addition & 1 deletion src/string.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ class String
end

# :nodoc:
protected def self.encode(slice, from, to, io, invalid)
def self.encode(slice, from, to, io, invalid)
IO::EncodingOptions.check_invalid(invalid)

inbuf_ptr = slice.to_unsafe
Expand Down

0 comments on commit 03ed280

Please sign in to comment.