1/*
2 * Copyright (C) 2007 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 com.android.unit_tests;
18
19import android.net.Uri;
20import android.content.ContentUris;
21import android.os.Parcel;
22import android.test.suitebuilder.annotation.SmallTest;
23import junit.framework.TestCase;
24
25import java.io.File;
26import java.util.Arrays;
27
28public class UriTest extends TestCase {
29
30    @SmallTest
31    public void testToStringWithPathOnly() {
32        Uri.Builder builder = new Uri.Builder();
33
34        // Not a valid path, but this came from a user's test case.
35        builder.path("//foo");
36        Uri uri = builder.build();
37        assertEquals("//foo", uri.toString());
38    }
39
40    @SmallTest
41    public void testParcelling() {
42        parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
43        parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
44        parcelAndUnparcel(new Uri.Builder()
45            .scheme("http")
46            .authority("crazybob.org")
47            .path("/rss/")
48            .encodedQuery("a=b")
49            .fragment("foo")
50            .build());
51    }
52
53    private void parcelAndUnparcel(Uri u) {
54        Parcel p = Parcel.obtain();
55        Uri.writeToParcel(p, u);
56        p.setDataPosition(0);
57        assertEquals(u, Uri.CREATOR.createFromParcel(p));
58
59        p.setDataPosition(0);
60        u = u.buildUpon().build();
61        Uri.writeToParcel(p, u);
62        p.setDataPosition(0);
63        assertEquals(u, Uri.CREATOR.createFromParcel(p));
64    }
65
66    @SmallTest
67    public void testBuildUponOpaqueStringUri() {
68        Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build();
69        assertEquals("robert", u.getScheme());
70        assertEquals("lee", u.getEncodedSchemeSpecificPart());
71        assertEquals("lee", u.getSchemeSpecificPart());
72        assertNull(u.getQuery());
73        assertNull(u.getPath());
74        assertNull(u.getAuthority());
75        assertNull(u.getHost());
76    }
77
78    @SmallTest
79    public void testStringUri() {
80        assertEquals("bob lee",
81                Uri.parse("foo:bob%20lee").getSchemeSpecificPart());
82        assertEquals("bob%20lee",
83                Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart());
84        assertEquals("/bob%20lee",
85                Uri.parse("foo:/bob%20lee").getEncodedPath());
86        assertNull(Uri.parse("foo:bob%20lee").getPath());
87        assertEquals("bob%20lee",
88                Uri.parse("foo:?bob%20lee").getEncodedQuery());
89        assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery());
90        assertEquals("bob%20lee",
91                Uri.parse("foo:#bob%20lee").getEncodedFragment());
92    }
93
94    @SmallTest
95    public void testStringUriIsHierarchical() {
96        assertTrue(Uri.parse("bob").isHierarchical());
97        assertFalse(Uri.parse("bob:").isHierarchical());
98    }
99
100    @SmallTest
101    public void testNullUriString() {
102        try {
103            Uri.parse(null);
104            fail();
105        } catch (NullPointerException e) {}
106    }
107
108    @SmallTest
109    public void testNullFile() {
110        try {
111            Uri.fromFile(null);
112            fail();
113        } catch (NullPointerException e) {}
114    }
115
116    @SmallTest
117    public void testCompareTo() {
118        Uri a = Uri.parse("foo:a");
119        Uri b = Uri.parse("foo:b");
120        Uri b2 = Uri.parse("foo:b");
121
122        assertTrue(a.compareTo(b) < 0);
123        assertTrue(b.compareTo(a) > 0);
124        assertEquals(0, b.compareTo(b2));
125    }
126
127    @SmallTest
128    public void testEqualsAndHashCode() {
129
130        Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee");
131
132        Uri b = new Uri.Builder()
133                .scheme("http")
134                .authority("crazybob.org")
135                .path("/test/")
136                .encodedQuery("foo=bar")
137                .fragment("tee")
138                .build();
139
140        // Try alternate builder methods.
141        Uri c = new Uri.Builder()
142                .scheme("http")
143                .encodedAuthority("crazybob.org")
144                .encodedPath("/test/")
145                .encodedQuery("foo=bar")
146                .encodedFragment("tee")
147                .build();
148
149        assertFalse(Uri.EMPTY.equals(null));
150
151        assertEquals(a, b);
152        assertEquals(b, c);
153        assertEquals(c, a);
154
155        assertEquals(a.hashCode(), b.hashCode());
156        assertEquals(b.hashCode(), c.hashCode());
157    }
158
159    @SmallTest
160    public void testAuthorityParsing() {
161        Uri uri = Uri.parse("http://localhost:42");
162        assertEquals("localhost", uri.getHost());
163        assertEquals(42, uri.getPort());
164
165        uri = Uri.parse("http://bob@localhost:42");
166        assertEquals("bob", uri.getUserInfo());
167        assertEquals("localhost", uri.getHost());
168        assertEquals(42, uri.getPort());
169
170        uri = Uri.parse("http://bob%20lee@localhost:42");
171        assertEquals("bob lee", uri.getUserInfo());
172        assertEquals("bob%20lee", uri.getEncodedUserInfo());
173
174        uri = Uri.parse("http://localhost");
175        assertEquals("localhost", uri.getHost());
176        assertEquals(-1, uri.getPort());
177    }
178
179    @SmallTest
180    public void testBuildUponOpaqueUri() {
181        Uri a = Uri.fromParts("foo", "bar", "tee");
182        Uri b = a.buildUpon().fragment("new").build();
183        assertEquals("new", b.getFragment());
184        assertEquals("bar", b.getSchemeSpecificPart());
185        assertEquals("foo", b.getScheme());
186    }
187
188    @SmallTest
189    public void testBuildUponEncodedOpaqueUri() {
190        Uri a = new Uri.Builder()
191                .scheme("foo")
192                .encodedOpaquePart("bar")
193                .fragment("tee")
194                .build();
195        Uri b = a.buildUpon().fragment("new").build();
196        assertEquals("new", b.getFragment());
197        assertEquals("bar", b.getSchemeSpecificPart());
198        assertEquals("foo", b.getScheme());
199    }
200
201    @SmallTest
202    public void testPathSegmentDecoding() {
203        Uri uri = Uri.parse("foo://bar/a%20a/b%20b");
204        assertEquals("a a", uri.getPathSegments().get(0));
205        assertEquals("b b", uri.getPathSegments().get(1));
206    }
207
208    @SmallTest
209    public void testSms() {
210        Uri base = Uri.parse("content://sms");
211        Uri appended = base.buildUpon()
212                .appendEncodedPath("conversations/addr=555-1212")
213                .build();
214        assertEquals("content://sms/conversations/addr=555-1212",
215                appended.toString());
216        assertEquals(2, appended.getPathSegments().size());
217        assertEquals("conversations", appended.getPathSegments().get(0));
218        assertEquals("addr=555-1212", appended.getPathSegments().get(1));
219    }
220
221    @SmallTest
222    public void testEncodeWithAllowedChars() {
223        String encoded = Uri.encode("Bob:/", "/");
224        assertEquals(-1, encoded.indexOf(':'));
225        assertTrue(encoded.indexOf('/') > -1);
226    }
227
228    @SmallTest
229    public void testEncodeDecode() {
230        code(null);
231        code("");
232        code("Bob");
233        code(":Bob");
234        code("::Bob");
235        code("Bob::Lee");
236        code("Bob:Lee");
237        code("Bob::");
238        code("Bob:");
239        code("::Bob::");
240    }
241
242    private void code(String s) {
243        assertEquals(s, Uri.decode(Uri.encode(s, null)));
244    }
245
246    @SmallTest
247    public void testFile() {
248        File f = new File("/tmp/bob");
249
250        Uri uri = Uri.fromFile(f);
251
252        assertEquals("file:///tmp/bob", uri.toString());
253    }
254
255    @SmallTest
256    public void testQueryParameters() {
257        Uri uri = Uri.parse("content://user");
258
259        assertEquals(null, uri.getQueryParameter("a"));
260
261        uri = uri.buildUpon().appendQueryParameter("a", "b").build();
262
263        assertEquals("b", uri.getQueryParameter("a"));
264
265        uri = uri.buildUpon().appendQueryParameter("a", "b2").build();
266
267        assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
268
269        uri = uri.buildUpon().appendQueryParameter("c", "d").build();
270
271        assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
272        assertEquals("d", uri.getQueryParameter("c"));
273    }
274
275    @SmallTest
276    public void testSchemeOnly() {
277        Uri uri = Uri.parse("empty:");
278        assertEquals("empty", uri.getScheme());
279        assertTrue(uri.isAbsolute());
280        assertNull(uri.getPath());
281    }
282
283    @SmallTest
284    public void testEmptyPath() {
285        Uri uri = Uri.parse("content://user");
286        assertEquals(0, uri.getPathSegments().size());
287    }
288
289    @SmallTest
290    public void testPathOperations() {
291        Uri uri = Uri.parse("content://user/a/b");
292
293        assertEquals(2, uri.getPathSegments().size());
294        assertEquals("b", uri.getLastPathSegment());
295
296        Uri first = uri;
297        uri = uri.buildUpon().appendPath("c").build();
298
299        assertEquals(3, uri.getPathSegments().size());
300        assertEquals("c", uri.getLastPathSegment());
301        assertEquals("content://user/a/b/c", uri.toString());
302
303        uri = ContentUris.withAppendedId(uri, 100);
304
305        assertEquals(4, uri.getPathSegments().size());
306        assertEquals("100", uri.getLastPathSegment());
307        assertEquals(100, ContentUris.parseId(uri));
308        assertEquals("content://user/a/b/c/100", uri.toString());
309
310        // Make sure the original URI is still intact.
311        assertEquals(2, first.getPathSegments().size());
312        assertEquals("b", first.getLastPathSegment());
313
314        try {
315            first.getPathSegments().get(2);
316            fail();
317        } catch (IndexOutOfBoundsException e) {}
318
319        assertEquals(null, Uri.EMPTY.getLastPathSegment());
320
321        Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build();
322        assertEquals("/a/b/c", withC.getPath());
323    }
324
325    @SmallTest
326    public void testOpaqueUri() {
327        Uri uri = Uri.parse("mailto:nobody");
328        testOpaqueUri(uri);
329
330        uri = uri.buildUpon().build();
331        testOpaqueUri(uri);
332
333        uri = Uri.fromParts("mailto", "nobody", null);
334        testOpaqueUri(uri);
335
336        uri = uri.buildUpon().build();
337        testOpaqueUri(uri);
338
339        uri = new Uri.Builder()
340                .scheme("mailto")
341                .opaquePart("nobody")
342                .build();
343        testOpaqueUri(uri);
344
345        uri = uri.buildUpon().build();
346        testOpaqueUri(uri);
347    }
348
349    private void testOpaqueUri(Uri uri) {
350        assertEquals("mailto", uri.getScheme());
351        assertEquals("nobody", uri.getSchemeSpecificPart());
352        assertEquals("nobody", uri.getEncodedSchemeSpecificPart());
353
354        assertNull(uri.getFragment());
355        assertTrue(uri.isAbsolute());
356        assertTrue(uri.isOpaque());
357        assertFalse(uri.isRelative());
358        assertFalse(uri.isHierarchical());
359
360        assertNull(uri.getAuthority());
361        assertNull(uri.getEncodedAuthority());
362        assertNull(uri.getPath());
363        assertNull(uri.getEncodedPath());
364        assertNull(uri.getUserInfo());
365        assertNull(uri.getEncodedUserInfo());
366        assertNull(uri.getQuery());
367        assertNull(uri.getEncodedQuery());
368        assertNull(uri.getHost());
369        assertEquals(-1, uri.getPort());
370
371        assertTrue(uri.getPathSegments().isEmpty());
372        assertNull(uri.getLastPathSegment());
373
374        assertEquals("mailto:nobody", uri.toString());
375
376        Uri withFragment = uri.buildUpon().fragment("top").build();
377        assertEquals("mailto:nobody#top", withFragment.toString());
378    }
379
380    @SmallTest
381    public void testHierarchicalUris() {
382        testHierarchical("http", "google.com", "/p1/p2", "query", "fragment");
383        testHierarchical("file", null, "/p1/p2", null, null);
384        testHierarchical("content", "contact", "/p1/p2", null, null);
385        testHierarchical("http", "google.com", "/p1/p2", null, "fragment");
386        testHierarchical("http", "google.com", "", null, "fragment");
387        testHierarchical("http", "google.com", "", "query", "fragment");
388        testHierarchical("http", "google.com", "", "query", null);
389        testHierarchical("http", null, "/", "query", null);
390    }
391
392    private static void testHierarchical(String scheme, String authority,
393            String path, String query, String fragment) {
394        StringBuilder sb = new StringBuilder();
395
396        if (authority != null) {
397            sb.append("//").append(authority);
398        }
399        if (path != null) {
400            sb.append(path);
401        }
402        if (query != null) {
403            sb.append('?').append(query);
404        }
405
406        String ssp = sb.toString();
407
408        if (scheme != null) {
409            sb.insert(0, scheme + ":");
410        }
411        if (fragment != null) {
412            sb.append('#').append(fragment);
413        }
414
415        String uriString = sb.toString();
416
417        Uri uri = Uri.parse(uriString);
418
419        // Run these twice to test caching.
420        compareHierarchical(
421                uriString, ssp, uri, scheme, authority, path, query, fragment);
422        compareHierarchical(
423                uriString, ssp, uri, scheme, authority, path, query, fragment);
424
425        // Test rebuilt version.
426        uri = uri.buildUpon().build();
427
428        // Run these twice to test caching.
429        compareHierarchical(
430                uriString, ssp, uri, scheme, authority, path, query, fragment);
431        compareHierarchical(
432                uriString, ssp, uri, scheme, authority, path, query, fragment);
433
434        // The decoded and encoded versions of the inputs are all the same.
435        // We'll test the actual encoding decoding separately.
436
437        // Test building with encoded versions.
438        Uri built = new Uri.Builder()
439                .scheme(scheme)
440                .encodedAuthority(authority)
441                .encodedPath(path)
442                .encodedQuery(query)
443                .encodedFragment(fragment)
444                .build();
445
446        compareHierarchical(
447                uriString, ssp, built, scheme, authority, path, query, fragment);
448        compareHierarchical(
449                uriString, ssp, built, scheme, authority, path, query, fragment);
450
451        // Test building with decoded versions.
452        built = new Uri.Builder()
453                .scheme(scheme)
454                .authority(authority)
455                .path(path)
456                .query(query)
457                .fragment(fragment)
458                .build();
459
460        compareHierarchical(
461                uriString, ssp, built, scheme, authority, path, query, fragment);
462        compareHierarchical(
463                uriString, ssp, built, scheme, authority, path, query, fragment);
464
465        // Rebuild.
466        built = built.buildUpon().build();
467
468        compareHierarchical(
469                uriString, ssp, built, scheme, authority, path, query, fragment);
470        compareHierarchical(
471                uriString, ssp, built, scheme, authority, path, query, fragment);
472    }
473
474    private static void compareHierarchical(String uriString, String ssp,
475            Uri uri,
476            String scheme, String authority, String path, String query,
477            String fragment) {
478        assertEquals(scheme, uri.getScheme());
479        assertEquals(authority, uri.getAuthority());
480        assertEquals(authority, uri.getEncodedAuthority());
481        assertEquals(path, uri.getPath());
482        assertEquals(path, uri.getEncodedPath());
483        assertEquals(query, uri.getQuery());
484        assertEquals(query, uri.getEncodedQuery());
485        assertEquals(fragment, uri.getFragment());
486        assertEquals(fragment, uri.getEncodedFragment());
487        assertEquals(ssp, uri.getSchemeSpecificPart());
488
489        if (scheme != null) {
490            assertTrue(uri.isAbsolute());
491            assertFalse(uri.isRelative());
492        } else {
493            assertFalse(uri.isAbsolute());
494            assertTrue(uri.isRelative());
495        }
496
497        assertFalse(uri.isOpaque());
498        assertTrue(uri.isHierarchical());
499
500        assertEquals(uriString, uri.toString());
501    }
502
503    public void testEmptyToStringNotNull() {
504        assertNotNull(Uri.EMPTY.toString());
505    }
506
507    @SmallTest
508    public void testParcellingWithoutFragment() {
509        parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
510        parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
511        parcelAndUnparcel(new Uri.Builder()
512            .scheme("http")
513            .authority("crazybob.org")
514            .path("/rss/")
515            .encodedQuery("a=b")
516            .build());
517    }
518
519    public void testGetQueryParameter() {
520        String nestedUrl = "http://crazybob.org/?a=1&b=2";
521        Uri uri = Uri.parse("http://test/").buildUpon()
522                .appendQueryParameter("foo", "bar")
523                .appendQueryParameter("nested", nestedUrl).build();
524        assertEquals(nestedUrl, uri.getQueryParameter("nested"));
525        assertEquals(nestedUrl, uri.getQueryParameters("nested").get(0));
526    }
527
528    public void testGetQueryParameterWorkaround() {
529        // This was a workaround for a bug where getQueryParameter called
530        // getQuery() instead of getEncodedQuery().
531        String nestedUrl = "http://crazybob.org/?a=1&b=2";
532        Uri uri = Uri.parse("http://test/").buildUpon()
533                .appendQueryParameter("foo", "bar")
534                .appendQueryParameter("nested", Uri.encode(nestedUrl)).build();
535        assertEquals(nestedUrl, Uri.decode(uri.getQueryParameter("nested")));
536        assertEquals(nestedUrl,
537                Uri.decode(uri.getQueryParameters("nested").get(0)));
538    }
539}
540