1b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey/*
2b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey *
4b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * you may not use this file except in compliance with the License.
6b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * You may obtain a copy of the License at
7b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey *
8b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey *
10b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * See the License for the specific language governing permissions and
14b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * limitations under the License.
15b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey */
16b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
17b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeypackage android.support.v4.content;
18b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
19b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport static android.provider.OpenableColumns.DISPLAY_NAME;
20b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport static android.provider.OpenableColumns.SIZE;
21b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
22b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.content.ContentResolver;
23b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.database.Cursor;
24b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.net.Uri;
25b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.os.Environment;
26b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.support.v4.content.FileProvider.SimplePathStrategy;
27b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.test.AndroidTestCase;
28b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.test.MoreAsserts;
292cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkeyimport android.test.suitebuilder.annotation.Suppress;
302cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkey
312cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkeyimport libcore.io.IoUtils;
322cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkeyimport libcore.io.Streams;
33b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
34b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.File;
35b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.FileNotFoundException;
36b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.FileOutputStream;
37b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.InputStream;
38b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.OutputStream;
39b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
40b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey/**
41b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Tests for {@link FileProvider}
42b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey */
432cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkey@Suppress
44b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeypublic class FileProviderTest extends AndroidTestCase {
45b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private static final String TEST_AUTHORITY = "moocow";
46b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
47b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private static final String TEST_FILE = "file.test";
48b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private static final byte[] TEST_DATA = new byte[] { (byte) 0xf0, 0x00, 0x0d };
49b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private static final byte[] TEST_DATA_ALT = new byte[] { (byte) 0x33, 0x66 };
50b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
51b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private ContentResolver mResolver;
52b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
53b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    @Override
54b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    protected void setUp() throws Exception {
55b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        super.setUp();
56b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
57b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        mResolver = getContext().getContentResolver();
58b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
59b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
60b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyUriSimple() throws Exception {
61b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
62b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
63b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
64b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "file.test");
65b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://authority/tag/file.test",
66b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(file).toString());
67b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
68b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        file = buildPath(mContext.getFilesDir(), "subdir", "file.test");
69b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://authority/tag/subdir/file.test",
70b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(file).toString());
71b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
72b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        file = buildPath(Environment.getExternalStorageDirectory(), "file.test");
73b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
74b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            strat.getUriForFile(file);
75b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            fail("somehow got uri for file outside roots?");
76b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } catch (IllegalArgumentException e) {
77b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
78b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
79b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
80b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyUriJumpOutside() throws Exception {
81b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
82b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
83b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
84b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "..", "file.test");
85b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
86b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            strat.getUriForFile(file);
87b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            fail("file escaped!");
88b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } catch (IllegalArgumentException e) {
89b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
90b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
91b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
92b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyUriShortestRoot() throws Exception {
93b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        SimplePathStrategy strat = new SimplePathStrategy("authority");
94b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag1", mContext.getFilesDir());
95b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag2", new File("/"));
96b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
97b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "file.test");
98b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://authority/tag1/file.test",
99b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(file).toString());
100b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
101b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat = new SimplePathStrategy("authority");
102b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag1", new File("/"));
103b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag2", mContext.getFilesDir());
104b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
105b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        file = buildPath(mContext.getFilesDir(), "file.test");
106b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://authority/tag2/file.test",
107b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(file).toString());
108b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
109b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
110b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyFileSimple() throws Exception {
111b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
112b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
113b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
114b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "file.test");
115b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(file.getPath(),
116b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getFileForUri(Uri.parse("content://authority/tag/file.test")).getPath());
117b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
118b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        file = buildPath(mContext.getFilesDir(), "subdir", "file.test");
119b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(file.getPath(), strat.getFileForUri(
120b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                Uri.parse("content://authority/tag/subdir/file.test")).getPath());
121b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
122b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
123b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyFileJumpOutside() throws Exception {
124b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
125b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
126b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
127b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
128b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            strat.getFileForUri(Uri.parse("content://authority/tag/../file.test"));
129b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            fail("file escaped!");
130b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } catch (SecurityException e) {
131b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
132b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
133b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
134b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyEscaping() throws Exception {
135b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
136b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("t/g", mContext.getFilesDir());
137b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
138b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "lol\"wat?foo&bar", "wat.txt");
139b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final String expected = "content://authority/t%2Fg/lol%22wat%3Ffoo%26bar/wat.txt";
140b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
141b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(expected,
142b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(file).toString());
143b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(file.getPath(),
144b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getFileForUri(Uri.parse(expected)).getPath());
145b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
146b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
147b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyExtraParams() throws Exception {
148b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
149b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
150b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
151b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File file = buildPath(mContext.getFilesDir(), "file.txt");
152b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(file.getPath(), strat.getFileForUri(
153b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                Uri.parse("content://authority/tag/file.txt?extra=foo")).getPath());
154b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
155b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
156b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testStrategyExtraSeparators() throws Exception {
157b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final SimplePathStrategy strat = new SimplePathStrategy("authority");
158b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        strat.addRoot("tag", mContext.getFilesDir());
159b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
160b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        // When canonicalized, the path separators are trimmed
161b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File inFile = new File(mContext.getFilesDir(), "//foo//bar//");
162b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File outFile = new File(mContext.getFilesDir(), "/foo/bar");
163b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final String expected = "content://authority/tag/foo/bar";
164b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
165b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(expected,
166b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getUriForFile(inFile).toString());
167b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(outFile.getPath(),
168b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                strat.getFileForUri(Uri.parse(expected)).getPath());
169b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
170b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
171b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testQueryProjectionNull() throws Exception {
172b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
173b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
174b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
175b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        // Verify that null brings out default columns
176b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        Cursor cursor = mResolver.query(uri, null, null, null, null);
177b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
178b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(1, cursor.getCount());
179b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.moveToFirst();
180b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_FILE, cursor.getString(cursor.getColumnIndex(DISPLAY_NAME)));
181b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_DATA.length, cursor.getLong(cursor.getColumnIndex(SIZE)));
182b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
183b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.close();
184b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
185b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
186b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
187b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testQueryProjectionOrder() throws Exception {
188b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
189b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
190b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
191b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        // Verify that swapped order works
192b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        Cursor cursor = mResolver.query(uri, new String[] {
193b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                SIZE, DISPLAY_NAME }, null, null, null);
194b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
195b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(1, cursor.getCount());
196b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.moveToFirst();
197b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_DATA.length, cursor.getLong(0));
198b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_FILE, cursor.getString(1));
199b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
200b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.close();
201b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
202b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
203b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        cursor = mResolver.query(uri, new String[] {
204b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                DISPLAY_NAME, SIZE }, null, null, null);
205b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
206b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(1, cursor.getCount());
207b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.moveToFirst();
208b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_FILE, cursor.getString(0));
209b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_DATA.length, cursor.getLong(1));
210b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
211b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.close();
212b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
213b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
214b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
215b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testQueryExtraColumn() throws Exception {
216b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
217b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
218b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
219b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        // Verify that extra column doesn't gook things up
220b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        Cursor cursor = mResolver.query(uri, new String[] {
221b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                SIZE, "foobar", DISPLAY_NAME }, null, null, null);
222b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
223b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(1, cursor.getCount());
224b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.moveToFirst();
225b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_DATA.length, cursor.getLong(0));
226b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertEquals(TEST_FILE, cursor.getString(1));
227b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
228b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            cursor.close();
229b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
230b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
231b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
232b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testReadFile() throws Exception {
233b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
234b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
235b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
236b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertContentsEquals(TEST_DATA, uri);
237b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
238b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
239b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testWriteFile() throws Exception {
240b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
241b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
242b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
243b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertContentsEquals(TEST_DATA, uri);
244b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
245b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final OutputStream out = mResolver.openOutputStream(uri);
246b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
247b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            out.write(TEST_DATA_ALT);
248b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
249b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            IoUtils.closeQuietly(out);
250b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
251b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
252b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertContentsEquals(TEST_DATA_ALT, uri);
253b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
254b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
255b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testWriteMissingFile() throws Exception {
256b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
257b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, null);
258b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
259b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
260b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertContentsEquals(new byte[0], uri);
261b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            fail("Somehow read missing file?");
262b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } catch(FileNotFoundException e) {
263b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
264b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
265b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final OutputStream out = mResolver.openOutputStream(uri);
266b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
267b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            out.write(TEST_DATA_ALT);
268b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
269b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            IoUtils.closeQuietly(out);
270b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
271b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
272b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertContentsEquals(TEST_DATA_ALT, uri);
273b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
274b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
275b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testDelete() throws Exception {
276b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final File file = new File(mContext.getFilesDir(), TEST_FILE);
277b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final Uri uri = stageFileAndGetUri(file, TEST_DATA);
278b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
279b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertContentsEquals(TEST_DATA, uri);
280b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
281b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(1, mResolver.delete(uri, null, null));
282b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals(0, mResolver.delete(uri, null, null));
283b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
284b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
285b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            assertContentsEquals(new byte[0], uri);
286b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            fail("Somehow read missing file?");
287b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } catch(FileNotFoundException e) {
288b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
289b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
290b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
291b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    public void testMetaDataTargets() {
292b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        Uri actual;
293b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
294b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
295b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                new File("/proc/version"));
296b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_root/proc/version", actual.toString());
297b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
298b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
299b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                new File("/proc/1/mountinfo"));
300b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_init/mountinfo", actual.toString());
301b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
302b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
303b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                buildPath(mContext.getFilesDir(), "meow"));
304b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_files/meow", actual.toString());
305b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
306b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
307b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                buildPath(mContext.getFilesDir(), "thumbs", "rawr"));
308b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_thumbs/rawr", actual.toString());
309b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
310b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
311b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                buildPath(mContext.getCacheDir(), "up", "down"));
312b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_cache/up/down", actual.toString());
313b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
314b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY,
315b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                buildPath(Environment.getExternalStorageDirectory(), "Android", "obb", "foobar"));
316b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        assertEquals("content://moocow/test_external/Android/obb/foobar", actual.toString());
317b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
318b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
319b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private void assertContentsEquals(byte[] expected, Uri actual) throws Exception {
320b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        final InputStream in = mResolver.openInputStream(actual);
321b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        try {
322b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            MoreAsserts.assertEquals(expected, Streams.readFully(in));
323b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } finally {
324b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            IoUtils.closeQuietly(in);
325b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
326b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
327b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
328b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private Uri stageFileAndGetUri(File file, byte[] data) throws Exception {
329b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        if (data != null) {
330b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            final FileOutputStream out = new FileOutputStream(file);
331b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            try {
332b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                out.write(data);
333b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            } finally {
334b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                out.close();
335b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            }
336b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        } else {
337b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            file.delete();
338b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
339b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        return FileProvider.getUriForFile(mContext, TEST_AUTHORITY, file);
340b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
341b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey
342b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    private static File buildPath(File base, String... segments) {
343b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        File cur = base;
344b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        for (String segment : segments) {
345b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            if (cur == null) {
346b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                cur = new File(segment);
347b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            } else {
348b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey                cur = new File(cur, segment);
349b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey            }
350b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        }
351b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey        return cur;
352b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey    }
353b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey}
354