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.escape;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.collect.ImmutableMap;
21 import com.google.common.escape.testing.EscaperAsserts;
22 
23 import junit.framework.TestCase;
24 
25 import java.io.IOException;
26 
27 /**
28  * @author David Beaumont
29  */
30 @GwtCompatible
31 public class EscapersTest extends TestCase {
testNullEscaper()32   public void testNullEscaper() throws IOException {
33     Escaper escaper = Escapers.nullEscaper();
34     EscaperAsserts.assertBasic(escaper);
35     String s = "\0\n\t\\az09~\uD800\uDC00\uFFFF";
36     assertEquals("null escaper should have no effect", s, escaper.escape(s));
37   }
38 
testBuilderInitialStateNoReplacement()39   public void testBuilderInitialStateNoReplacement() {
40     // Unsafe characters aren't modified by default (unsafeReplacement == null).
41     Escaper escaper = Escapers.builder().setSafeRange('a', 'z').build();
42     assertEquals("The Quick Brown Fox", escaper.escape("The Quick Brown Fox"));
43   }
44 
testBuilderInitialStateNoneUnsafe()45   public void testBuilderInitialStateNoneUnsafe() {
46     // No characters are unsafe by default (safeMin == 0, safeMax == 0xFFFF).
47     Escaper escaper = Escapers.builder().setUnsafeReplacement("X").build();
48     assertEquals("\0\uFFFF", escaper.escape("\0\uFFFF"));
49   }
50 
testBuilderRetainsState()51   public void testBuilderRetainsState() {
52     // Setting a safe range and unsafe replacement works as expected.
53     Escapers.Builder builder = Escapers.builder();
54     builder.setSafeRange('a', 'z');
55     builder.setUnsafeReplacement("X");
56     assertEquals("XheXXuickXXrownXXoxX",
57         builder.build().escape("The Quick Brown Fox!"));
58     // Explicit replacements take priority over unsafe characters.
59     builder.addEscape(' ', "_");
60     builder.addEscape('!', "_");
61     assertEquals("Xhe_Xuick_Xrown_Xox_",
62         builder.build().escape("The Quick Brown Fox!"));
63     // Explicit replacements take priority over safe characters.
64     builder.setSafeRange(' ', '~');
65     assertEquals("The_Quick_Brown_Fox_",
66         builder.build().escape("The Quick Brown Fox!"));
67   }
68 
testBuilderCreatesIndependentEscapers()69   public void testBuilderCreatesIndependentEscapers() {
70     // Setup a simple builder and create the first escaper.
71     Escapers.Builder builder = Escapers.builder();
72     builder.setSafeRange('a', 'z');
73     builder.setUnsafeReplacement("X");
74     builder.addEscape(' ', "_");
75     Escaper first = builder.build();
76     // Modify one of the existing mappings before creating a new escaper.
77     builder.addEscape(' ', "-");
78     builder.addEscape('!', "$");
79     Escaper second = builder.build();
80     // This should have no effect on existing escapers.
81     builder.addEscape(' ', "*");
82 
83     // Test both escapers after modifying the builder.
84     assertEquals("Xhe_Xuick_Xrown_XoxX", first.escape("The Quick Brown Fox!"));
85     assertEquals("Xhe-Xuick-Xrown-Xox$", second.escape("The Quick Brown Fox!"));
86   }
87 
testAsUnicodeEscaper()88   public void testAsUnicodeEscaper() throws IOException {
89     CharEscaper charEscaper = createSimpleCharEscaper(
90         ImmutableMap.<Character, char[]>builder()
91             .put('x', "<hello>".toCharArray())
92             .put('\uD800', "<hi>".toCharArray())
93             .put('\uDC00', "<lo>".toCharArray())
94             .build());
95     UnicodeEscaper unicodeEscaper = Escapers.asUnicodeEscaper(charEscaper);
96     EscaperAsserts.assertBasic(unicodeEscaper);
97     assertEquals("<hello><hi><lo>", charEscaper.escape("x\uD800\uDC00"));
98     assertEquals("<hello><hi><lo>", unicodeEscaper.escape("x\uD800\uDC00"));
99 
100     // Test that wrapped escapers acquire good Unicode semantics.
101     assertEquals("<hi><hello><lo>", charEscaper.escape("\uD800x\uDC00"));
102     try {
103       unicodeEscaper.escape("\uD800x\uDC00");
104       fail("should have failed for bad Unicode input");
105     } catch (IllegalArgumentException e) {
106       // pass
107     }
108     assertEquals("<lo><hi>", charEscaper.escape("\uDC00\uD800"));
109     try {
110       unicodeEscaper.escape("\uDC00\uD800");
111       fail("should have failed for bad Unicode input");
112     } catch (IllegalArgumentException e) {
113       // pass
114     }
115   }
116 
117   // A trival non-optimized escaper for testing.
createSimpleCharEscaper( final ImmutableMap<Character, char[]> replacementMap)118   private CharEscaper createSimpleCharEscaper(
119       final ImmutableMap<Character, char[]> replacementMap) {
120     return new CharEscaper() {
121       @Override protected char[] escape(char c) {
122         return replacementMap.get(c);
123       }
124     };
125   }
126 
127   // A trival non-optimized escaper for testing.
128   private UnicodeEscaper createSimpleUnicodeEscaper(
129       final ImmutableMap<Integer, char[]> replacementMap) {
130     return new UnicodeEscaper() {
131       @Override protected char[] escape(int cp) {
132         return replacementMap.get(cp);
133       }
134     };
135   }
136 }
137