View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.text;
18  
19  import org.junit.Test;
20  
21  import java.io.IOException;
22  import java.io.StringWriter;
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.Modifier;
25  import java.nio.charset.Charset;
26  import java.nio.charset.StandardCharsets;
27  import java.nio.file.Files;
28  import java.nio.file.Paths;
29  
30  import static org.apache.commons.text.StringEscapeUtils.escapeXSI;
31  import static org.apache.commons.text.StringEscapeUtils.unescapeXSI;
32  import static org.junit.Assert.assertEquals;
33  import static org.junit.Assert.assertFalse;
34  import static org.junit.Assert.assertNotNull;
35  import static org.junit.Assert.assertNull;
36  import static org.junit.Assert.assertTrue;
37  import static org.junit.Assert.fail;
38  
39  /**
40   * Unit tests for {@link StringEscapeUtils}.
41   *
42   * <p>
43   * This code has been adapted from Apache Commons Lang 3.5.
44   * </p>
45   *
46   */
47  public class StringEscapeUtilsTest {
48      private static final String FOO = "foo";
49  
50      @Test
51      public void testConstructor() {
52          assertNotNull(new StringEscapeUtils());
53          final Constructor<?>[] cons = StringEscapeUtils.class.getDeclaredConstructors();
54          assertEquals(1, cons.length);
55          assertTrue(Modifier.isPublic(cons[0].getModifiers()));
56          assertTrue(Modifier.isPublic(StringEscapeUtils.class.getModifiers()));
57          assertFalse(Modifier.isFinal(StringEscapeUtils.class.getModifiers()));
58      }
59  
60      @Test
61      public void testEscapeJava() throws IOException {
62          assertNull(StringEscapeUtils.escapeJava(null));
63          try {
64              StringEscapeUtils.ESCAPE_JAVA.translate(null, null);
65              fail();
66          } catch (final IOException ex) {
67              fail();
68          } catch (final IllegalArgumentException ex) {
69          }
70          try {
71              StringEscapeUtils.ESCAPE_JAVA.translate("", null);
72              fail();
73          } catch (final IOException ex) {
74              fail();
75          } catch (final IllegalArgumentException ex) {
76          }
77  
78          assertEscapeJava("empty string", "", "");
79          assertEscapeJava(FOO, FOO);
80          assertEscapeJava("tab", "\\t", "\t");
81          assertEscapeJava("backslash", "\\\\", "\\");
82          assertEscapeJava("single quote should not be escaped", "'", "'");
83          assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r");
84          assertEscapeJava("\\u1234", "\u1234");
85          assertEscapeJava("\\u0234", "\u0234");
86          assertEscapeJava("\\u00EF", "\u00ef");
87          assertEscapeJava("\\u0001", "\u0001");
88          assertEscapeJava("Should use capitalized Unicode hex", "\\uABCD", "\uabcd");
89  
90          assertEscapeJava("He didn't say, \\\"stop!\\\"",
91                  "He didn't say, \"stop!\"");
92          assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\\u00A0",
93                  "This space is non-breaking:\u00a0");
94          assertEscapeJava("\\uABCD\\u1234\\u012C",
95                  "\uABCD\u1234\u012C");
96      }
97  
98      /**
99       * Tests https://issues.apache.org/jira/browse/LANG-421
100      */
101     @Test
102     public void testEscapeJavaWithSlash() {
103         final String input = "String with a slash (/) in it";
104 
105         final String expected = input;
106         final String actual = StringEscapeUtils.escapeJava(input);
107 
108         /**
109          * In 2.4 StringEscapeUtils.escapeJava(String) escapes '/' characters, which are not a valid character
110          * to escape in a Java string.
111          */
112         assertEquals(expected, actual);
113     }
114 
115     private void assertEscapeJava(final String escaped, final String original) throws IOException {
116         assertEscapeJava(null, escaped, original);
117     }
118 
119     private void assertEscapeJava(String message, final String expected, final String original) throws IOException {
120         final String converted = StringEscapeUtils.escapeJava(original);
121         message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
122         assertEquals(message, expected, converted);
123 
124         final StringWriter writer = new StringWriter();
125         StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
126         assertEquals(expected, writer.toString());
127     }
128 
129     @Test
130     public void testUnescapeJava() throws IOException {
131         assertNull(StringEscapeUtils.unescapeJava(null));
132         try {
133             StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
134             fail();
135         } catch (final IOException ex) {
136             fail();
137         } catch (final IllegalArgumentException ex) {
138         }
139         try {
140             StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
141             fail();
142         } catch (final IOException ex) {
143             fail();
144         } catch (final IllegalArgumentException ex) {
145         }
146         try {
147             StringEscapeUtils.unescapeJava("\\u02-3");
148             fail();
149         } catch (final RuntimeException ex) {
150         }
151 
152         assertUnescapeJava("", "");
153         assertUnescapeJava("test", "test");
154         assertUnescapeJava("\ntest\b", "\\ntest\\b");
155         assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
156         assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
157         assertUnescapeJava("", "\\");
158         //foo
159         assertUnescapeJava("lowercase Unicode", "\uABCDx", "\\uabcdx");
160         assertUnescapeJava("uppercase Unicode", "\uABCDx", "\\uABCDx");
161         assertUnescapeJava("Unicode as final character", "\uABCD", "\\uabcd");
162     }
163 
164     private void assertUnescapeJava(final String unescaped, final String original) throws IOException {
165         assertUnescapeJava(null, unescaped, original);
166     }
167 
168     private void assertUnescapeJava(final String message, final String unescaped, final String original)
169             throws IOException {
170         final String expected = unescaped;
171         final String actual = StringEscapeUtils.unescapeJava(original);
172 
173         assertEquals("unescape(String) failed"
174                         + (message == null ? "" : (": " + message))
175                         + ": expected '" + StringEscapeUtils.escapeJava(expected)
176                         // we escape this so we can see it in the error message
177                         + "' actual '" + StringEscapeUtils.escapeJava(actual) + "'",
178                 expected, actual);
179 
180         final StringWriter writer = new StringWriter();
181         StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
182         assertEquals(unescaped, writer.toString());
183     }
184 
185     @Test
186     public void testEscapeEcmaScript() {
187         assertNull(StringEscapeUtils.escapeEcmaScript(null));
188         try {
189             StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
190             fail();
191         } catch (final IOException ex) {
192             fail();
193         } catch (final IllegalArgumentException ex) {
194         }
195         try {
196             StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
197             fail();
198         } catch (final IOException ex) {
199             fail();
200         } catch (final IllegalArgumentException ex) {
201         }
202 
203         assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
204         assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
205                 StringEscapeUtils.escapeEcmaScript(
206                         "document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
207     }
208 
209 
210     // HTML and XML
211     //--------------------------------------------------------------
212 
213     private static final String[][] HTML_ESCAPES = {
214             {"no escaping", "plain text", "plain text"},
215             {"no escaping", "plain text", "plain text"},
216             {"empty string", "", ""},
217             {"null", null, null},
218             {"ampersand", "bread &amp; butter", "bread & butter"},
219             {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
220             {"final character only", "greater than &gt;", "greater than >"},
221             {"first character only", "&lt; less than", "< less than"},
222             {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
223             {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)",
224                 "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
225             {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
226     };
227 
228     @Test
229     public void testEscapeHtml3() {
230         for (final String[] element : HTML_ESCAPES) {
231             final String message = element[0];
232             final String expected = element[1];
233             final String original = element[2];
234             assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
235             final StringWriter sw = new StringWriter();
236             try {
237                 StringEscapeUtils.ESCAPE_HTML3.translate(original, sw);
238             } catch (final IOException e) {
239             }
240             final String actual = original == null ? null : sw.toString();
241             assertEquals(message, expected, actual);
242         }
243     }
244 
245     @Test
246     public void testUnescapeHtml3() {
247         for (final String[] element : HTML_ESCAPES) {
248             final String message = element[0];
249             final String expected = element[2];
250             final String original = element[1];
251             assertEquals(message, expected, StringEscapeUtils.unescapeHtml3(original));
252 
253             final StringWriter sw = new StringWriter();
254             try {
255                 StringEscapeUtils.UNESCAPE_HTML3.translate(original, sw);
256             } catch (final IOException e) {
257             }
258             final String actual = original == null ? null : sw.toString();
259             assertEquals(message, expected, actual);
260         }
261         // \u00E7 is a cedilla (c with wiggle under)
262         // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
263         // on some locales
264         assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml3("Fran\u00E7ais"));
265 
266         assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml3("Hello&;World"));
267         assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml3("Hello&#;World"));
268         assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml3("Hello&# ;World"));
269         assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml3("Hello&##;World"));
270     }
271 
272 @Test
273     public void testEscapeHtml4() {
274         for (final String[] element : HTML_ESCAPES) {
275             final String message = element[0];
276             final String expected = element[1];
277             final String original = element[2];
278             assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
279             final StringWriter sw = new StringWriter();
280             try {
281                 StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
282             } catch (final IOException e) {
283             }
284             final String actual = original == null ? null : sw.toString();
285             assertEquals(message, expected, actual);
286         }
287     }
288 
289     @Test
290     public void testUnescapeHtml4() {
291         for (final String[] element : HTML_ESCAPES) {
292             final String message = element[0];
293             final String expected = element[2];
294             final String original = element[1];
295             assertEquals(message, expected, StringEscapeUtils.unescapeHtml4(original));
296 
297             final StringWriter sw = new StringWriter();
298             try {
299                 StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
300             } catch (final IOException e) {
301             }
302             final String actual = original == null ? null : sw.toString();
303             assertEquals(message, expected, actual);
304         }
305         // \u00E7 is a cedilla (c with wiggle under)
306         // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
307         // on some locales
308         assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"));
309 
310         assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
311         assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
312         assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
313         assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
314     }
315 
316     @Test
317     public void testUnescapeHexCharsHtml() {
318         // Simple easy to grok test
319         assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"));
320         assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"));
321         // Test all Character values:
322         for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
323             final Character c1 = i;
324             final Character c2 = (char) (i + 1);
325             final String expected = c1.toString() + c2.toString();
326             final String escapedC1 = "&#x" + Integer.toHexString(c1) + ";";
327             final String escapedC2 = "&#x" + Integer.toHexString(c2) + ";";
328             assertEquals("hex number unescape index " + i, expected,
329                     StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2));
330         }
331     }
332 
333     @Test
334     public void testUnescapeUnknownEntity() {
335         assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
336     }
337 
338     @Test
339     public void testEscapeHtmlVersions() {
340         assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
341         assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
342 
343         // TODO: refine API for escaping/unescaping specific HTML versions
344     }
345 
346 
347 
348     @Test
349     public void testEscapeXml10() {
350         assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml10("a<b>c\"d'e&f"));
351         assertEquals("XML 1.0 should not escape \t \n \r",
352                 "a\tb\rc\nd", StringEscapeUtils.escapeXml10("a\tb\rc\nd"));
353         assertEquals("XML 1.0 should omit most #x0-x8 | #xb | #xc | #xe-#x19",
354                 "ab", StringEscapeUtils.escapeXml10("a\u0000\u0001\u0008\u000b\u000c\u000e\u001fb"));
355         assertEquals("XML 1.0 should omit #xd800-#xdfff",
356                 "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml10("a\ud7ff\ud800 \udfff \ue000b"));
357         assertEquals("XML 1.0 should omit #xfffe | #xffff",
358                 "a\ufffdb", StringEscapeUtils.escapeXml10("a\ufffd\ufffe\uffffb"));
359         assertEquals("XML 1.0 should escape #x7f-#x84 | #x86 - #x9f, for XML 1.1 compatibility",
360                 "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b",
361                 StringEscapeUtils.escapeXml10("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
362     }
363 
364     @Test
365     public void testEscapeXml11() {
366         assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml11("a<b>c\"d'e&f"));
367         assertEquals("XML 1.1 should not escape \t \n \r",
368                 "a\tb\rc\nd", StringEscapeUtils.escapeXml11("a\tb\rc\nd"));
369         assertEquals("XML 1.1 should omit #x0",
370                 "ab", StringEscapeUtils.escapeXml11("a\u0000b"));
371         assertEquals("XML 1.1 should escape #x1-x8 | #xb | #xc | #xe-#x19",
372                 "a&#1;&#8;&#11;&#12;&#14;&#31;b",
373                 StringEscapeUtils.escapeXml11("a\u0001\u0008\u000b\u000c\u000e\u001fb"));
374         assertEquals("XML 1.1 should escape #x7F-#x84 | #x86-#x9F",
375                 "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b",
376                 StringEscapeUtils.escapeXml11("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
377         assertEquals("XML 1.1 should omit #xd800-#xdfff",
378                 "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml11("a\ud7ff\ud800 \udfff \ue000b"));
379         assertEquals("XML 1.1 should omit #xfffe | #xffff",
380                 "a\ufffdb", StringEscapeUtils.escapeXml11("a\ufffd\ufffe\uffffb"));
381     }
382 
383     /**
384      * Reverse of the above.
385      *
386      * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
387      */
388     @Test
389     public void testUnescapeXmlSupplementaryCharacters() {
390         assertEquals("Supplementary character must be represented using a single escape", "\uD84C\uDFB4",
391                 StringEscapeUtils.unescapeXml("&#144308;"));
392 
393         assertEquals("Supplementary characters mixed with basic characters should be decoded correctly",
394                 "a b c \uD84C\uDFB4", StringEscapeUtils.unescapeXml("a b c &#144308;"));
395     }
396 
397     // Tests issue #38569
398     // http://issues.apache.org/bugzilla/show_bug.cgi?id=38569
399     @Test
400     public void testStandaloneAmphersand() {
401         assertEquals("<P&O>", StringEscapeUtils.unescapeHtml4("&lt;P&O&gt;"));
402         assertEquals("test & <", StringEscapeUtils.unescapeHtml4("test & &lt;"));
403         assertEquals("<P&O>", StringEscapeUtils.unescapeXml("&lt;P&O&gt;"));
404         assertEquals("test & <", StringEscapeUtils.unescapeXml("test & &lt;"));
405     }
406 
407     @Test
408     public void testLang313() {
409         assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
410     }
411 
412     @Test
413     public void testEscapeCsvString() {
414         assertEquals("foo.bar", StringEscapeUtils.escapeCsv("foo.bar"));
415         assertEquals("\"foo,bar\"", StringEscapeUtils.escapeCsv("foo,bar"));
416         assertEquals("\"foo\nbar\"", StringEscapeUtils.escapeCsv("foo\nbar"));
417         assertEquals("\"foo\rbar\"", StringEscapeUtils.escapeCsv("foo\rbar"));
418         assertEquals("\"foo\"\"bar\"", StringEscapeUtils.escapeCsv("foo\"bar"));
419         assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar"));
420         assertEquals("", StringEscapeUtils.escapeCsv(""));
421         assertNull(StringEscapeUtils.escapeCsv(null));
422     }
423 
424     @Test
425     public void testEscapeCsvWriter() {
426         checkCsvEscapeWriter("foo.bar", "foo.bar");
427         checkCsvEscapeWriter("\"foo,bar\"", "foo,bar");
428         checkCsvEscapeWriter("\"foo\nbar\"", "foo\nbar");
429         checkCsvEscapeWriter("\"foo\rbar\"", "foo\rbar");
430         checkCsvEscapeWriter("\"foo\"\"bar\"", "foo\"bar");
431         checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
432         checkCsvEscapeWriter("", null);
433         checkCsvEscapeWriter("", "");
434     }
435 
436     private void checkCsvEscapeWriter(final String expected, final String value) {
437         try {
438             final StringWriter writer = new StringWriter();
439             StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
440             assertEquals(expected, writer.toString());
441         } catch (final IOException e) {
442             fail("Threw: " + e);
443         }
444     }
445 
446     @Test
447     public void testUnescapeCsvString() {
448         assertEquals("foo.bar", StringEscapeUtils.unescapeCsv("foo.bar"));
449         assertEquals("foo,bar", StringEscapeUtils.unescapeCsv("\"foo,bar\""));
450         assertEquals("foo\nbar", StringEscapeUtils.unescapeCsv("\"foo\nbar\""));
451         assertEquals("foo\rbar", StringEscapeUtils.unescapeCsv("\"foo\rbar\""));
452         assertEquals("foo\"bar", StringEscapeUtils.unescapeCsv("\"foo\"\"bar\""));
453         assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.unescapeCsv("foo\uD84C\uDFB4bar"));
454         assertEquals("", StringEscapeUtils.unescapeCsv(""));
455         assertNull(StringEscapeUtils.unescapeCsv(null));
456 
457         assertEquals("\"foo.bar\"", StringEscapeUtils.unescapeCsv("\"foo.bar\""));
458     }
459 
460     @Test
461     public void testUnescapeCsvWriter() {
462         checkCsvUnescapeWriter("foo.bar", "foo.bar");
463         checkCsvUnescapeWriter("foo,bar", "\"foo,bar\"");
464         checkCsvUnescapeWriter("foo\nbar", "\"foo\nbar\"");
465         checkCsvUnescapeWriter("foo\rbar", "\"foo\rbar\"");
466         checkCsvUnescapeWriter("foo\"bar", "\"foo\"\"bar\"");
467         checkCsvUnescapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
468         checkCsvUnescapeWriter("", null);
469         checkCsvUnescapeWriter("", "");
470 
471         checkCsvUnescapeWriter("\"foo.bar\"", "\"foo.bar\"");
472     }
473 
474     private void checkCsvUnescapeWriter(final String expected, final String value) {
475         try {
476             final StringWriter writer = new StringWriter();
477             StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
478             assertEquals(expected, writer.toString());
479         } catch (final IOException e) {
480             fail("Threw: " + e);
481         }
482     }
483 
484     /**
485      * Tests // https://issues.apache.org/jira/browse/LANG-480
486      */
487     @Test
488     public void testEscapeHtmlHighUnicode() {
489         // this is the utf8 representation of the character:
490         // COUNTING ROD UNIT DIGIT THREE
491         // in Unicode
492         // codepoint: U+1D362
493         final byte[] data = {(byte) 0xF0, (byte) 0x9D, (byte) 0x8D, (byte) 0xA2};
494 
495         final String original = new String(data, Charset.forName("UTF8"));
496 
497         final String escaped = StringEscapeUtils.escapeHtml4(original);
498         assertEquals("High Unicode should not have been escaped", original, escaped);
499 
500         final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
501         assertEquals("High Unicode should have been unchanged", original, unescaped);
502 
503         // TODO: I think this should hold, needs further investigation
504         //        String unescapedFromEntity = StringEscapeUtils.unescapeHtml4("&#119650;");
505         //        assertEquals("High Unicode should have been unescaped", original, unescapedFromEntity);
506     }
507 
508     /**
509      * Tests https://issues.apache.org/jira/browse/LANG-339
510      */
511     @Test
512     public void testEscapeHiragana() {
513         // Some random Japanese Unicode characters
514         final String original = "\u304B\u304C\u3068";
515         final String escaped = StringEscapeUtils.escapeHtml4(original);
516         assertEquals("Hiragana character Unicode behaviour should not be being escaped by escapeHtml4",
517                 original, escaped);
518 
519         final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
520 
521         assertEquals("Hiragana character Unicode behaviour has changed - expected no unescaping", escaped, unescaped);
522     }
523 
524     /**
525      * Tests https://issues.apache.org/jira/browse/LANG-708
526      *
527      * @throws IOException
528      *             if an I/O error occurs
529      */
530     @Test
531     public void testLang708() throws IOException {
532         final byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/stringEscapeUtilsTestData.txt"));
533         final String input = new String(inputBytes, StandardCharsets.UTF_8);
534         final String escaped = StringEscapeUtils.escapeEcmaScript(input);
535         // just the end:
536         assertTrue(escaped, escaped.endsWith("}]"));
537         // a little more:
538         assertTrue(escaped, escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"));
539     }
540 
541     /**
542      * Tests https://issues.apache.org/jira/browse/LANG-911
543      */
544     @Test
545     public void testLang911() {
546         final String bellsTest = "\ud83d\udc80\ud83d\udd14";
547         final String value = StringEscapeUtils.escapeJava(bellsTest);
548         final String valueTest = StringEscapeUtils.unescapeJava(value);
549         assertEquals(bellsTest, valueTest);
550     }
551 
552     @Test
553     public void testEscapeJson() {
554         assertNull(StringEscapeUtils.escapeJson(null));
555         try {
556             StringEscapeUtils.ESCAPE_JSON.translate(null, null);
557             fail();
558         } catch (final IOException ex) {
559             fail();
560         } catch (final IllegalArgumentException ex) {
561         }
562         try {
563             StringEscapeUtils.ESCAPE_JSON.translate("", null);
564             fail();
565         } catch (final IOException ex) {
566             fail();
567         } catch (final IllegalArgumentException ex) {
568         }
569 
570         assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\""));
571 
572         final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/";
573         final String input = "\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/";
574 
575         assertEquals(expected, StringEscapeUtils.escapeJson(input));
576     }
577 
578     @Test
579     public void testBuilder() {
580         final String result =
581                 StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString();
582         assertEquals("&lt;>", result);
583     }
584 
585     @Test
586     public void testEscapeXSI() {
587         assertNull(null, escapeXSI(null));
588         assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\""));
589         assertEquals("\\\\", escapeXSI("\\"));
590         assertEquals("", escapeXSI("\n"));
591     }
592 
593     @Test
594     public void testUnscapeXSI() {
595         assertNull(null, unescapeXSI(null));
596         assertEquals("\"", unescapeXSI("\\\""));
597         assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\""));
598         assertEquals("\\", unescapeXSI("\\\\"));
599         assertEquals("", unescapeXSI("\\"));
600     }
601 
602     @Test
603     public void testUnescapeEcmaScript() {
604         assertNull("Should be null.", StringEscapeUtils.unescapeEcmaScript(null));
605         assertEquals("8lvc1u+6B#-I", StringEscapeUtils.unescapeEcmaScript("8lvc1u+6B#-I"));
606         assertEquals("<script src=\"build/main.bundle.js\"></script>",
607                 StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>"));
608         assertEquals("<script src=\"build/main.bundle.js\"></script>>",
609                 StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>>"));
610     }
611 
612     @Test
613     public void testEscapeHtmlThree() {
614         assertNull("Should be null.", StringEscapeUtils.escapeHtml3(null));
615         assertEquals("a", StringEscapeUtils.escapeHtml3("a"));
616         assertEquals("&lt;b&gt;a", StringEscapeUtils.escapeHtml3("<b>a"));
617     }
618 
619     @Test
620     public void testUnescapeJson() {
621         final String jsonString =
622                 "{\"age\":100,\"name\":\"kyong.com\n\",\"messages\":[\"msg 1\",\"msg 2\",\"msg 3\"]}";
623 
624         assertEquals("", StringEscapeUtils.unescapeJson(""));
625         assertEquals(" ", StringEscapeUtils.unescapeJson(" "));
626         assertEquals("a:b", StringEscapeUtils.unescapeJson("a:b"));
627         assertEquals(jsonString, StringEscapeUtils.unescapeJson(jsonString));
628     }
629 
630     @Test
631     public void testUnescapeJsonFoundBug_Issue_Text_100() {
632         final String jsonString =
633                 "{\"age\":100,\"name\":\"m\\\"kyong.com\",\"messages\":[\"msg 1\",\"msg 2\",\"msg 3\"]}";
634 
635         assertEquals(jsonString, StringEscapeUtils.unescapeJson(jsonString));
636     }
637 
638     @Test
639     public void testUnescapeJsonFoundBug_Issue_Text_100_Fix() {
640         final String jsonString =
641                 "{\"age\":100,\"name\":\"n\\\"m\\\"kyong.com\",\"messages\":[\"msg 1\",\"msg 2\",\"msg 3\"]}";
642 
643         assertEquals(jsonString, StringEscapeUtils.unescapeJson(jsonString));
644     }
645 }