Home | History | Annotate | Download | only in archives
      1 /*
      2  * Copyright (C) 2015 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 com.android.documentsui.archives;
     18 
     19 import com.android.documentsui.archives.ReadableArchive;
     20 import com.android.documentsui.tests.R;
     21 
     22 import android.content.Context;
     23 import android.database.Cursor;
     24 import android.net.Uri;
     25 import android.os.ParcelFileDescriptor;
     26 import android.provider.DocumentsContract.Document;
     27 import android.support.test.InstrumentationRegistry;
     28 import android.system.ErrnoException;
     29 import android.system.Os;
     30 import android.system.OsConstants;
     31 import android.test.AndroidTestCase;
     32 import android.test.suitebuilder.annotation.MediumTest;
     33 
     34 import java.io.File;
     35 import java.io.FileOutputStream;
     36 import java.io.IOException;
     37 import java.io.InputStream;
     38 import java.util.Scanner;
     39 import java.util.concurrent.ExecutorService;
     40 import java.util.concurrent.Executors;
     41 import java.util.concurrent.TimeUnit;
     42 
     43 @MediumTest
     44 public class ReadableArchiveTest extends AndroidTestCase {
     45     private static final Uri ARCHIVE_URI = Uri.parse("content://i/love/strawberries");
     46     private static final String NOTIFICATION_URI =
     47             "content://com.android.documentsui.archives/notification-uri";
     48     private ExecutorService mExecutor = null;
     49     private Archive mArchive = null;
     50     private TestUtils mTestUtils = null;
     51 
     52     @Override
     53     public void setUp() throws Exception {
     54         super.setUp();
     55         mExecutor = Executors.newSingleThreadExecutor();
     56         mTestUtils = new TestUtils(InstrumentationRegistry.getTargetContext(),
     57                 InstrumentationRegistry.getContext(), mExecutor);
     58     }
     59 
     60     @Override
     61     public void tearDown() throws Exception {
     62         mExecutor.shutdown();
     63         assertTrue(mExecutor.awaitTermination(3 /* timeout */, TimeUnit.SECONDS));
     64         if (mArchive != null) {
     65             mArchive.close();
     66         }
     67         super.tearDown();
     68     }
     69 
     70     public static ArchiveId createArchiveId(String path) {
     71         return new ArchiveId(ARCHIVE_URI, ParcelFileDescriptor.MODE_READ_ONLY, path);
     72     }
     73 
     74     public void loadArchive(ParcelFileDescriptor descriptor) throws IOException {
     75         mArchive = ReadableArchive.createForParcelFileDescriptor(
     76                 InstrumentationRegistry.getTargetContext(),
     77                 descriptor,
     78                 ARCHIVE_URI,
     79                 ParcelFileDescriptor.MODE_READ_ONLY,
     80                 Uri.parse(NOTIFICATION_URI));
     81     }
     82 
     83     public void testQueryChildDocument() throws IOException {
     84         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
     85         final Cursor cursor = mArchive.queryChildDocuments(
     86                 createArchiveId("/").toDocumentId(), null, null);
     87 
     88         assertTrue(cursor.moveToFirst());
     89         assertEquals(
     90                 createArchiveId("/file1.txt").toDocumentId(),
     91                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
     92         assertEquals("file1.txt",
     93                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
     94         assertEquals("text/plain",
     95                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
     96         assertEquals(13,
     97                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
     98 
     99         assertTrue(cursor.moveToNext());
    100         assertEquals(createArchiveId("/dir1/").toDocumentId(),
    101                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
    102         assertEquals("dir1",
    103                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
    104         assertEquals(Document.MIME_TYPE_DIR,
    105                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
    106         assertEquals(0,
    107                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    108 
    109         assertTrue(cursor.moveToNext());
    110         assertEquals(
    111                 createArchiveId("/dir2/").toDocumentId(),
    112                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
    113         assertEquals("dir2",
    114                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
    115         assertEquals(Document.MIME_TYPE_DIR,
    116                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
    117         assertEquals(0,
    118                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    119 
    120         assertFalse(cursor.moveToNext());
    121 
    122         // Check if querying children works too.
    123         final Cursor childCursor = mArchive.queryChildDocuments(
    124                 createArchiveId("/dir1/").toDocumentId(), null, null);
    125 
    126         assertTrue(childCursor.moveToFirst());
    127         assertEquals(
    128                 createArchiveId("/dir1/cherries.txt").toDocumentId(),
    129                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    130                         Document.COLUMN_DOCUMENT_ID)));
    131         assertEquals("cherries.txt",
    132                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    133                         Document.COLUMN_DISPLAY_NAME)));
    134         assertEquals("text/plain",
    135                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    136                         Document.COLUMN_MIME_TYPE)));
    137         assertEquals(17,
    138                 childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    139     }
    140 
    141     public void testQueryChildDocument_NoDirs() throws IOException {
    142         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.no_dirs));
    143         final Cursor cursor = mArchive.queryChildDocuments(
    144             createArchiveId("/").toDocumentId(), null, null);
    145 
    146         assertTrue(cursor.moveToFirst());
    147         assertEquals(
    148                 createArchiveId("/dir1/").toDocumentId(),
    149                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
    150         assertEquals("dir1",
    151                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
    152         assertEquals(Document.MIME_TYPE_DIR,
    153                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
    154         assertEquals(0,
    155                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    156         assertFalse(cursor.moveToNext());
    157 
    158         final Cursor childCursor = mArchive.queryChildDocuments(
    159                 createArchiveId("/dir1/").toDocumentId(), null, null);
    160 
    161         assertTrue(childCursor.moveToFirst());
    162         assertEquals(
    163                 createArchiveId("/dir1/dir2/").toDocumentId(),
    164                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    165                         Document.COLUMN_DOCUMENT_ID)));
    166         assertEquals("dir2",
    167                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    168                         Document.COLUMN_DISPLAY_NAME)));
    169         assertEquals(Document.MIME_TYPE_DIR,
    170                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    171                         Document.COLUMN_MIME_TYPE)));
    172         assertEquals(0,
    173                 childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    174         assertFalse(childCursor.moveToNext());
    175 
    176         final Cursor childCursor2 = mArchive.queryChildDocuments(
    177                 createArchiveId("/dir1/dir2/").toDocumentId(),
    178                 null, null);
    179 
    180         assertTrue(childCursor2.moveToFirst());
    181         assertEquals(
    182                 createArchiveId("/dir1/dir2/cherries.txt").toDocumentId(),
    183                 childCursor2.getString(childCursor.getColumnIndexOrThrow(
    184                         Document.COLUMN_DOCUMENT_ID)));
    185         assertFalse(childCursor2.moveToNext());
    186     }
    187 
    188     public void testQueryChildDocument_EmptyDirs() throws IOException {
    189         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.empty_dirs));
    190         final Cursor cursor = mArchive.queryChildDocuments(
    191                 createArchiveId("/").toDocumentId(), null, null);
    192 
    193         assertTrue(cursor.moveToFirst());
    194         assertEquals(
    195                 createArchiveId("/dir1/").toDocumentId(),
    196                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
    197         assertEquals("dir1",
    198                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
    199         assertEquals(Document.MIME_TYPE_DIR,
    200                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
    201         assertEquals(0,
    202                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    203         assertFalse(cursor.moveToNext());
    204 
    205         final Cursor childCursor = mArchive.queryChildDocuments(
    206                 createArchiveId("/dir1/").toDocumentId(), null, null);
    207 
    208         assertTrue(childCursor.moveToFirst());
    209         assertEquals(
    210                 createArchiveId("/dir1/dir2/").toDocumentId(),
    211                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    212                         Document.COLUMN_DOCUMENT_ID)));
    213         assertEquals("dir2",
    214                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    215                         Document.COLUMN_DISPLAY_NAME)));
    216         assertEquals(Document.MIME_TYPE_DIR,
    217                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    218                         Document.COLUMN_MIME_TYPE)));
    219         assertEquals(0,
    220                 childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    221 
    222         assertTrue(childCursor.moveToNext());
    223         assertEquals(
    224                 createArchiveId("/dir1/dir3/").toDocumentId(),
    225                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    226                         Document.COLUMN_DOCUMENT_ID)));
    227         assertEquals("dir3",
    228                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    229                         Document.COLUMN_DISPLAY_NAME)));
    230         assertEquals(Document.MIME_TYPE_DIR,
    231                 childCursor.getString(childCursor.getColumnIndexOrThrow(
    232                         Document.COLUMN_MIME_TYPE)));
    233         assertEquals(0,
    234                 childCursor.getInt(childCursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    235         assertFalse(cursor.moveToNext());
    236 
    237         final Cursor childCursor2 = mArchive.queryChildDocuments(
    238                 createArchiveId("/dir1/dir2/").toDocumentId(),
    239                 null, null);
    240         assertFalse(childCursor2.moveToFirst());
    241 
    242         final Cursor childCursor3 = mArchive.queryChildDocuments(
    243                 createArchiveId("/dir1/dir3/").toDocumentId(),
    244                 null, null);
    245         assertFalse(childCursor3.moveToFirst());
    246     }
    247 
    248     public void testGetDocumentType() throws IOException {
    249         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
    250         assertEquals(Document.MIME_TYPE_DIR, mArchive.getDocumentType(
    251                 createArchiveId("/dir1/").toDocumentId()));
    252         assertEquals("text/plain", mArchive.getDocumentType(
    253                 createArchiveId("/file1.txt").toDocumentId()));
    254     }
    255 
    256     public void testIsChildDocument() throws IOException {
    257         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
    258         final String documentId = createArchiveId("/").toDocumentId();
    259         assertTrue(mArchive.isChildDocument(documentId,
    260                 createArchiveId("/dir1/").toDocumentId()));
    261         assertFalse(mArchive.isChildDocument(documentId,
    262                 createArchiveId("/this-does-not-exist").toDocumentId()));
    263         assertTrue(mArchive.isChildDocument(
    264                 createArchiveId("/dir1/").toDocumentId(),
    265                 createArchiveId("/dir1/cherries.txt").toDocumentId()));
    266         assertTrue(mArchive.isChildDocument(documentId,
    267                 createArchiveId("/dir1/cherries.txt").toDocumentId()));
    268     }
    269 
    270     public void testQueryDocument() throws IOException {
    271         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
    272         final Cursor cursor = mArchive.queryDocument(
    273                 createArchiveId("/dir2/strawberries.txt").toDocumentId(),
    274                 null);
    275 
    276         assertTrue(cursor.moveToFirst());
    277         assertEquals(
    278                 createArchiveId("/dir2/strawberries.txt").toDocumentId(),
    279                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
    280         assertEquals("strawberries.txt",
    281                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
    282         assertEquals("text/plain",
    283                 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
    284         assertEquals(21,
    285                 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
    286     }
    287 
    288     public void testOpenDocument() throws IOException, ErrnoException {
    289         loadArchive(mTestUtils.getSeekableDescriptor(R.raw.archive));
    290         commonTestOpenDocument();
    291     }
    292 
    293     public void testOpenDocument_NonSeekable() throws IOException, ErrnoException {
    294         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
    295         commonTestOpenDocument();
    296     }
    297 
    298     // Common part of testOpenDocument and testOpenDocument_NonSeekable.
    299     void commonTestOpenDocument() throws IOException, ErrnoException {
    300         final ParcelFileDescriptor descriptor = mArchive.openDocument(
    301                 createArchiveId("/dir2/strawberries.txt").toDocumentId(),
    302                 "r", null /* signal */);
    303         assertTrue(Archive.canSeek(descriptor));
    304         try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
    305                 new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
    306             Os.lseek(descriptor.getFileDescriptor(), "I love ".length(), OsConstants.SEEK_SET);
    307             assertEquals("strawberries!", new Scanner(inputStream).nextLine());
    308             Os.lseek(descriptor.getFileDescriptor(), 0, OsConstants.SEEK_SET);
    309             assertEquals("I love strawberries!", new Scanner(inputStream).nextLine());
    310         }
    311     }
    312 
    313     public void testCanSeek() throws IOException {
    314         assertTrue(Archive.canSeek(mTestUtils.getSeekableDescriptor(R.raw.archive)));
    315         assertFalse(Archive.canSeek(mTestUtils.getNonSeekableDescriptor(R.raw.archive)));
    316     }
    317 
    318     public void testBrokenArchive() throws IOException {
    319         loadArchive(mTestUtils.getNonSeekableDescriptor(R.raw.archive));
    320         final Cursor cursor = mArchive.queryChildDocuments(
    321                 createArchiveId("/").toDocumentId(), null, null);
    322     }
    323 }
    324