1 /*
2  * Copyright (C) 2008 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.net;
18 
19 import static com.google.common.escape.testing.EscaperAsserts.assertEscaping;
20 import static com.google.common.escape.testing.EscaperAsserts.assertUnescaped;
21 import static com.google.common.escape.testing.EscaperAsserts.assertUnicodeEscaping;
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import com.google.common.annotations.GwtCompatible;
25 import com.google.common.base.Preconditions;
26 import com.google.common.escape.UnicodeEscaper;
27 import junit.framework.TestCase;
28 
29 /**
30  * Tests for {@link PercentEscaper}.
31  *
32  * @author David Beaumont
33  */
34 @GwtCompatible
35 public class PercentEscaperTest extends TestCase {
36 
37   /** Tests that the simple escaper treats 0-9, a-z and A-Z as safe */
testSimpleEscaper()38   public void testSimpleEscaper() {
39     UnicodeEscaper e = new PercentEscaper("", false);
40     for (char c = 0; c < 128; c++) {
41       if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
42         assertUnescaped(e, c);
43       } else {
44         assertEscaping(e, escapeAscii(c), c);
45       }
46     }
47 
48     // Testing mutlibyte escape sequences
49     assertEscaping(e, "%00", '\u0000'); // nul
50     assertEscaping(e, "%7F", '\u007f'); // del
51     assertEscaping(e, "%C2%80", '\u0080'); // xx-00010,x-000000
52     assertEscaping(e, "%DF%BF", '\u07ff'); // xx-11111,x-111111
53     assertEscaping(e, "%E0%A0%80", '\u0800'); // xxx-0000,x-100000,x-00,0000
54     assertEscaping(e, "%EF%BF%BF", '\uffff'); // xxx-1111,x-111111,x-11,1111
55     assertUnicodeEscaping(e, "%F0%90%80%80", '\uD800', '\uDC00');
56     assertUnicodeEscaping(e, "%F4%8F%BF%BF", '\uDBFF', '\uDFFF');
57 
58     // simple string tests
59     assertEquals("", e.escape(""));
60     assertEquals("safestring", e.escape("safestring"));
61     assertEquals("embedded%00null", e.escape("embedded\0null"));
62     assertEquals("max%EF%BF%BFchar", e.escape("max\uffffchar"));
63   }
64 
65   /** Tests the various ways that the space character can be handled */
testPlusForSpace()66   public void testPlusForSpace() {
67     UnicodeEscaper basicEscaper = new PercentEscaper("", false);
68     UnicodeEscaper plusForSpaceEscaper = new PercentEscaper("", true);
69     UnicodeEscaper spaceEscaper = new PercentEscaper(" ", false);
70 
71     assertEquals("string%20with%20spaces", basicEscaper.escape("string with spaces"));
72     assertEquals("string+with+spaces", plusForSpaceEscaper.escape("string with spaces"));
73     assertEquals("string with spaces", spaceEscaper.escape("string with spaces"));
74   }
75 
76   /** Tests that if we add extra 'safe' characters they remain unescaped */
testCustomEscaper()77   public void testCustomEscaper() {
78     UnicodeEscaper e = new PercentEscaper("+*/-", false);
79     for (char c = 0; c < 128; c++) {
80       if ((c >= '0' && c <= '9')
81           || (c >= 'a' && c <= 'z')
82           || (c >= 'A' && c <= 'Z')
83           || "+*/-".indexOf(c) >= 0) {
84         assertUnescaped(e, c);
85       } else {
86         assertEscaping(e, escapeAscii(c), c);
87       }
88     }
89   }
90 
91   /** Tests that if specify '%' as safe the result is an idempotent escaper. */
testCustomEscaper_withpercent()92   public void testCustomEscaper_withpercent() {
93     UnicodeEscaper e = new PercentEscaper("%", false);
94     assertEquals("foo%7Cbar", e.escape("foo|bar"));
95     assertEquals("foo%7Cbar", e.escape("foo%7Cbar")); // idempotent
96   }
97 
98   /** Test that giving a null 'safeChars' string causes a {@link NullPointerException}. */
testBadArguments_null()99   public void testBadArguments_null() {
100     try {
101       new PercentEscaper(null, false);
102       fail("Expected null pointer exception for null parameter");
103     } catch (NullPointerException expected) {
104       // pass
105     }
106   }
107 
108   /**
109    * Tests that specifying any alphanumeric characters as 'safe' causes an {@link
110    * IllegalArgumentException}.
111    */
testBadArguments_badchars()112   public void testBadArguments_badchars() {
113     String msg =
114         "Alphanumeric characters are always 'safe' " + "and should not be explicitly specified";
115     try {
116       new PercentEscaper("-+#abc.!", false);
117       fail(msg);
118     } catch (IllegalArgumentException expected) {
119       assertThat(expected).hasMessageThat().isEqualTo(msg);
120     }
121   }
122 
123   /**
124    * Tests that if space is a safe character you cannot also specify 'plusForSpace' (throws {@link
125    * IllegalArgumentException}).
126    */
testBadArguments_plusforspace()127   public void testBadArguments_plusforspace() {
128     try {
129       new PercentEscaper(" ", false);
130     } catch (IllegalArgumentException e) {
131       fail("Space can be a 'safe' character if plusForSpace is false");
132     }
133     String msg = "plusForSpace cannot be specified when space is a 'safe' character";
134     try {
135       new PercentEscaper(" ", true);
136       fail(msg);
137     } catch (IllegalArgumentException expected) {
138       assertThat(expected).hasMessageThat().isEqualTo(msg);
139     }
140   }
141 
142   /** Helper to manually escape a 7-bit ascii character */
escapeAscii(char c)143   private String escapeAscii(char c) {
144     Preconditions.checkArgument(c < 128);
145     String hex = "0123456789ABCDEF";
146     return "%" + hex.charAt((c >> 4) & 0xf) + hex.charAt(c & 0xf);
147   }
148 }
149