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