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