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