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