From f4bd113e19dfeea8977600909ada8302f580db06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Le=20Callonnec?= Date: Sat, 11 May 2013 09:01:39 +0100 Subject: [PATCH] Fix string concatenation with a number as per rubyspec behaviour. Following https://github.com/tychobrailleur/jcodings/commit/8536b4fdeecf3dec31ca868803654b3ab7829915, the incorrect behaviour of String#concat with a number was made obvious by throwing an EncodingException. MRI changes the encoding of the String if the concatenated codepoint is within ASCII-8BIT range, and throws a RangeError otherwise. --- .../tags/1.9/ruby/core/string/concat_tags.txt | 2 -- src/org/jruby/RubyString.java | 21 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/spec/tags/1.9/ruby/core/string/concat_tags.txt b/spec/tags/1.9/ruby/core/string/concat_tags.txt index a6dbfa04444..8baa2501382 100644 --- a/spec/tags/1.9/ruby/core/string/concat_tags.txt +++ b/spec/tags/1.9/ruby/core/string/concat_tags.txt @@ -1,3 +1 @@ -fails:String#concat with Integer returns a ASCII-8BIT string if self is US-ASCII and the argument is between 128-255 (inclusive) -fails:String#concat with Integer raises RangeError if the argument is an invalid codepoint for self's encoding fails:String#concat when self is ASCII-8BIT and argument is US-ASCII uses ASCII-8BIT encoding diff --git a/src/org/jruby/RubyString.java b/src/org/jruby/RubyString.java index 693f391fc59..9e16d4dc194 100644 --- a/src/org/jruby/RubyString.java +++ b/src/org/jruby/RubyString.java @@ -69,6 +69,7 @@ import org.jcodings.EncodingDB; import org.jcodings.ascii.AsciiTables; import org.jcodings.constants.CharacterType; +import org.jcodings.exception.EncodingException; import org.jcodings.specific.ASCIIEncoding; import org.jcodings.specific.USASCIIEncoding; import org.jcodings.specific.UTF8Encoding; @@ -2635,9 +2636,23 @@ public RubyString concat19(ThreadContext context, IRubyObject other) { private RubyString concatNumeric(Ruby runtime, int c) { Encoding enc = value.getEncoding(); - int cl = codeLength(runtime, enc, c); - modify19(value.getRealSize() + cl); - enc.codeToMbc(c, value.getUnsafeBytes(), value.getBegin() + value.getRealSize()); + int cl; + + try { + cl = codeLength(runtime, enc, c); + modify19(value.getRealSize() + cl); + + if (enc == USASCIIEncoding.INSTANCE) { + if (c > 0xff) runtime.newRangeError(c + " out of char range"); + if (c > 0x79) { + value.setEncoding(ASCIIEncoding.INSTANCE); + enc = value.getEncoding(); + } + } + enc.codeToMbc(c, value.getUnsafeBytes(), value.getBegin() + value.getRealSize()); + } catch (EncodingException e) { + throw runtime.newRangeError(c + " out of char range"); + } value.setRealSize(value.getRealSize() + cl); return this; }