1 /*
2  * Copyright (C) 2009 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.xml;
18 
19 import static com.google.common.escape.testing.EscaperAsserts.assertEscaping;
20 import static com.google.common.escape.testing.EscaperAsserts.assertUnescaped;
21 
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.escape.CharEscaper;
24 import junit.framework.TestCase;
25 
26 /**
27  * Tests for the {@link XmlEscapers} class.
28  *
29  * @author Alex Matevossian
30  * @author David Beaumont
31  */
32 @GwtCompatible
33 public class XmlEscapersTest extends TestCase {
34 
testXmlContentEscaper()35   public void testXmlContentEscaper() throws Exception {
36     CharEscaper xmlContentEscaper = (CharEscaper) XmlEscapers.xmlContentEscaper();
37     assertBasicXmlEscaper(xmlContentEscaper, false, false);
38     // Test quotes are not escaped.
39     assertEquals("\"test\"", xmlContentEscaper.escape("\"test\""));
40     assertEquals("'test'", xmlContentEscaper.escape("'test'"));
41   }
42 
testXmlAttributeEscaper()43   public void testXmlAttributeEscaper() throws Exception {
44     CharEscaper xmlAttributeEscaper = (CharEscaper) XmlEscapers.xmlAttributeEscaper();
45     assertBasicXmlEscaper(xmlAttributeEscaper, true, true);
46     // Test quotes are escaped.
47     assertEquals(""test"", xmlAttributeEscaper.escape("\"test\""));
48     assertEquals("'test'", xmlAttributeEscaper.escape("\'test'"));
49     // Test all escapes
50     assertEquals(
51         "a&quot;b&lt;c&gt;d&amp;e&quot;f&apos;", xmlAttributeEscaper.escape("a\"b<c>d&e\"f'"));
52     // Test '\t', '\n' and '\r' are escaped.
53     assertEquals("a&#x9;b&#xA;c&#xD;d", xmlAttributeEscaper.escape("a\tb\nc\rd"));
54   }
55 
56   // Helper to assert common properties of xml escapers.
assertBasicXmlEscaper( CharEscaper xmlEscaper, boolean shouldEscapeQuotes, boolean shouldEscapeWhitespaceChars)57   static void assertBasicXmlEscaper(
58       CharEscaper xmlEscaper, boolean shouldEscapeQuotes, boolean shouldEscapeWhitespaceChars) {
59     // Simple examples (smoke tests)
60     assertEquals("xxx", xmlEscaper.escape("xxx"));
61     assertEquals("test &amp; test &amp; test", xmlEscaper.escape("test & test & test"));
62     assertEquals("test &lt;&lt; 1", xmlEscaper.escape("test << 1"));
63     assertEquals("test &gt;&gt; 1", xmlEscaper.escape("test >> 1"));
64     assertEquals("&lt;tab&gt;", xmlEscaper.escape("<tab>"));
65 
66     // Test all non-escaped ASCII characters.
67     String s =
68         "!@#$%^*()_+=-/?\\|]}[{,.;:"
69             + "abcdefghijklmnopqrstuvwxyz"
70             + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
71             + "1234567890";
72     assertEquals(s, xmlEscaper.escape(s));
73 
74     // Test ASCII control characters.
75     for (char ch = 0; ch < 0x20; ch++) {
76       if (ch == '\t' || ch == '\n' || ch == '\r') {
77         // Only these whitespace chars are permitted in XML,
78         if (shouldEscapeWhitespaceChars) {
79           assertEscaping(xmlEscaper, "&#x" + Integer.toHexString(ch).toUpperCase() + ";", ch);
80         } else {
81           assertUnescaped(xmlEscaper, ch);
82         }
83       } else {
84         // and everything else is replaced with FFFD.
85         assertEscaping(xmlEscaper, "\uFFFD", ch);
86       }
87     }
88 
89     // Test _all_ allowed characters (including surrogate values).
90     for (char ch = 0x20; ch <= 0xFFFD; ch++) {
91       // There are a small number of cases to consider, so just do it manually.
92       if (ch == '&') {
93         assertEscaping(xmlEscaper, "&amp;", ch);
94       } else if (ch == '<') {
95         assertEscaping(xmlEscaper, "&lt;", ch);
96       } else if (ch == '>') {
97         assertEscaping(xmlEscaper, "&gt;", ch);
98       } else if (shouldEscapeQuotes && ch == '\'') {
99         assertEscaping(xmlEscaper, "&apos;", ch);
100       } else if (shouldEscapeQuotes && ch == '"') {
101         assertEscaping(xmlEscaper, "&quot;", ch);
102       } else {
103         String input = String.valueOf(ch);
104         String escaped = xmlEscaper.escape(input);
105         assertEquals(
106             "char 0x" + Integer.toString(ch, 16) + " should not be escaped", input, escaped);
107       }
108     }
109 
110     // Test that 0xFFFE and 0xFFFF are replaced with 0xFFFD
111     assertEscaping(xmlEscaper, "\uFFFD", '\uFFFE');
112     assertEscaping(xmlEscaper, "\uFFFD", '\uFFFF');
113 
114     assertEquals(
115         "0xFFFE is forbidden and should be replaced during escaping",
116         "[\uFFFD]",
117         xmlEscaper.escape("[\ufffe]"));
118     assertEquals(
119         "0xFFFF is forbidden and should be replaced during escaping",
120         "[\uFFFD]",
121         xmlEscaper.escape("[\uffff]"));
122   }
123 }
124