/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package libcore.java.net; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import junit.framework.TestCase; public final class UrlEncodingTest extends TestCase { public void testUriRetainsOriginalEncoding() throws Exception { assertEquals("%61", new URI("http://foo#%61").getRawFragment()); } /** * URLDecoder and URI disagree on what '+' should decode to. */ public void testDecodingPlus() throws Exception { assertEquals("a b", URLDecoder.decode("a+b")); assertEquals("a b", URLDecoder.decode("a+b", "UTF-8")); assertEquals("a+b", new URI("http://foo#a+b").getFragment()); } public void testEncodingPlus() throws Exception { assertEquals("a%2Bb", URLEncoder.encode("a+b")); assertEquals("a%2Bb", URLEncoder.encode("a+b", "UTF-8")); assertEquals("a+b", new URI("http", "foo", "/", "a+b").getRawFragment()); } public void testDecodingSpace() throws Exception { assertEquals("a b", URLDecoder.decode("a b")); assertEquals("a b", URLDecoder.decode("a b", "UTF-8")); try { new URI("http://foo#a b"); fail(); } catch (URISyntaxException expected) { } } public void testEncodingSpace() throws Exception { assertEquals("a+b", URLEncoder.encode("a b")); assertEquals("a+b", URLEncoder.encode("a b", "UTF-8")); assertEquals("a%20b", new URI("http", "foo", "/", "a b").getRawFragment()); } public void testUriDecodingPartial() throws Exception { try { new URI("http://foo#%"); fail(); } catch (URISyntaxException expected) { } try { new URI("http://foo#%0"); fail(); } catch (URISyntaxException expected) { } } public void testUrlDecoderDecodingPartial() throws Exception { try { URLDecoder.decode("%"); fail(); } catch (IllegalArgumentException expected) { } try { URLDecoder.decode("%0"); fail(); } catch (IllegalArgumentException expected) { } } public void testUriDecodingInvalid() { try { new URI("http://foo#%0g"); fail(); } catch (URISyntaxException expected) { } } public void testUrlDecoderDecodingInvalid() { try { URLDecoder.decode("%0g"); fail(); } catch (IllegalArgumentException expected) { } } public void testUrlDecoderFailsOnNullCharset() throws Exception { try { URLDecoder.decode("ab", null); fail(); } catch (IllegalCharsetNameException expected) { } catch (NullPointerException expected) { } } public void testUrlDecoderFailsOnEmptyCharset() { try { URLDecoder.decode("ab", ""); fail(); } catch (IllegalCharsetNameException expected) { } catch (UnsupportedEncodingException expected) { } } public void testUrlEncoderFailsOnNullCharset() throws Exception { try { URLEncoder.encode("ab", null); fail(); } catch (IllegalCharsetNameException expected) { } catch (NullPointerException expected) { } } public void testUrlEncoderFailsOnEmptyCharset() { try { URLEncoder.encode("ab", ""); fail(); } catch (IllegalCharsetNameException expected) { } catch (UnsupportedEncodingException expected) { } } /** * The RI looks up the charset lazily; Android looks it up eagerly. Either * behavior is acceptable. */ public void testUrlDecoderIgnoresUnnecessaryCharset() throws Exception { try { assertEquals("ab", URLDecoder.decode("ab", "no-such-charset")); // no fail() } catch (UnsupportedCharsetException expected) { } } public void testUrlEncoderFailsOnInvalidCharset() throws Exception { try { URLEncoder.encode("ab", "no-such-charset"); fail(); } catch (UnsupportedCharsetException expected) { } catch (UnsupportedEncodingException expected) { } } public void testDecoding() throws Exception { assertDecoded("a\u0000b", "a%00b"); assertDecoded("a b", "a%20b"); assertDecoded("a+b", "a%2bb"); assertDecoded("a%b", "a%25b"); assertDecoded("a\u007fb", "a%7fb"); } public void testEncoding() throws Exception { assertEncoded("a%25b", "a%b"); assertEncoded("a%7Fb", "a\u007fb"); } public void testDecodingLiterals() throws Exception { assertDecoded("\ud842\udf9f", "\ud842\udf9f"); } public void testDecodingBrokenUtf8SequenceYieldsReplacementCharacter() throws Exception { assertDecoded("a\ufffdb", "a%ffb"); } public void testDecodingUtf8Octets() throws Exception { assertDecoded("\u20AC", "%e2%82%ac"); assertDecoded("\ud842\udf9f", "%f0%a0%ae%9f"); } public void testDecodingNonUsDigits() throws Exception { try { new URI("http://foo#" + "%\u0664\u0661"); fail(); } catch (URISyntaxException expected) { } try { URLDecoder.decode("%\u0664\u0661"); fail(); // RI fails this test returning "A" } catch (IllegalArgumentException expected) { } } /** * Android's URLEncoder.encode() failed for surrogate pairs, encoding them * as two replacement characters ("??"). http://b/3436051 */ public void testUrlEncoderEncodesNonPrintableNonAsciiCharacters() throws Exception { assertEquals("%00", URLEncoder.encode("\u0000", "UTF-8")); assertEquals("%00", URLEncoder.encode("\u0000")); assertEquals("%E2%82%AC", URLEncoder.encode("\u20AC", "UTF-8")); assertEquals("%E2%82%AC", URLEncoder.encode("\u20AC")); assertEquals("%F0%A0%AE%9F", URLEncoder.encode("\ud842\udf9f", "UTF-8")); assertEquals("%F0%A0%AE%9F", URLEncoder.encode("\ud842\udf9f")); } public void testUriDoesNotEncodeNonPrintableNonAsciiCharacters() throws Exception { assertEquals("\u20AC", new URI("http", "foo", "/", "\u20AC").getRawFragment()); assertEquals("\ud842\udf9f", new URI("http", "foo", "/", "\ud842\udf9f").getRawFragment()); } public void testUriEncodesControlCharacters() throws Exception { assertEquals("%01", new URI("http", "foo", "/", "\u0001").getRawFragment()); // The RI fails this, encoding \u0001 but not \u0000 assertEquals("%00", new URI("http", "foo", "/", "\u0000").getRawFragment()); } public void testEncodeAndDecode() throws Exception { assertRoundTrip("http://jcltest.apache.org/test?hl=en&q=te st", "http%3A%2F%2Fjcltest.apache.org%2Ftest%3Fhl%3Den%26q%3Dte+st"); assertRoundTrip ("file://a b/c/d.e-f*g_ l", "file%3A%2F%2Fa+b%2Fc%2Fd.e-f*g_+l"); assertRoundTrip("jar:file://a.jar !/b.c/\u1052", "jar%3Afile%3A%2F%2Fa.jar+%21%2Fb.c%2F%E1%81%92"); assertRoundTrip("ftp://test:pwd@localhost:2121/%D0%9C", "ftp%3A%2F%2Ftest%3Apwd%40localhost%3A2121%2F%25D0%259C"); } /** * Asserts that {@code original} decodes to {@code decoded} using both URI * and UrlDecoder. */ private void assertDecoded(String decoded, String original) throws Exception { assertEquals(decoded, new URI("http://foo#" + original).getFragment()); assertEquals(decoded, URLDecoder.decode(original)); assertEquals(decoded, URLDecoder.decode(original, "UTF-8")); } /** * Asserts that {@code original} encodes to {@code encoded} using both URI * and URLEncoder. */ private void assertEncoded(String encoded, String original) throws Exception { assertEquals(encoded, URLEncoder.encode(original, "UTF-8")); assertEquals(encoded, URLEncoder.encode(original)); assertEquals(encoded, new URI("http", "foo", "/", original).getRawFragment()); } private void assertRoundTrip(String original, String encoded) throws Exception { assertEquals(encoded, URLEncoder.encode(original, "UTF-8")); assertEquals(original, URLDecoder.decode(encoded, "UTF-8")); } }