301 lines
11 KiB
Java
301 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2017 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 com.android.documentsui.archives;
|
|
|
|
import android.database.Cursor;
|
|
import android.net.Uri;
|
|
import android.os.ParcelFileDescriptor;
|
|
import android.provider.DocumentsContract.Document;
|
|
import android.test.AndroidTestCase;
|
|
import android.test.suitebuilder.annotation.MediumTest;
|
|
|
|
import androidx.test.InstrumentationRegistry;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Enumeration;
|
|
import java.util.Scanner;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipFile;
|
|
|
|
@MediumTest
|
|
public class WriteableArchiveTest extends AndroidTestCase {
|
|
|
|
private static final Uri ARCHIVE_URI = Uri.parse("content://i/love/strawberries");
|
|
private static final String NOTIFICATION_URI =
|
|
"content://com.android.documentsui.archives/notification-uri";
|
|
private ExecutorService mExecutor = null;
|
|
private Archive mArchive = null;
|
|
private TestUtils mTestUtils = null;
|
|
private File mFile = null;
|
|
|
|
@Override
|
|
public void setUp() throws Exception {
|
|
super.setUp();
|
|
mExecutor = Executors.newSingleThreadExecutor();
|
|
mTestUtils = new TestUtils(InstrumentationRegistry.getTargetContext(),
|
|
InstrumentationRegistry.getContext(), mExecutor);
|
|
mFile = mTestUtils.createTemporaryFile();
|
|
|
|
mArchive = WriteableArchive.createForParcelFileDescriptor(
|
|
InstrumentationRegistry.getTargetContext(),
|
|
ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_WRITE_ONLY),
|
|
ARCHIVE_URI,
|
|
ParcelFileDescriptor.MODE_WRITE_ONLY,
|
|
Uri.parse(NOTIFICATION_URI));
|
|
}
|
|
|
|
@Override
|
|
public void tearDown() throws Exception {
|
|
mExecutor.shutdown();
|
|
assertTrue(mExecutor.awaitTermination(3 /* timeout */, TimeUnit.SECONDS));
|
|
if (mFile != null) {
|
|
mFile.delete();
|
|
}
|
|
if (mArchive != null) {
|
|
mArchive.close();
|
|
}
|
|
super.tearDown();
|
|
}
|
|
|
|
public static ArchiveId createArchiveId(String path) {
|
|
return new ArchiveId(ARCHIVE_URI, ParcelFileDescriptor.MODE_WRITE_ONLY, path);
|
|
}
|
|
|
|
public void testCreateDocument() throws IOException {
|
|
final String dirDocumentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, "dir");
|
|
assertEquals(createArchiveId("/dir/").toDocumentId(), dirDocumentId);
|
|
|
|
final String documentId = mArchive.createDocument(dirDocumentId, "image/jpeg", "test.jpeg");
|
|
assertEquals(createArchiveId("/dir/test.jpeg").toDocumentId(), documentId);
|
|
|
|
try {
|
|
mArchive.createDocument(dirDocumentId,
|
|
"image/jpeg", "test.jpeg");
|
|
fail("Creating should fail, as the document already exists.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
"image/jpeg", "test.jpeg/");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, "test/");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, "..");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, ".");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, "");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
try {
|
|
mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
"image/jpeg", "a/b.jpeg");
|
|
fail("Creating should fail, as the document name is invalid.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
}
|
|
|
|
public void testAddDirectory() throws IOException {
|
|
final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
Document.MIME_TYPE_DIR, "dir");
|
|
|
|
{
|
|
final Cursor cursor = mArchive.queryDocument(documentId, null);
|
|
assertTrue(cursor.moveToFirst());
|
|
assertEquals(documentId,
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
|
|
assertEquals("dir",
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
|
|
assertEquals(Document.MIME_TYPE_DIR,
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
|
|
assertEquals(0,
|
|
cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
|
|
}
|
|
|
|
{
|
|
final Cursor cursor = mArchive.queryChildDocuments(
|
|
createArchiveId("/").toDocumentId(), null, null);
|
|
|
|
assertTrue(cursor.moveToFirst());
|
|
assertEquals(documentId,
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
|
|
assertEquals("dir",
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
|
|
assertEquals(Document.MIME_TYPE_DIR,
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
|
|
assertEquals(0,
|
|
cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
|
|
}
|
|
|
|
mArchive.close();
|
|
|
|
// Verify archive.
|
|
ZipFile zip = null;
|
|
try {
|
|
zip = new ZipFile(mFile);
|
|
final Enumeration<? extends ZipEntry> entries = zip.entries();
|
|
assertTrue(entries.hasMoreElements());
|
|
final ZipEntry entry = entries.nextElement();
|
|
assertEquals("dir/", entry.getName());
|
|
assertFalse(entries.hasMoreElements());
|
|
} finally {
|
|
if (zip != null) {
|
|
zip.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testAddFile() throws IOException, InterruptedException {
|
|
final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
"text/plain", "hoge.txt");
|
|
|
|
{
|
|
final Cursor cursor = mArchive.queryDocument(documentId, null);
|
|
assertTrue(cursor.moveToFirst());
|
|
assertEquals(documentId,
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
|
|
assertEquals("hoge.txt",
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
|
|
assertEquals("text/plain",
|
|
cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
|
|
assertEquals(0,
|
|
cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
|
|
}
|
|
|
|
try {
|
|
mArchive.openDocument(documentId, "r", null);
|
|
fail("Should fail when opened for reading!");
|
|
} catch (IllegalArgumentException e) {
|
|
// Expected.
|
|
}
|
|
|
|
final ParcelFileDescriptor fd = mArchive.openDocument(documentId, "w", null);
|
|
try (ParcelFileDescriptor.AutoCloseOutputStream outputStream =
|
|
new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
|
|
outputStream.write("Hello world!".getBytes());
|
|
}
|
|
|
|
try {
|
|
mArchive.openDocument(documentId, "w", null);
|
|
fail("Should fail when opened for the second time!");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
// Wait until the pipe thread fully writes all the data from the pipe.
|
|
// TODO: Maybe add some method in WriteableArchive to wait until the executor
|
|
// completes the job?
|
|
Thread.sleep(500);
|
|
|
|
{
|
|
final Cursor cursor = mArchive.queryDocument(documentId, null);
|
|
assertTrue(cursor.moveToFirst());
|
|
assertEquals(12,
|
|
cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
|
|
}
|
|
|
|
mArchive.close();
|
|
|
|
// Verify archive.
|
|
ZipFile zip = null;
|
|
try {
|
|
try {
|
|
zip = new ZipFile(mFile);
|
|
} catch (Exception e) {
|
|
throw new IOException(mFile.getAbsolutePath());
|
|
}
|
|
final Enumeration<? extends ZipEntry> entries = zip.entries();
|
|
assertTrue(entries.hasMoreElements());
|
|
final ZipEntry entry = entries.nextElement();
|
|
assertEquals("hoge.txt", entry.getName());
|
|
assertFalse(entries.hasMoreElements());
|
|
final InputStream inputStream = zip.getInputStream(entry);
|
|
final Scanner scanner = new Scanner(inputStream);
|
|
assertEquals("Hello world!", scanner.nextLine());
|
|
assertFalse(scanner.hasNext());
|
|
} finally {
|
|
if (zip != null) {
|
|
zip.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testAddFile_empty() throws IOException, Exception {
|
|
final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
|
|
"text/plain", "hoge.txt");
|
|
mArchive.close();
|
|
|
|
// Verify archive.
|
|
ZipFile zip = null;
|
|
try {
|
|
try {
|
|
zip = new ZipFile(mFile);
|
|
} catch (Exception e) {
|
|
throw new IOException(mFile.getAbsolutePath());
|
|
}
|
|
final Enumeration<? extends ZipEntry> entries = zip.entries();
|
|
assertTrue(entries.hasMoreElements());
|
|
final ZipEntry entry = entries.nextElement();
|
|
assertEquals("hoge.txt", entry.getName());
|
|
assertFalse(entries.hasMoreElements());
|
|
final InputStream inputStream = zip.getInputStream(entry);
|
|
final Scanner scanner = new Scanner(inputStream);
|
|
assertFalse(scanner.hasNext());
|
|
} finally {
|
|
if (zip != null) {
|
|
zip.close();
|
|
}
|
|
}
|
|
}
|
|
}
|