1/* 2 * Copyright (C) 2015 The Android Open Source Project 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 17package libcore.net; 18 19import junit.framework.TestCase; 20 21import java.net.URISyntaxException; 22import java.nio.charset.StandardCharsets; 23 24/** 25 * Tests for {@link UriCodec} 26 */ 27public class UriCodecTest extends TestCase { 28 private static final UriCodec CODEC = new UriCodec() { 29 @Override 30 protected boolean isRetained(char c) { 31 return c == '$'; 32 } 33 }; 34 35 private static final String VALID_ENCODED_STRING = "a0b$CD%01a%23b%45c%67%89%abd%cd%efq"; 36 37 public void testValidate_stringOK_passes() throws Exception { 38 assertEquals( 39 VALID_ENCODED_STRING, 40 CODEC.validate( 41 VALID_ENCODED_STRING, 0, VALID_ENCODED_STRING.length(), "test OK string")); 42 } 43 44 // Hex codes in upper case are valid as well. 45 public void testValidate_stringUppercaseOK_passes() throws Exception { 46 String stringOKUpperCase = VALID_ENCODED_STRING.toUpperCase(); 47 CODEC.validate(stringOKUpperCase, 0, stringOKUpperCase.length(), "test OK UC string"); 48 } 49 50 // Characters before the start index are ignored. 51 public void testValidate_wrongCharsBeforeStart_passes() throws Exception { 52 assertEquals(VALID_ENCODED_STRING, CODEC.validate( 53 "%p" + VALID_ENCODED_STRING, 54 2, 55 VALID_ENCODED_STRING.length() + 2, 56 "test string")); 57 } 58 59 // Fails with character 'p', invalid after '%' 60 public void testValidate_wrongCharsAtStart_fails() throws Exception { 61 try { 62 CODEC.validate( 63 "%p" + VALID_ENCODED_STRING, 64 0, 65 VALID_ENCODED_STRING.length() + 2, 66 "test string"); 67 fail("Expected URISyntaxException"); 68 } catch (URISyntaxException expected) { 69 // Expected. 70 } 71 } 72 73 // Fails with character 'p', invalid after '%' 74 public void testValidate_wrongCharsBeyondEnd_passes() throws Exception { 75 assertEquals(VALID_ENCODED_STRING, CODEC.validate( 76 VALID_ENCODED_STRING + "%p", 77 0, 78 VALID_ENCODED_STRING.length(), 79 "test string")); 80 } 81 82 // Fails with character 'p', invalid after '%' 83 public void testValidate_wrongCharsAtEnd_fails() throws Exception { 84 try { 85 CODEC.validate( 86 VALID_ENCODED_STRING + "%p", 87 0, 88 VALID_ENCODED_STRING.length() + 2, 89 "test string"); 90 fail("Expected URISyntaxException"); 91 } catch (URISyntaxException expected) { 92 // Expected. 93 } 94 } 95 96 public void testValidate_secondDigitWrong_fails() throws Exception { 97 try { 98 CODEC.validate( 99 VALID_ENCODED_STRING + "%1p", 100 0, 101 VALID_ENCODED_STRING.length() + 2, 102 "test string"); 103 fail("Expected URISyntaxException"); 104 } catch (URISyntaxException expected) { 105 // Expected. 106 } 107 } 108 109 public void testValidate_emptyString_passes() throws Exception { 110 assertEquals("", CODEC.validate("", 0, 0, "empty string")); 111 } 112 113 public void testValidate_stringEndingWithPercent_fails() throws Exception { 114 try { 115 CODEC.validate("a%", 0, 0, "a% string"); 116 } catch (URISyntaxException expected) { 117 // Expected. 118 } 119 } 120 121 public void testValidate_stringEndingWithPercentAndSingleDigit_fails() throws Exception { 122 try { 123 CODEC.validate("a%1", 0, 0, "a%1 string"); 124 } catch (URISyntaxException expected) { 125 // Expected. 126 } 127 } 128 129 public void testValidateSimple_stringOK_passes() throws Exception { 130 UriCodec.validateSimple(VALID_ENCODED_STRING, "$%"); 131 } 132 133 // Hex codes in upper case are valid as well. 134 public void testValidateSimple_stringUppercaseOK_passes() throws Exception { 135 UriCodec.validateSimple(VALID_ENCODED_STRING.toUpperCase(), "$%"); 136 } 137 138 // Fails with character 'p', invalid after '%' 139 public void testValidateSimple_wrongCharsAtStart_fails() throws Exception { 140 try { 141 UriCodec.validateSimple("%/" + VALID_ENCODED_STRING, "$%"); 142 fail("Expected URISyntaxException"); 143 } catch (URISyntaxException expected) { 144 // Expected. 145 } 146 } 147 148 // Fails with character 'p', invalid after '%' 149 public void testValidateSimple_wrongCharsAtEnd_fails() throws Exception { 150 try { 151 UriCodec.validateSimple(VALID_ENCODED_STRING + "%/", "$%"); 152 fail("Expected URISyntaxException"); 153 } catch (URISyntaxException expected) { 154 // Expected. 155 } 156 } 157 158 public void testValidateSimple_emptyString_passes() throws Exception { 159 UriCodec.validateSimple("", "$%"); 160 } 161 162 public void testValidateSimple_stringEndingWithPercent_passes() throws Exception { 163 UriCodec.validateSimple("a%", "$%"); 164 } 165 166 public void testValidateSimple_stringEndingWithPercentAndSingleDigit_passes() throws Exception { 167 UriCodec.validateSimple("a%1", "$%"); 168 } 169 170 public void testEncode_emptyString_returnsEmptyString() { 171 assertEquals("", CODEC.encode("", StandardCharsets.UTF_8)); 172 } 173 174 public void testEncode() { 175 assertEquals("ab%2F$%C4%82%2512", CODEC.encode("ab/$\u0102%12", StandardCharsets.UTF_8)); 176 } 177 178 public void testEncode_convertWhitespace() { 179 // Whitespace is not retained, output %20. 180 assertEquals("ab%2F$%C4%82%2512%20", 181 CODEC.encode("ab/$\u0102%12 ", StandardCharsets.UTF_8)); 182 183 UriCodec withWhitespaceRetained = new UriCodec() { 184 @Override 185 protected boolean isRetained(char c) { 186 return c == '$' || c == ' '; 187 } 188 }; 189 // Whitespace is retained, convert to plus. 190 assertEquals("ab%2F$%C4%82%2512+", 191 withWhitespaceRetained.encode("ab/$\u0102%12 ", StandardCharsets.UTF_8)); 192 } 193 194 /** Confirm that '%' can be retained, disabling '%' encoding. http://b/24806835 */ 195 public void testEncode_percentRetained() { 196 UriCodec withPercentRetained = new UriCodec() { 197 @Override 198 protected boolean isRetained(char c) { 199 return c == '%'; 200 } 201 }; 202 // Percent is retained 203 assertEquals("ab%34%20", withPercentRetained.encode("ab%34 ", StandardCharsets.UTF_8)); 204 } 205 206 public void testEncode_partially_returnsPercentUnchanged() { 207 StringBuilder stringBuilder = new StringBuilder(); 208 // Check it's really appending instead of returning a new builder. 209 stringBuilder.append("pp"); 210 CODEC.appendPartiallyEncoded(stringBuilder, "ab/$\u0102%"); 211 // Returns % at the end instead of %25. 212 assertEquals("ppab%2F$%C4%82%", stringBuilder.toString()); 213 } 214 215 public void testEncode_partially_returnsCharactersAfterPercentEncoded() { 216 StringBuilder stringBuilder = new StringBuilder(); 217 // Check it's really appending instead of returning a new builder. 218 stringBuilder.append("pp"); 219 CODEC.appendPartiallyEncoded(stringBuilder, "ab/$\u0102%\u0102"); 220 // Returns %C4%82 at the end. 221 assertEquals("ppab%2F$%C4%82%%C4%82", stringBuilder.toString()); 222 } 223 224 public void testEncode_partially_returnsDigitsAfterPercentUnchanged() { 225 StringBuilder stringBuilder = new StringBuilder(); 226 // Check it's really appending instead of returning a new builder. 227 stringBuilder.append("pp"); 228 CODEC.appendPartiallyEncoded(stringBuilder, "ab/$\u0102%38"); 229 // Returns %38 at the end. 230 assertEquals("ppab%2F$%C4%82%38", stringBuilder.toString()); 231 } 232 233 // Last character needs encoding (make sure we are flushing the buffer with chars to encode). 234 public void testEncode_lastCharacter() { 235 assertEquals("ab%2F$%C4%82%25%E0%A1%80", 236 CODEC.encode("ab/$\u0102%\u0840", StandardCharsets.UTF_8)); 237 } 238 239 // Last character needs encoding (make sure we are flushing the buffer with chars to encode). 240 public void testEncode_flushBufferBeforePlusFromSpace() { 241 UriCodec withSpaceRetained = new UriCodec() { 242 @Override 243 protected boolean isRetained(char c) { 244 return c == ' '; 245 } 246 }; 247 assertEquals("%2F+", 248 withSpaceRetained.encode("/ ", StandardCharsets.UTF_8)); 249 } 250 251 public void testDecode_emptyString_returnsEmptyString() { 252 assertEquals("", UriCodec.decode("")); 253 } 254 255 public void testDecode_wrongHexDigit_fails() { 256 try { 257 // %p in the end. 258 UriCodec.decode("ab%2f$%C4%82%25%e0%a1%80%p"); 259 fail("Expected URISyntaxException"); 260 } catch (IllegalArgumentException expected) { 261 // Expected. 262 } 263 } 264 265 public void testDecode_secondHexDigitWrong_fails() { 266 try { 267 // %1p in the end. 268 UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%1p"); 269 fail("Expected URISyntaxException"); 270 } catch (IllegalArgumentException expected) { 271 // Expected. 272 } 273 } 274 275 public void testDecode_endsWithPercent_fails() { 276 try { 277 // % in the end. 278 UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%"); 279 fail("Expected URISyntaxException"); 280 } catch (IllegalArgumentException expected) { 281 // Expected. 282 } 283 } 284 285 public void testDecode_dontThrowException_appendsUnknownCharacter() { 286 assertEquals("ab/$\u0102%\u0840\ufffd", 287 UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80%", 288 false /* convertPlus */, 289 StandardCharsets.UTF_8, 290 false /* throwOnFailure */)); 291 } 292 293 public void testDecode_convertPlus() { 294 assertEquals("ab/$\u0102% \u0840", 295 UriCodec.decode("ab%2f$%c4%82%25+%e0%a1%80", 296 true /* convertPlus */, 297 StandardCharsets.UTF_8, 298 false /* throwOnFailure */)); 299 } 300 301 // Last character needs decoding (make sure we are flushing the buffer with chars to decode). 302 public void testDecode_lastCharacter() { 303 assertEquals("ab/$\u0102%\u0840", 304 UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80")); 305 } 306 307 // Check that a second row of encoded characters is decoded properly (internal buffers are 308 // reset properly). 309 public void testDecode_secondRowOfEncoded() { 310 assertEquals("ab/$\u0102%\u0840aa\u0840", 311 UriCodec.decode("ab%2f$%c4%82%25%e0%a1%80aa%e0%a1%80")); 312 } 313} 314