[go: nahoru, domu]

1/*
2 * Copyright (C) 2014 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 android.support.v4.provider;
18
19import android.content.ContentResolver;
20import android.content.UriPermission;
21import android.net.Uri;
22import android.os.Environment;
23import android.os.SystemClock;
24import android.test.AndroidTestCase;
25import android.util.Log;
26
27import java.io.DataInputStream;
28import java.io.DataOutputStream;
29import java.io.File;
30import java.io.FileInputStream;
31import java.io.FileOutputStream;
32import java.io.IOException;
33import java.util.List;
34
35/**
36 * Tests for {@link DocumentFile}
37 */
38public class DocumentFileTest extends AndroidTestCase {
39
40    private Uri treeUri;
41
42    private File root;
43    private File rootFoo;
44    private File rootMeow;
45    private File rootMeowCat;
46    private File rootMeowDog;
47    private File rootMeowBar;
48
49    private static final String FOO = "foo.randomext";
50    private static final String MEOW = "meow";
51    private static final String CAT = "cat.jpg";
52    private static final String DOG = "DOG.PDF";
53    private static final String BAR = "bar.png";
54
55    @Override
56    protected void setUp() throws Exception {
57        super.setUp();
58
59        final ContentResolver resolver = getContext().getContentResolver();
60        final List<UriPermission> perms = resolver.getPersistedUriPermissions();
61
62        if (perms.isEmpty()) {
63            throw new RuntimeException(
64                    "Failed to find outstanding grant; did you run the activity first?");
65        } else {
66            treeUri = perms.get(0).getUri();
67        }
68
69        root = Environment.getExternalStorageDirectory();
70        rootFoo = new File(root, FOO);
71        rootMeow = new File(root, MEOW);
72        rootMeowCat = new File(rootMeow, CAT);
73        rootMeowDog = new File(rootMeow, DOG);
74        rootMeowBar = new File(rootMeow, BAR);
75
76        resetRoot();
77    }
78
79    private void resetRoot() throws Exception {
80        final File tmp = new File(root, "bark.pdf");
81        deleteContents(tmp);
82        tmp.delete();
83
84        deleteContents(rootMeow);
85        rootMeow.mkdir();
86        rootMeowBar.mkdir();
87
88        writeInt(rootFoo, 12);
89        writeInt(rootMeowCat, 24);
90        writeInt(rootMeowDog, 48);
91    }
92
93    public static boolean deleteContents(File dir) {
94        File[] files = dir.listFiles();
95        boolean success = true;
96        if (files != null) {
97            for (File file : files) {
98                if (file.isDirectory()) {
99                    success &= deleteContents(file);
100                }
101                if (!file.delete()) {
102                    success = false;
103                }
104            }
105        }
106        return success;
107    }
108
109    private interface DocumentTest {
110        public void exec(DocumentFile doc) throws Exception;
111    }
112
113    public void testSimple() throws Exception {
114        final DocumentTest test = new DocumentTest() {
115            @Override
116            public void exec(DocumentFile doc) throws Exception {
117                resetRoot();
118                assertTrue("isDirectory", doc.isDirectory());
119                assertFalse("isFile", doc.isFile());
120                assertTrue("canRead", doc.canRead());
121                assertTrue("canWrite", doc.canWrite());
122                assertTrue("exists", doc.exists());
123            }
124        };
125
126        test.exec(DocumentFile.fromFile(root));
127        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
128    }
129
130    public void testTraverse() throws Exception {
131        final DocumentTest test = new DocumentTest() {
132            @Override
133            public void exec(DocumentFile doc) throws Exception {
134                resetRoot();
135
136                // Root needs to at least contain our test file and dir
137                final DocumentFile foo = doc.findFile(FOO);
138                final DocumentFile meow = doc.findFile(MEOW);
139                assertTrue("isFile", foo.isFile());
140                assertTrue("isDirectory", meow.isDirectory());
141
142                // Traverse inside, and expect to find exact number of items
143                DocumentFile[] docs = meow.listFiles();
144                assertEquals("length", 3, docs.length);
145
146                final DocumentFile cat = meow.findFile(CAT);
147                final DocumentFile dog = meow.findFile(DOG);
148                final DocumentFile bar = meow.findFile(BAR);
149                assertTrue("isFile", cat.isFile());
150                assertTrue("isFile", dog.isFile());
151                assertTrue("isDirectory", bar.isDirectory());
152
153                // Empty directory is empty
154                assertEquals("length", 0, bar.listFiles().length);
155            }
156        };
157
158        test.exec(DocumentFile.fromFile(root));
159        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
160    }
161
162    public void testReadAndWrite() throws Exception {
163        final DocumentTest test = new DocumentTest() {
164            @Override
165            public void exec(DocumentFile doc) throws Exception {
166                resetRoot();
167
168                final DocumentFile foo = doc.findFile(FOO);
169                assertEquals("file", 12, readInt(rootFoo));
170                assertEquals("uri", 12, readInt(foo.getUri()));
171
172                // Underlying storage may not have sub-second resolution, so
173                // wait a few seconds.
174                SystemClock.sleep(2000);
175
176                // Ensure provider write makes its way to disk
177                final long beforeTime = foo.lastModified();
178                writeInt(foo.getUri(), 13);
179                final long afterTime = foo.lastModified();
180
181                assertEquals("file", 13, readInt(rootFoo));
182                assertEquals("uri", 13, readInt(foo.getUri()));
183
184                // Make sure we kicked time forward
185                assertTrue("lastModified", afterTime > beforeTime);
186            }
187        };
188
189        test.exec(DocumentFile.fromFile(root));
190        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
191    }
192
193    public void testMimes() throws Exception {
194        final DocumentTest test = new DocumentTest() {
195            @Override
196            public void exec(DocumentFile doc) throws Exception {
197                resetRoot();
198
199                final DocumentFile foo = doc.findFile(FOO);
200                final DocumentFile meow = doc.findFile(MEOW);
201                final DocumentFile cat = meow.findFile(CAT);
202                final DocumentFile dog = meow.findFile(DOG);
203                final DocumentFile bar = meow.findFile(BAR);
204
205                assertEquals(null, doc.getType());
206                assertEquals("application/octet-stream", foo.getType());
207                assertEquals(null, meow.getType());
208                assertEquals("image/jpeg", cat.getType());
209                assertEquals("application/pdf", dog.getType());
210                assertEquals(null, bar.getType());
211            }
212        };
213
214        test.exec(DocumentFile.fromFile(root));
215        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
216    }
217
218    public void testCreate() throws Exception {
219        final DocumentTest test = new DocumentTest() {
220            @Override
221            public void exec(DocumentFile doc) throws Exception {
222                resetRoot();
223
224                final DocumentFile meow = doc.findFile(MEOW);
225                assertEquals("length", 3, meow.listFiles().length);
226
227                // Create file with MIME
228                final DocumentFile newFile = meow.createFile("text/plain", "My New File");
229                assertEquals("My New File.txt", newFile.getName());
230                assertEquals("text/plain", newFile.getType());
231                assertTrue("isFile", newFile.isFile());
232                assertFalse("isDirectory", newFile.isDirectory());
233
234                assertEquals("length", 0, newFile.length());
235                writeInt(newFile.getUri(), 0);
236                assertEquals("length", 4, newFile.length());
237
238                // Create raw file
239                final DocumentFile newRaw = meow.createFile("application/octet-stream",
240                        "myrawfile");
241                assertEquals("myrawfile", newRaw.getName());
242                assertEquals("application/octet-stream", newRaw.getType());
243                assertTrue("isFile", newRaw.isFile());
244                assertFalse("isDirectory", newRaw.isDirectory());
245
246                // Create directory
247                final DocumentFile newDir = meow.createDirectory("My New Directory.png");
248                assertEquals("My New Directory.png", newDir.getName());
249                assertFalse("isFile", newDir.isFile());
250                assertTrue("isDirectory", newDir.isDirectory());
251                assertEquals("length", 0, newDir.listFiles().length);
252
253                // And overall dir grew
254                assertEquals("length", 6, meow.listFiles().length);
255            }
256        };
257
258        test.exec(DocumentFile.fromFile(root));
259        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
260    }
261
262    public void testDelete() throws Exception {
263        final DocumentTest test = new DocumentTest() {
264            @Override
265            public void exec(DocumentFile doc) throws Exception {
266                resetRoot();
267
268                final DocumentFile meow = doc.findFile(MEOW);
269                final DocumentFile cat = meow.findFile(CAT);
270                final DocumentFile dog = meow.findFile(DOG);
271
272                // Delete single file
273                assertTrue(cat.delete());
274                assertNull("cat", meow.findFile(CAT));
275
276                // Other file still exists
277                assertTrue("exists", dog.exists());
278
279                // Delete entire tree
280                assertTrue(meow.delete());
281                assertNull("meow", doc.findFile(MEOW));
282
283                // Nuking tree deleted other file
284                assertFalse("exists", dog.exists());
285            }
286        };
287
288        test.exec(DocumentFile.fromFile(root));
289        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
290    }
291
292    public void testRename() throws Exception {
293        final DocumentTest test = new DocumentTest() {
294            @Override
295            public void exec(DocumentFile doc) throws Exception {
296                resetRoot();
297
298                DocumentFile meow = doc.findFile(MEOW);
299                DocumentFile cat = meow.findFile(CAT);
300                DocumentFile dog = meow.findFile(DOG);
301                assertTrue(dog.exists());
302
303                // Rename a file
304                assertEquals("cat.jpg", cat.getName());
305                assertEquals("image/jpeg", cat.getType());
306
307                assertTrue(cat.renameTo("music.aAc"));
308                assertEquals("music.aAc", cat.getName());
309                assertEquals("audio/aac", cat.getType());
310
311                // Rename a directory
312                assertEquals("meow", meow.getName());
313                assertEquals(null, meow.getType());
314                assertTrue(meow.isDirectory());
315                assertEquals(3, meow.listFiles().length);
316
317                assertTrue(meow.renameTo("bark.pdf"));
318                assertEquals("bark.pdf", meow.getName());
319                assertEquals(null, meow.getType());
320                assertTrue(meow.isDirectory());
321                assertEquals(3, meow.listFiles().length);
322
323                // Current implementation of ExternalStorageProvider invalidates
324                // all children documents when directory is renamed.
325                assertFalse(dog.exists());
326
327                // But we can find it again
328                dog = meow.findFile(DOG);
329                assertTrue(dog.exists());
330            }
331        };
332
333        test.exec(DocumentFile.fromFile(root));
334        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
335    }
336
337    private void writeInt(Uri uri, int value) throws IOException {
338        final DataOutputStream os = new DataOutputStream(
339                getContext().getContentResolver().openOutputStream(uri));
340        try {
341            os.writeInt(value);
342        } finally {
343            os.close();
344        }
345    }
346
347    private static void writeInt(File file, int value) throws IOException {
348        final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
349        try {
350            os.writeInt(value);
351        } finally {
352            os.close();
353        }
354    }
355
356    private int readInt(Uri uri) throws IOException {
357        final DataInputStream is = new DataInputStream(
358                getContext().getContentResolver().openInputStream(uri));
359        try {
360            return is.readInt();
361        } finally {
362            is.close();
363        }
364    }
365
366    private static int readInt(File file) throws IOException {
367        final DataInputStream is = new DataInputStream(new FileInputStream(file));
368        try {
369            return is.readInt();
370        } finally {
371            is.close();
372        }
373    }
374}
375