FileDocCategorySizeDatePackage
DocumentFileTest.javaAPI DocAndroid 5.1 API13009Thu Mar 12 22:22:56 GMT 2015android.support.v4.provider

DocumentFileTest.java

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.v4.provider;

import android.content.ContentResolver;
import android.content.UriPermission;
import android.net.Uri;
import android.os.Environment;
import android.os.FileUtils;
import android.os.SystemClock;
import android.support.v4.provider.DocumentFile;
import android.test.AndroidTestCase;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * Tests for {@link DocumentFile}
 */
public class DocumentFileTest extends AndroidTestCase {

    private Uri treeUri;

    private File root;
    private File rootFoo;
    private File rootMeow;
    private File rootMeowCat;
    private File rootMeowDog;
    private File rootMeowBar;

    private static final String FOO = "foo.randomext";
    private static final String MEOW = "meow";
    private static final String CAT = "cat.jpg";
    private static final String DOG = "DOG.PDF";
    private static final String BAR = "bar.png";

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        final ContentResolver resolver = getContext().getContentResolver();
        final List<UriPermission> perms = resolver.getPersistedUriPermissions();

        if (perms.isEmpty()) {
            throw new RuntimeException(
                    "Failed to find outstanding grant; did you run the activity first?");
        } else {
            treeUri = perms.get(0).getUri();
        }

        root = Environment.getExternalStorageDirectory();
        rootFoo = new File(root, FOO);
        rootMeow = new File(root, MEOW);
        rootMeowCat = new File(rootMeow, CAT);
        rootMeowDog = new File(rootMeow, DOG);
        rootMeowBar = new File(rootMeow, BAR);

        resetRoot();
    }

    private void resetRoot() throws Exception {
        final File tmp = new File(root, "bark.pdf");
        FileUtils.deleteContents(tmp);
        tmp.delete();

        FileUtils.deleteContents(rootMeow);
        rootMeow.mkdir();
        rootMeowBar.mkdir();

        writeInt(rootFoo, 12);
        writeInt(rootMeowCat, 24);
        writeInt(rootMeowDog, 48);
    }

    private interface DocumentTest {
        public void exec(DocumentFile doc) throws Exception;
    }

    public void testSimple() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();
                assertTrue("isDirectory", doc.isDirectory());
                assertFalse("isFile", doc.isFile());
                assertTrue("canRead", doc.canRead());
                assertTrue("canWrite", doc.canWrite());
                assertTrue("exists", doc.exists());
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testTraverse() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                // Root needs to at least contain our test file and dir
                final DocumentFile foo = doc.findFile(FOO);
                final DocumentFile meow = doc.findFile(MEOW);
                assertTrue("isFile", foo.isFile());
                assertTrue("isDirectory", meow.isDirectory());

                // Traverse inside, and expect to find exact number of items
                DocumentFile[] docs = meow.listFiles();
                assertEquals("length", 3, docs.length);

                final DocumentFile cat = meow.findFile(CAT);
                final DocumentFile dog = meow.findFile(DOG);
                final DocumentFile bar = meow.findFile(BAR);
                assertTrue("isFile", cat.isFile());
                assertTrue("isFile", dog.isFile());
                assertTrue("isDirectory", bar.isDirectory());

                // Empty directory is empty
                assertEquals("length", 0, bar.listFiles().length);
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testReadAndWrite() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                final DocumentFile foo = doc.findFile(FOO);
                assertEquals("file", 12, readInt(rootFoo));
                assertEquals("uri", 12, readInt(foo.getUri()));

                // Underlying storage may not have sub-second resolution, so
                // wait a few seconds.
                SystemClock.sleep(2000);

                // Ensure provider write makes its way to disk
                final long beforeTime = foo.lastModified();
                writeInt(foo.getUri(), 13);
                final long afterTime = foo.lastModified();

                assertEquals("file", 13, readInt(rootFoo));
                assertEquals("uri", 13, readInt(foo.getUri()));

                // Make sure we kicked time forward
                assertTrue("lastModified", afterTime > beforeTime);
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testMimes() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                final DocumentFile foo = doc.findFile(FOO);
                final DocumentFile meow = doc.findFile(MEOW);
                final DocumentFile cat = meow.findFile(CAT);
                final DocumentFile dog = meow.findFile(DOG);
                final DocumentFile bar = meow.findFile(BAR);

                assertEquals(null, doc.getType());
                assertEquals("application/octet-stream", foo.getType());
                assertEquals(null, meow.getType());
                assertEquals("image/jpeg", cat.getType());
                assertEquals("application/pdf", dog.getType());
                assertEquals(null, bar.getType());
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testCreate() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                final DocumentFile meow = doc.findFile(MEOW);
                assertEquals("length", 3, meow.listFiles().length);

                // Create file with MIME
                final DocumentFile newFile = meow.createFile("text/plain", "My New File");
                assertEquals("My New File.txt", newFile.getName());
                assertEquals("text/plain", newFile.getType());
                assertTrue("isFile", newFile.isFile());
                assertFalse("isDirectory", newFile.isDirectory());

                assertEquals("length", 0, newFile.length());
                writeInt(newFile.getUri(), 0);
                assertEquals("length", 4, newFile.length());

                // Create raw file
                final DocumentFile newRaw = meow.createFile("application/octet-stream",
                        "myrawfile");
                assertEquals("myrawfile", newRaw.getName());
                assertEquals("application/octet-stream", newRaw.getType());
                assertTrue("isFile", newRaw.isFile());
                assertFalse("isDirectory", newRaw.isDirectory());

                // Create directory
                final DocumentFile newDir = meow.createDirectory("My New Directory.png");
                assertEquals("My New Directory.png", newDir.getName());
                assertFalse("isFile", newDir.isFile());
                assertTrue("isDirectory", newDir.isDirectory());
                assertEquals("length", 0, newDir.listFiles().length);

                // And overall dir grew
                assertEquals("length", 6, meow.listFiles().length);
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testDelete() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                final DocumentFile meow = doc.findFile(MEOW);
                final DocumentFile cat = meow.findFile(CAT);
                final DocumentFile dog = meow.findFile(DOG);

                // Delete single file
                assertTrue(cat.delete());
                assertNull("cat", meow.findFile(CAT));

                // Other file still exists
                assertTrue("exists", dog.exists());

                // Delete entire tree
                assertTrue(meow.delete());
                assertNull("meow", doc.findFile(MEOW));

                // Nuking tree deleted other file
                assertFalse("exists", dog.exists());
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    public void testRename() throws Exception {
        final DocumentTest test = new DocumentTest() {
            @Override
            public void exec(DocumentFile doc) throws Exception {
                resetRoot();

                DocumentFile meow = doc.findFile(MEOW);
                DocumentFile cat = meow.findFile(CAT);
                DocumentFile dog = meow.findFile(DOG);
                assertTrue(dog.exists());

                // Rename a file
                assertEquals("cat.jpg", cat.getName());
                assertEquals("image/jpeg", cat.getType());

                assertTrue(cat.renameTo("music.aAc"));
                assertEquals("music.aAc", cat.getName());
                assertEquals("audio/aac", cat.getType());

                // Rename a directory
                assertEquals("meow", meow.getName());
                assertEquals(null, meow.getType());
                assertTrue(meow.isDirectory());
                assertEquals(3, meow.listFiles().length);

                assertTrue(meow.renameTo("bark.pdf"));
                assertEquals("bark.pdf", meow.getName());
                assertEquals(null, meow.getType());
                assertTrue(meow.isDirectory());
                assertEquals(3, meow.listFiles().length);

                // Current implementation of ExternalStorageProvider invalidates
                // all children documents when directory is renamed.
                assertFalse(dog.exists());

                // But we can find it again
                dog = meow.findFile(DOG);
                assertTrue(dog.exists());
            }
        };

        test.exec(DocumentFile.fromFile(root));
        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
    }

    private void writeInt(Uri uri, int value) throws IOException {
        final DataOutputStream os = new DataOutputStream(
                getContext().getContentResolver().openOutputStream(uri));
        try {
            os.writeInt(value);
        } finally {
            os.close();
        }
    }

    private static void writeInt(File file, int value) throws IOException {
        final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
        try {
            os.writeInt(value);
        } finally {
            os.close();
        }
    }

    private int readInt(Uri uri) throws IOException {
        final DataInputStream is = new DataInputStream(
                getContext().getContentResolver().openInputStream(uri));
        try {
            return is.readInt();
        } finally {
            is.close();
        }
    }

    private static int readInt(File file) throws IOException {
        final DataInputStream is = new DataInputStream(new FileInputStream(file));
        try {
            return is.readInt();
        } finally {
            is.close();
        }
    }
}