| /* |
| * Copyright (C) 2019 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 static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.fail; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import android.os.ParcelFileDescriptor; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import org.apache.commons.compress.archivers.ArchiveEntry; |
| import org.apache.commons.compress.archivers.ArchiveException; |
| import org.apache.commons.compress.compressors.CompressorException; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.List; |
| import java.util.Locale; |
| |
| @RunWith(AndroidJUnit4.class) |
| public class ArchiveHandleTest { |
| @Rule |
| public ArchiveFileTestRule mArchiveFileTestRule = new ArchiveFileTestRule(); |
| |
| |
| private ArchiveHandle prepareArchiveHandle(String archivePath, String suffix, |
| String mimeType) throws IOException, CompressorException, ArchiveException { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile(archivePath, suffix); |
| |
| return ArchiveHandle.create(parcelFileDescriptor, mimeType); |
| } |
| |
| private static ArchiveEntry getFileInArchive(Enumeration<ArchiveEntry> enumeration, |
| String pathInArchive) { |
| while (enumeration.hasMoreElements()) { |
| ArchiveEntry entry = enumeration.nextElement(); |
| if (entry.getName().equals(pathInArchive)) { |
| return entry; |
| } |
| } |
| return null; |
| } |
| |
| |
| private static class ArchiveEntryRecord implements ArchiveEntry { |
| private final String mName; |
| private final long mSize; |
| private final boolean mIsDirectory; |
| |
| private ArchiveEntryRecord(ArchiveEntry archiveEntry) { |
| this(archiveEntry.getName(), archiveEntry.getSize(), archiveEntry.isDirectory()); |
| } |
| |
| private ArchiveEntryRecord(String name, long size, boolean isDirectory) { |
| mName = name; |
| mSize = size; |
| mIsDirectory = isDirectory; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (obj == null) { |
| return false; |
| } |
| |
| if (obj instanceof ArchiveEntryRecord) { |
| ArchiveEntryRecord recordB = (ArchiveEntryRecord) obj; |
| return mName.equals(recordB.mName) |
| && mSize == recordB.mSize |
| && mIsDirectory == recordB.mIsDirectory; |
| } |
| |
| return false; |
| } |
| |
| @Override |
| public String getName() { |
| return mName; |
| } |
| |
| @Override |
| public long getSize() { |
| return mSize; |
| } |
| |
| @Override |
| public boolean isDirectory() { |
| return mIsDirectory; |
| } |
| |
| @Override |
| public Date getLastModifiedDate() { |
| return null; |
| } |
| |
| @NonNull |
| @Override |
| public String toString() { |
| return String.format(Locale.ENGLISH, "name: %s, size: %d, isDirectory: %b", |
| mName, mSize, mIsDirectory); |
| } |
| } |
| |
| private static List<ArchiveEntry> transformToIterable(Enumeration<ArchiveEntry> enumeration) { |
| List list = new ArrayList<ArchiveEntry>(); |
| while (enumeration.hasMoreElements()) { |
| list.add(new ArchiveEntryRecord(enumeration.nextElement())); |
| } |
| return list; |
| } |
| |
| private static final List<ArchiveEntryRecord> sExpectEntries = |
| new ArrayList<ArchiveEntryRecord>() { |
| { |
| add(new ArchiveEntryRecord("hello/hello.txt", 48, false)); |
| add(new ArchiveEntryRecord("hello/inside_folder/hello_insside.txt", |
| 14, false)); |
| add(new ArchiveEntryRecord("hello/hello2.txt", 48, false)); |
| } |
| }; |
| |
| |
| @Test |
| public void buildArchiveHandle_withoutFileDescriptor_shouldBeIllegal() throws Exception { |
| try { |
| ArchiveHandle.create(null, |
| "application/x-7z-compressed"); |
| fail("It should not be here!"); |
| } catch (NullPointerException e) { |
| /* do nothing */ |
| } |
| } |
| |
| @Test |
| public void buildArchiveHandle_withWrongMimeType_shouldBeIllegal() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/7z/hello.7z", ".7z"); |
| |
| try { |
| ArchiveHandle.create(parcelFileDescriptor, null); |
| fail("It should not be here!"); |
| } catch (IllegalArgumentException e) { |
| /* do nothing */ |
| } |
| } |
| |
| @Test |
| public void buildArchiveHandle_sevenZFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", |
| ".7z", "application/x-7z-compressed"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_zipFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_zipWithWrongMimeType_shouldBeNull() throws Exception { |
| try { |
| prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/xxxzip"); |
| fail("It should not be here!"); |
| } catch (UnsupportedOperationException e) { |
| /* do nothing */ |
| } |
| } |
| |
| @Test |
| public void buildArchiveHandle_tarFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar/hello.tar", |
| ".tar", "application/x-gtar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_tgzFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello.tgz", |
| ".tgz", "application/x-compressed-tar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_tarGzFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar_gz/hello_tar_gz", ".tar.gz", |
| "application/x-compressed-tar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_tarBzipFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", |
| ".tar.bz2", "application/x-bzip-compressed-tar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_tarXzFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", |
| "application/x-xz-compressed-tar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void buildArchiveHandle_tarBrFile_shouldNotNull() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", |
| "application/x-brotli-compressed-tar"); |
| |
| assertThat(archiveHandle).isNotNull(); |
| } |
| |
| @Test |
| public void getMimeType_sevenZFile_shouldBeSevenZ() |
| throws CompressorException, ArchiveException, IOException { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", |
| ".7z", "application/x-7z-compressed"); |
| |
| assertThat(archiveHandle.getMimeType()).isEqualTo("application/x-7z-compressed"); |
| } |
| |
| @Test |
| public void getMimeType_tarBrotli_shouldBeBrotliCompressedTar() |
| throws CompressorException, ArchiveException, IOException { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", |
| "application/x-brotli-compressed-tar"); |
| |
| assertThat(archiveHandle.getMimeType()) |
| .isEqualTo("application/x-brotli-compressed-tar"); |
| } |
| |
| @Test |
| public void getMimeType_tarXz_shouldBeXzCompressedTar() |
| throws CompressorException, ArchiveException, IOException { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", |
| "application/x-xz-compressed-tar"); |
| |
| assertThat(archiveHandle.getMimeType()) |
| .isEqualTo("application/x-xz-compressed-tar"); |
| } |
| |
| @Test |
| public void getMimeType_tarGz_shouldBeCompressedTar() |
| throws CompressorException, ArchiveException, IOException { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar_gz/hello_tar_gz", ".tar.gz", |
| "application/x-compressed-tar"); |
| |
| assertThat(archiveHandle.getMimeType()) |
| .isEqualTo("application/x-compressed-tar"); |
| } |
| |
| @Test |
| public void getCommonArchive_tarBrFile_shouldBeCommonArchiveInputHandle() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", |
| "application/x-brotli-compressed-tar"); |
| |
| assertThat(archiveHandle.toString()).contains("CommonArchiveInputHandle"); |
| } |
| |
| @Test |
| public void getCommonArchive_sevenZFile_shouldBeSevenZFileHandle() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", |
| ".7z", "application/x-7z-compressed"); |
| |
| assertThat(archiveHandle.toString()).contains("SevenZFileHandle"); |
| } |
| |
| |
| @Test |
| public void getCommonArchive_zipFile_shouldBeZipFileHandle() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| assertThat(archiveHandle.toString()).contains("ZipFileHandle"); |
| } |
| |
| @Test |
| public void close_zipFile_shouldBeSuccess() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| archiveHandle.close(); |
| } |
| |
| @Test |
| public void close_sevenZFile_shouldBeSuccess() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", |
| ".7z", "application/x-7z-compressed"); |
| |
| archiveHandle.close(); |
| } |
| |
| @Test |
| public void closeInputStream_zipFile_shouldBeSuccess() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| InputStream inputStream = archiveHandle.getInputStream( |
| getFileInArchive(archiveHandle.getEntries(), |
| "hello/inside_folder/hello_insside.txt")); |
| |
| assertThat(inputStream).isNotNull(); |
| |
| inputStream.close(); |
| } |
| |
| @Test |
| public void close_zipFile_shouldNotOpen() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/zip/hello.zip", ".zip"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/zip"); |
| |
| archiveHandle.close(); |
| |
| FileInputStream fileInputStream = |
| new FileInputStream(parcelFileDescriptor.getFileDescriptor()); |
| assertThat(fileInputStream).isNotNull(); |
| } |
| |
| @Test |
| public void getInputStream_zipFile_shouldHaveTheSameContent() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/zip/hello.zip", ".zip"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/zip"); |
| |
| InputStream inputStream = archiveHandle.getInputStream( |
| getFileInArchive(archiveHandle.getEntries(), |
| "hello/inside_folder/hello_insside.txt")); |
| |
| assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) |
| .isEqualTo(expectedContent); |
| } |
| |
| @Test |
| public void getInputStream_zipFileNotExistEntry_shouldFail() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| ArchiveEntry archiveEntry = mock(ArchiveEntry.class); |
| when(archiveEntry.getName()).thenReturn("/not_exist_entry"); |
| |
| try { |
| archiveHandle.getInputStream(archiveEntry); |
| fail("It should not be here."); |
| } catch (ClassCastException e) { |
| /* do nothing */ |
| } |
| } |
| |
| @Test |
| public void getInputStream_directoryEntry_shouldFail() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| ArchiveEntry archiveEntry = mock(ArchiveEntry.class); |
| when(archiveEntry.isDirectory()).thenReturn(true); |
| |
| try { |
| archiveHandle.getInputStream(archiveEntry); |
| fail("It should not be here."); |
| } catch (IllegalArgumentException e) { |
| /* expected, do nothing */ |
| } |
| } |
| |
| @Test |
| public void getInputStream_negativeSizeEntry_shouldFail() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| ArchiveEntry archiveEntry = mock(ArchiveEntry.class); |
| when(archiveEntry.isDirectory()).thenReturn(false); |
| when(archiveEntry.getSize()).thenReturn(-1L); |
| |
| try { |
| archiveHandle.getInputStream(archiveEntry); |
| fail("It should not be here."); |
| } catch (IllegalArgumentException e) { |
| /* expected, do nothing */ |
| } |
| } |
| |
| @Test |
| public void getInputStream_emptyStringEntry_shouldFail() throws Exception { |
| ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", |
| ".zip", "application/zip"); |
| |
| ArchiveEntry archiveEntry = mock(ArchiveEntry.class); |
| when(archiveEntry.isDirectory()).thenReturn(false); |
| when(archiveEntry.getSize()).thenReturn(14L); |
| when(archiveEntry.getName()).thenReturn(""); |
| |
| try { |
| archiveHandle.getInputStream(archiveEntry); |
| fail("It should not be here."); |
| } catch (IllegalArgumentException e) { |
| /* expected, do nothing */ |
| } |
| } |
| |
| @Test |
| public void getInputStream_sevenZFile_shouldHaveTheSameContent() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/7z/hello.7z", ".7z"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/x-7z-compressed"); |
| |
| InputStream inputStream = archiveHandle.getInputStream( |
| getFileInArchive(archiveHandle.getEntries(), |
| "hello/inside_folder/hello_insside.txt")); |
| |
| assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) |
| .isEqualTo(expectedContent); |
| } |
| |
| @Test |
| public void getInputStream_tarGzFile_shouldHaveTheSameContent() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/x-compressed-tar"); |
| |
| InputStream inputStream = archiveHandle.getInputStream( |
| getFileInArchive(archiveHandle.getEntries(), |
| "hello/inside_folder/hello_insside.txt")); |
| |
| assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) |
| .isEqualTo(expectedContent); |
| } |
| |
| @Test |
| public void getInputStream_tarGzFileNullEntry_getNullInputStream() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/x-compressed-tar"); |
| |
| try { |
| archiveHandle.getInputStream(null); |
| fail("It should not here"); |
| } catch (IllegalArgumentException | ArchiveException | CompressorException e) { |
| /* expected, do nothing */ |
| } |
| } |
| |
| |
| @Test |
| public void getInputStream_tarGzFileInvalidEntry_getNullInputStream() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/x-compressed-tar"); |
| |
| ArchiveEntry archiveEntry = mock(ArchiveEntry.class); |
| when(archiveEntry.getName()).thenReturn(""); |
| try { |
| archiveHandle.getInputStream(archiveEntry); |
| fail("It should not here"); |
| } catch (IllegalArgumentException | ArchiveException | CompressorException e) { |
| /* expected, do nothing */ |
| } |
| } |
| |
| @Test |
| public void getInputStream_tarBrotliFile_shouldHaveTheSameContent() throws Exception { |
| ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule |
| .openAssetFile("archives/brotli/hello.tar.br", ".tar.br"); |
| |
| String expectedContent = mArchiveFileTestRule.getAssetText( |
| "archives/original/hello/inside_folder/hello_insside.txt"); |
| |
| ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, |
| "application/x-brotli-compressed-tar"); |
| |
| InputStream inputStream = archiveHandle.getInputStream( |
| getFileInArchive(archiveHandle.getEntries(), |
| "hello/inside_folder/hello_insside.txt")); |
| |
| assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) |
| .isEqualTo(expectedContent); |
| } |
| |
| @Test |
| public void getEntries_zipFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/zip/hello.zip", ".zip", |
| "application/zip"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| |
| @Test |
| public void getEntries_tarFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar/hello.tar", ".tar", |
| "application/x-gtar"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| |
| @Test |
| public void getEntries_tgzFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar_gz/hello.tgz", ".tgz", |
| "application/x-compressed-tar"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| |
| @Test |
| public void getEntries_tarBzFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", ".tar.bz2", |
| "application/x-bzip-compressed-tar"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| |
| @Test |
| public void getEntries_tarBrotliFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", |
| "application/x-brotli-compressed-tar"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| |
| @Test |
| public void getEntries_tarXzFile_shouldTheSameWithList() throws Exception { |
| ArchiveHandle archiveHandle = |
| prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", |
| "application/x-xz-compressed-tar"); |
| |
| assertThat(transformToIterable(archiveHandle.getEntries())) |
| .containsAllIn(sExpectEntries); |
| } |
| } |