Index: src/test/groovy/StringTest.groovy =================================================================== --- src/test/groovy/StringTest.groovy (revision 15021) +++ src/test/groovy/StringTest.groovy (working copy) @@ -174,8 +174,8 @@ void testNormalize() { assert "a".normalize() == "a" - assert "a\n".normalize() == "a" - assert "a\n\n".normalize() == "a\n" + assert "a\n".normalize() == "a\n" + assert "a\n\n".normalize() == "a\n\n" assert "a\nb\rc\r\nd".normalize() == "a\nb\nc\nd" assert "a\n\nb".normalize() == "a\n\nb" } @@ -186,7 +186,7 @@ assert 'a\n'.denormalize() == 'a' + LS assert 'a\n\n'.denormalize() == 'a' + LS + LS assert 'a\n\nb'.denormalize() == 'a' + LS + LS + 'b' - assert 'a\nb\r\nc\n\rd'.denormalize() == 'a' + LS + 'b' + LS + 'c' + LS + 'd' + assert 'a\nb\r\nc\n\rd'.denormalize() == 'a' + LS + 'b\r' + LS + 'c' + LS + '\rd' } void testSplitEqualsTokenize() { Index: src/test/groovy/bugs/Groovy3235Bug.groovy =================================================================== --- src/test/groovy/bugs/Groovy3235Bug.groovy (revision 15021) +++ src/test/groovy/bugs/Groovy3235Bug.groovy (working copy) @@ -2,9 +2,12 @@ public class Groovy3235Bug extends GroovyTestCase { - void testBug () { +void testBug () { def d = """This is one line. - This is another. + + That was an empty line. + Another empty line follows. + All these lines should be written. """ def f = File.createTempFile("groovy.bugs.Groovy3235Bug", ".txt") @@ -13,6 +16,10 @@ d.eachLine { w.println it } } - assert d.readLines() == f.readLines() + def t = f.text + + assert d == t.normalize() + + assert d.denormalize() == t } } Index: src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java =================================================================== --- src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java (revision 15021) +++ src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java (working copy) @@ -9110,57 +9110,50 @@ return readLines(new StringReader(self)); } + static String lineSeparator = null; + /** - * Return a String with linefeeds denormalized to the platform specific - * end of line character. Algorithm used is throw away all '\r' chars - * and replace all '\n' chars with platform 'line.separator' char. + * Return a String with linefeeds replaced by the platform specific + * end of line character. * * @param self a String object * @return the denormalized string - * @throws java.io.IOException if an error occurs * @since 1.6.0 - * @see groovy.io.PlatformLineWriter */ - public static String denormalize(String self) throws IOException { - StringWriter result = new StringWriter(self.length()); - PlatformLineWriter w = new PlatformLineWriter(result, self.length()); - try { - w.write(self); - } finally { - closeWithWarning(w); + public static String denormalize(String self) { + if (lineSeparator == null) { + StringWriter sw = new StringWriter(2); + try { + BufferedWriter bw = new BufferedWriter(sw); + bw.newLine(); + bw.flush(); + lineSeparator = sw.toString(); + } catch (IOException ioe) { + lineSeparator = "\n"; + } } - return result.toString(); + + if (!lineSeparator.equals("\n")) { + self = self.replace("\n", lineSeparator); + } + + return self; } /** * Return a String with linefeeds and carriage returns normalized to linefeeds. - * The last trailing linefeed (after normalization) if found is removed. * * @param self a String object * @return the normalized string - * @throws java.io.IOException if an error occurs * @since 1.6.0 */ - public static String normalize(String self) throws IOException { - // for efficiency, we don't use: return join(readLines(self), "\n"); - BufferedReader br = new BufferedReader(new StringReader(self)); - StringBuilder sb = new StringBuilder(self.length()); - boolean first = true; - try { - while (true) { - String line = br.readLine(); - if (line == null) { - break; - } else { - if (first) first = false; - else sb.append("\n"); - sb.append(line); - } - } - } finally { - closeWithWarning(br); + public static String normalize(String self) { + if (self.contains("\r")) { + self = self.replace("\r\n", "\n"); + self = self.replace('\r', '\n'); } - return sb.toString(); + + return self; } /**