summaryrefslogtreecommitdiff
path: root/google/zip_reader_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'google/zip_reader_unittest.cc')
-rw-r--r--google/zip_reader_unittest.cc708
1 files changed, 489 insertions, 219 deletions
diff --git a/google/zip_reader_unittest.cc b/google/zip_reader_unittest.cc
index 44134f8..fc80637 100644
--- a/google/zip_reader_unittest.cc
+++ b/google/zip_reader_unittest.cc
@@ -8,30 +8,36 @@
#include <stdint.h>
#include <string.h>
-#include <set>
+#include <iterator>
#include <string>
+#include <vector>
#include "base/bind.h"
#include "base/check.h"
#include "base/files/file.h"
+#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/hash/md5.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "third_party/zlib/google/zip_internal.h"
-using ::testing::Return;
using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::SizeIs;
namespace {
@@ -39,10 +45,7 @@ const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
class FileWrapper {
public:
- typedef enum {
- READ_ONLY,
- READ_WRITE
- } AccessMode;
+ typedef enum { READ_ONLY, READ_WRITE } AccessMode;
FileWrapper(const base::FilePath& path, AccessMode mode) {
int flags = base::File::FLAG_READ;
@@ -73,18 +76,13 @@ class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> {
: success_calls_(0),
failure_calls_(0),
progress_calls_(0),
- current_progress_(0) {
- }
+ current_progress_(0) {}
// Success callback for async functions.
- void OnUnzipSuccess() {
- success_calls_++;
- }
+ void OnUnzipSuccess() { success_calls_++; }
// Failure callback for async functions.
- void OnUnzipFailure() {
- failure_calls_++;
- }
+ void OnUnzipFailure() { failure_calls_++; }
// Progress callback for async functions.
void OnUnzipProgress(int64_t progress) {
@@ -111,184 +109,189 @@ class MockWriterDelegate : public zip::WriterDelegate {
MOCK_METHOD0(PrepareOutput, bool());
MOCK_METHOD2(WriteBytes, bool(const char*, int));
MOCK_METHOD1(SetTimeModified, void(const base::Time&));
+ MOCK_METHOD1(SetPosixFilePermissions, void(int));
+ MOCK_METHOD0(OnError, void());
};
bool ExtractCurrentEntryToFilePath(zip::ZipReader* reader,
base::FilePath path) {
zip::FilePathWriterDelegate writer(path);
- return reader->ExtractCurrentEntry(&writer,
- std::numeric_limits<uint64_t>::max());
+ return reader->ExtractCurrentEntry(&writer);
}
-bool LocateAndOpenEntry(zip::ZipReader* reader,
- const base::FilePath& path_in_zip) {
+const zip::ZipReader::Entry* LocateAndOpenEntry(
+ zip::ZipReader* const reader,
+ const base::FilePath& path_in_zip) {
+ DCHECK(reader);
+ EXPECT_TRUE(reader->ok());
+
// The underlying library can do O(1) access, but ZipReader does not expose
// that. O(N) access is acceptable for these tests.
- while (reader->HasMore()) {
- if (!reader->OpenCurrentEntryInZip())
- return false;
- if (reader->current_entry_info()->file_path() == path_in_zip)
- return true;
- reader->AdvanceToNextEntry();
+ while (const zip::ZipReader::Entry* const entry = reader->Next()) {
+ EXPECT_TRUE(reader->ok());
+ if (entry->path == path_in_zip)
+ return entry;
}
- return false;
+
+ EXPECT_TRUE(reader->ok());
+ return nullptr;
}
-} // namespace
+using Paths = std::vector<base::FilePath>;
+
+} // namespace
namespace zip {
// Make the test a PlatformTest to setup autorelease pools properly on Mac.
class ZipReaderTest : public PlatformTest {
protected:
- virtual void SetUp() {
+ void SetUp() override {
PlatformTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
test_dir_ = temp_dir_.GetPath();
-
- ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_));
-
- test_zip_file_ = test_data_dir_.AppendASCII("test.zip");
- encrypted_zip_file_ = test_data_dir_.AppendASCII("test_encrypted.zip");
- evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip");
- evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII(
- "evil_via_invalid_utf8.zip");
- evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII(
- "evil_via_absolute_file_name.zip");
-
- test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/")));
- test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/")));
- test_zip_contents_.insert(
- base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")));
- test_zip_contents_.insert(
- base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
- test_zip_contents_.insert(
- base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")));
- test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
- test_zip_contents_.insert(
- base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
}
- virtual void TearDown() {
- PlatformTest::TearDown();
+ static base::FilePath GetTestDataDirectory() {
+ base::FilePath path;
+ CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &path));
+ return path.AppendASCII("third_party")
+ .AppendASCII("zlib")
+ .AppendASCII("google")
+ .AppendASCII("test")
+ .AppendASCII("data");
}
- bool GetTestDataDirectory(base::FilePath* path) {
- bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, path);
- EXPECT_TRUE(success);
- if (!success)
- return false;
- *path = path->AppendASCII("third_party");
- *path = path->AppendASCII("zlib");
- *path = path->AppendASCII("google");
- *path = path->AppendASCII("test");
- *path = path->AppendASCII("data");
- return true;
- }
+ static Paths GetPaths(const base::FilePath& zip_path,
+ base::StringPiece encoding = {}) {
+ Paths paths;
+
+ if (ZipReader reader; reader.Open(zip_path)) {
+ if (!encoding.empty())
+ reader.SetEncoding(std::string(encoding));
+
+ while (const ZipReader::Entry* const entry = reader.Next()) {
+ EXPECT_TRUE(reader.ok());
+ paths.push_back(entry->path);
+ }
+
+ EXPECT_TRUE(reader.ok());
+ }
- bool CompareFileAndMD5(const base::FilePath& path,
- const std::string expected_md5) {
- // Read the output file and compute the MD5.
- std::string output;
- if (!base::ReadFileToString(path, &output))
- return false;
- const std::string md5 = base::MD5String(output);
- return expected_md5 == md5;
+ return paths;
}
// The path to temporary directory used to contain the test operations.
base::FilePath test_dir_;
// The path to the test data directory where test.zip etc. are located.
- base::FilePath test_data_dir_;
+ const base::FilePath data_dir_ = GetTestDataDirectory();
// The path to test.zip in the test data directory.
- base::FilePath test_zip_file_;
- // The path to test_encrypted.zip in the test data directory.
- base::FilePath encrypted_zip_file_;
- // The path to evil.zip in the test data directory.
- base::FilePath evil_zip_file_;
- // The path to evil_via_invalid_utf8.zip in the test data directory.
- base::FilePath evil_via_invalid_utf8_zip_file_;
- // The path to evil_via_absolute_file_name.zip in the test data directory.
- base::FilePath evil_via_absolute_file_name_zip_file_;
- std::set<base::FilePath> test_zip_contents_;
-
+ const base::FilePath test_zip_file_ = data_dir_.AppendASCII("test.zip");
+ const Paths test_zip_contents_ = {
+ base::FilePath(FILE_PATH_LITERAL("foo/")),
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")),
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")),
+ base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")),
+ base::FilePath(FILE_PATH_LITERAL("foo.txt")),
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")),
+ };
base::ScopedTempDir temp_dir_;
-
base::test::TaskEnvironment task_environment_;
};
TEST_F(ZipReaderTest, Open_ValidZipFile) {
ZipReader reader;
- ASSERT_TRUE(reader.Open(test_zip_file_));
+ EXPECT_TRUE(reader.Open(test_zip_file_));
+ EXPECT_TRUE(reader.ok());
}
TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) {
ZipReader reader;
+ EXPECT_FALSE(reader.ok());
FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
- ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ EXPECT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ EXPECT_TRUE(reader.ok());
}
TEST_F(ZipReaderTest, Open_NonExistentFile) {
ZipReader reader;
- ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip")));
+ EXPECT_FALSE(reader.ok());
+ EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("nonexistent.zip")));
+ EXPECT_FALSE(reader.ok());
}
TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) {
ZipReader reader;
- ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh")));
+ EXPECT_FALSE(reader.ok());
+ EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("create_test_zip.sh")));
+ EXPECT_FALSE(reader.ok());
}
-// Iterate through the contents in the test zip file, and compare that the
-// contents collected from the zip reader matches the expected contents.
+TEST_F(ZipReaderTest, Open_EmptyFile) {
+ ZipReader reader;
+ EXPECT_FALSE(reader.ok());
+ EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("empty.zip")));
+ EXPECT_FALSE(reader.ok());
+}
+
+// Iterate through the contents in the test ZIP archive, and compare that the
+// contents collected from the ZipReader matches the expected contents.
TEST_F(ZipReaderTest, Iteration) {
- std::set<base::FilePath> actual_contents;
+ Paths actual_contents;
ZipReader reader;
- ASSERT_TRUE(reader.Open(test_zip_file_));
- while (reader.HasMore()) {
- ASSERT_TRUE(reader.OpenCurrentEntryInZip());
- actual_contents.insert(reader.current_entry_info()->file_path());
- ASSERT_TRUE(reader.AdvanceToNextEntry());
+ EXPECT_FALSE(reader.ok());
+ EXPECT_TRUE(reader.Open(test_zip_file_));
+ EXPECT_TRUE(reader.ok());
+ while (const ZipReader::Entry* const entry = reader.Next()) {
+ EXPECT_TRUE(reader.ok());
+ actual_contents.push_back(entry->path);
}
- EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
- EXPECT_EQ(test_zip_contents_.size(),
- static_cast<size_t>(reader.num_entries()));
- EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
- EXPECT_EQ(test_zip_contents_, actual_contents);
+
+ EXPECT_TRUE(reader.ok());
+ EXPECT_FALSE(reader.Next()); // Shouldn't go further.
+ EXPECT_TRUE(reader.ok());
+
+ EXPECT_THAT(actual_contents, SizeIs(reader.num_entries()));
+ EXPECT_THAT(actual_contents, ElementsAreArray(test_zip_contents_));
}
-// Open the test zip file from a file descriptor, iterate through its contents,
-// and compare that they match the expected contents.
+// Open the test ZIP archive from a file descriptor, iterate through its
+// contents, and compare that they match the expected contents.
TEST_F(ZipReaderTest, PlatformFileIteration) {
- std::set<base::FilePath> actual_contents;
+ Paths actual_contents;
ZipReader reader;
FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
- ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
- while (reader.HasMore()) {
- ASSERT_TRUE(reader.OpenCurrentEntryInZip());
- actual_contents.insert(reader.current_entry_info()->file_path());
- ASSERT_TRUE(reader.AdvanceToNextEntry());
+ EXPECT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ EXPECT_TRUE(reader.ok());
+ while (const ZipReader::Entry* const entry = reader.Next()) {
+ EXPECT_TRUE(reader.ok());
+ actual_contents.push_back(entry->path);
}
- EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
- EXPECT_EQ(test_zip_contents_.size(),
- static_cast<size_t>(reader.num_entries()));
- EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
- EXPECT_EQ(test_zip_contents_, actual_contents);
+
+ EXPECT_TRUE(reader.ok());
+ EXPECT_FALSE(reader.Next()); // Shouldn't go further.
+ EXPECT_TRUE(reader.ok());
+
+ EXPECT_THAT(actual_contents, SizeIs(reader.num_entries()));
+ EXPECT_THAT(actual_contents, ElementsAreArray(test_zip_contents_));
}
-TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
+TEST_F(ZipReaderTest, RegularFile) {
ZipReader reader;
ASSERT_TRUE(reader.Open(test_zip_file_));
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
- EXPECT_EQ(target_path, current_entry_info->file_path());
- EXPECT_EQ(13527, current_entry_info->original_size());
+ const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
+ ASSERT_TRUE(entry);
+
+ EXPECT_EQ(target_path, entry->path);
+ EXPECT_EQ(13527, entry->original_size);
// The expected time stamp: 2009-05-29 06:22:20
base::Time::Exploded exploded = {}; // Zero-clear.
- current_entry_info->last_modified().LocalExplode(&exploded);
+ entry->last_modified.UTCExplode(&exploded);
EXPECT_EQ(2009, exploded.year);
EXPECT_EQ(5, exploded.month);
EXPECT_EQ(29, exploded.day_of_month);
@@ -297,67 +300,108 @@ TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
EXPECT_EQ(20, exploded.second);
EXPECT_EQ(0, exploded.millisecond);
- EXPECT_FALSE(current_entry_info->is_unsafe());
- EXPECT_FALSE(current_entry_info->is_directory());
+ EXPECT_FALSE(entry->is_unsafe);
+ EXPECT_FALSE(entry->is_directory);
}
-TEST_F(ZipReaderTest, current_entry_info_DotDotFile) {
+TEST_F(ZipReaderTest, DotDotFile) {
ZipReader reader;
- ASSERT_TRUE(reader.Open(evil_zip_file_));
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("evil.zip")));
base::FilePath target_path(FILE_PATH_LITERAL(
"../levilevilevilevilevilevilevilevilevilevilevilevil"));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
- EXPECT_EQ(target_path, current_entry_info->file_path());
-
+ const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(target_path, entry->path);
// This file is unsafe because of ".." in the file name.
- EXPECT_TRUE(current_entry_info->is_unsafe());
- EXPECT_FALSE(current_entry_info->is_directory());
+ EXPECT_TRUE(entry->is_unsafe);
+ EXPECT_FALSE(entry->is_directory);
}
-TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) {
+TEST_F(ZipReaderTest, InvalidUTF8File) {
ZipReader reader;
- ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_));
- // The evil file is the 2nd file in the zip file.
- // We cannot locate by the file name ".\x80.\\evil.txt",
- // as FilePath may internally convert the string.
- ASSERT_TRUE(reader.AdvanceToNextEntry());
- ASSERT_TRUE(reader.OpenCurrentEntryInZip());
- ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("evil_via_invalid_utf8.zip")));
+ base::FilePath target_path = base::FilePath::FromUTF8Unsafe(".�.\\evil.txt");
+ const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(target_path, entry->path);
+ EXPECT_FALSE(entry->is_unsafe);
+ EXPECT_FALSE(entry->is_directory);
+}
+
+// By default, file paths in ZIPs are interpreted as UTF-8. But in this test,
+// the ZIP archive contains file paths that are actually encoded in Shift JIS.
+// The SJIS-encoded paths are thus wrongly interpreted as UTF-8, resulting in
+// garbled paths. Invalid UTF-8 sequences are safely converted to the
+// replacement character �.
+TEST_F(ZipReaderTest, EncodingSjisAsUtf8) {
+ EXPECT_THAT(
+ GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip")),
+ ElementsAre(
+ base::FilePath::FromUTF8Unsafe("�V�����t�H���_/SJIS_835C_�\\.txt"),
+ base::FilePath::FromUTF8Unsafe(
+ "�V�����t�H���_/�V�����e�L�X�g �h�L�������g.txt")));
+}
+
+// In this test, SJIS-encoded paths are interpreted as Code Page 1252. This
+// results in garbled paths. Note the presence of C1 control codes U+0090 and
+// U+0081 in the garbled paths.
+TEST_F(ZipReaderTest, EncodingSjisAs1252) {
+ EXPECT_THAT(
+ GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "windows-1252"),
+ ElementsAre(base::FilePath::FromUTF8Unsafe(
+ "\u0090V‚µ‚¢ƒtƒHƒ‹ƒ_/SJIS_835C_ƒ\\.txt"),
+ base::FilePath::FromUTF8Unsafe(
+ "\u0090V‚µ‚¢ƒtƒHƒ‹ƒ_/\u0090V‚µ‚¢ƒeƒLƒXƒg "
+ "ƒhƒLƒ…ƒ\u0081ƒ“ƒg.txt")));
+}
+
+// In this test, SJIS-encoded paths are interpreted as Code Page 866. This
+// results in garbled paths.
+TEST_F(ZipReaderTest, EncodingSjisAsIbm866) {
+ EXPECT_THAT(
+ GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "IBM866"),
+ ElementsAre(
+ base::FilePath::FromUTF8Unsafe("РVВ╡ВвГtГHГЛГ_/SJIS_835C_Г\\.txt"),
+ base::FilePath::FromUTF8Unsafe(
+ "РVВ╡ВвГtГHГЛГ_/РVВ╡ВвГeГLГXГg ГhГLГЕГБГУГg.txt")));
+}
- // This file is unsafe because of invalid UTF-8 in the file name.
- EXPECT_TRUE(current_entry_info->is_unsafe());
- EXPECT_FALSE(current_entry_info->is_directory());
+// Tests that SJIS-encoded paths are correctly converted to Unicode.
+TEST_F(ZipReaderTest, EncodingSjis) {
+ EXPECT_THAT(
+ GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "Shift_JIS"),
+ ElementsAre(
+ base::FilePath::FromUTF8Unsafe("新しいフォルダ/SJIS_835C_ソ.txt"),
+ base::FilePath::FromUTF8Unsafe(
+ "新しいフォルダ/新しいテキスト ドキュメント.txt")));
}
-TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) {
+TEST_F(ZipReaderTest, AbsoluteFile) {
ZipReader reader;
- ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_));
+ ASSERT_TRUE(
+ reader.Open(data_dir_.AppendASCII("evil_via_absolute_file_name.zip")));
base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt"));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
- EXPECT_EQ(target_path, current_entry_info->file_path());
-
+ const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(target_path, entry->path);
// This file is unsafe because of the absolute file name.
- EXPECT_TRUE(current_entry_info->is_unsafe());
- EXPECT_FALSE(current_entry_info->is_directory());
+ EXPECT_TRUE(entry->is_unsafe);
+ EXPECT_FALSE(entry->is_directory);
}
-TEST_F(ZipReaderTest, current_entry_info_Directory) {
+TEST_F(ZipReaderTest, Directory) {
ZipReader reader;
ASSERT_TRUE(reader.Open(test_zip_file_));
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/"));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
-
- EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
- current_entry_info->file_path());
+ const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(target_path, entry->path);
// The directory size should be zero.
- EXPECT_EQ(0, current_entry_info->original_size());
+ EXPECT_EQ(0, entry->original_size);
// The expected time stamp: 2009-05-31 15:49:52
base::Time::Exploded exploded = {}; // Zero-clear.
- current_entry_info->last_modified().LocalExplode(&exploded);
+ entry->last_modified.UTCExplode(&exploded);
EXPECT_EQ(2009, exploded.year);
EXPECT_EQ(5, exploded.month);
EXPECT_EQ(31, exploded.day_of_month);
@@ -366,22 +410,91 @@ TEST_F(ZipReaderTest, current_entry_info_Directory) {
EXPECT_EQ(52, exploded.second);
EXPECT_EQ(0, exploded.millisecond);
- EXPECT_FALSE(current_entry_info->is_unsafe());
- EXPECT_TRUE(current_entry_info->is_directory());
+ EXPECT_FALSE(entry->is_unsafe);
+ EXPECT_TRUE(entry->is_directory);
}
-TEST_F(ZipReaderTest, current_entry_info_EncryptedFile) {
+TEST_F(ZipReaderTest, EncryptedFile_WrongPassword) {
ZipReader reader;
- base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
+ reader.SetPassword("wrong password");
- ASSERT_TRUE(reader.Open(encrypted_zip_file_));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- EXPECT_TRUE(reader.current_entry_info()->is_encrypted());
- reader.Close();
+ {
+ const ZipReader::Entry* entry = reader.Next();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(base::FilePath::FromASCII("ClearText.txt"), entry->path);
+ EXPECT_FALSE(entry->is_directory);
+ EXPECT_FALSE(entry->is_encrypted);
+ std::string contents = "dummy";
+ EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
+ EXPECT_EQ("This is not encrypted.\n", contents);
+ }
- ASSERT_TRUE(reader.Open(test_zip_file_));
- ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- EXPECT_FALSE(reader.current_entry_info()->is_encrypted());
+ for (const base::StringPiece path : {
+ "Encrypted AES-128.txt",
+ "Encrypted AES-192.txt",
+ "Encrypted AES-256.txt",
+ "Encrypted ZipCrypto.txt",
+ }) {
+ const ZipReader::Entry* entry = reader.Next();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(base::FilePath::FromASCII(path), entry->path);
+ EXPECT_FALSE(entry->is_directory);
+ EXPECT_TRUE(entry->is_encrypted);
+ std::string contents = "dummy";
+ EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
+ }
+
+ EXPECT_FALSE(reader.Next());
+ EXPECT_TRUE(reader.ok());
+}
+
+TEST_F(ZipReaderTest, EncryptedFile_RightPassword) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
+ reader.SetPassword("password");
+
+ {
+ const ZipReader::Entry* entry = reader.Next();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(base::FilePath::FromASCII("ClearText.txt"), entry->path);
+ EXPECT_FALSE(entry->is_directory);
+ EXPECT_FALSE(entry->is_encrypted);
+ std::string contents = "dummy";
+ EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
+ EXPECT_EQ("This is not encrypted.\n", contents);
+ }
+
+ // TODO(crbug.com/1296838) Support AES encryption.
+ for (const base::StringPiece path : {
+ "Encrypted AES-128.txt",
+ "Encrypted AES-192.txt",
+ "Encrypted AES-256.txt",
+ }) {
+ const ZipReader::Entry* entry = reader.Next();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(base::FilePath::FromASCII(path), entry->path);
+ EXPECT_FALSE(entry->is_directory);
+ EXPECT_TRUE(entry->is_encrypted);
+ std::string contents = "dummy";
+ EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
+ EXPECT_EQ("", contents);
+ }
+
+ {
+ const ZipReader::Entry* entry = reader.Next();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(base::FilePath::FromASCII("Encrypted ZipCrypto.txt"),
+ entry->path);
+ EXPECT_FALSE(entry->is_directory);
+ EXPECT_TRUE(entry->is_encrypted);
+ std::string contents = "dummy";
+ EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
+ EXPECT_EQ("This is encrypted with ZipCrypto.\n", contents);
+ }
+
+ EXPECT_FALSE(reader.Next());
+ EXPECT_TRUE(reader.ok());
}
// Verifies that the ZipReader class can extract a file from a zip archive
@@ -404,7 +517,7 @@ TEST_F(ZipReaderTest, OpenFromString) {
"\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00"
"\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00"
"\x52\x00\x00\x00\x00\x00";
- std::string data(kTestData, base::size(kTestData));
+ std::string data(kTestData, std::size(kTestData));
ZipReader reader;
ASSERT_TRUE(reader.OpenFromString(data));
base::FilePath target_path(FILE_PATH_LITERAL("test.txt"));
@@ -413,8 +526,8 @@ TEST_F(ZipReaderTest, OpenFromString) {
test_dir_.AppendASCII("test.txt")));
std::string actual;
- ASSERT_TRUE(base::ReadFileToString(
- test_dir_.AppendASCII("test.txt"), &actual));
+ ASSERT_TRUE(
+ base::ReadFileToString(test_dir_.AppendASCII("test.txt"), &actual));
EXPECT_EQ(std::string("This is a test.\n"), actual);
}
@@ -445,8 +558,8 @@ TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
EXPECT_LE(1, listener.progress_calls());
std::string output;
- ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
- &output));
+ ASSERT_TRUE(
+ base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), &output));
const std::string md5 = base::MD5String(output);
EXPECT_EQ(kQuuxExpectedMD5, md5);
@@ -456,6 +569,103 @@ TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
EXPECT_EQ(file_size, listener.current_progress());
}
+TEST_F(ZipReaderTest, ExtractToFileAsync_Encrypted_NoPassword) {
+ MockUnzipListener listener;
+
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
+ ASSERT_TRUE(LocateAndOpenEntry(
+ &reader, base::FilePath::FromASCII("Encrypted ZipCrypto.txt")));
+ const base::FilePath target_path = test_dir_.AppendASCII("extracted");
+ reader.ExtractCurrentEntryToFilePathAsync(
+ target_path,
+ base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
+ base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
+ base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
+ listener.AsWeakPtr()));
+
+ EXPECT_EQ(0, listener.success_calls());
+ EXPECT_EQ(0, listener.failure_calls());
+ EXPECT_EQ(0, listener.progress_calls());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, listener.success_calls());
+ EXPECT_EQ(1, listener.failure_calls());
+ EXPECT_LE(1, listener.progress_calls());
+
+ // The extracted file contains rubbish data.
+ // We probably shouldn't even look at it.
+ std::string contents;
+ ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
+ EXPECT_NE("", contents);
+ EXPECT_EQ(contents.size(), listener.current_progress());
+}
+
+TEST_F(ZipReaderTest, ExtractToFileAsync_Encrypted_RightPassword) {
+ MockUnzipListener listener;
+
+ ZipReader reader;
+ reader.SetPassword("password");
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
+ ASSERT_TRUE(LocateAndOpenEntry(
+ &reader, base::FilePath::FromASCII("Encrypted ZipCrypto.txt")));
+ const base::FilePath target_path = test_dir_.AppendASCII("extracted");
+ reader.ExtractCurrentEntryToFilePathAsync(
+ target_path,
+ base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
+ base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
+ base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
+ listener.AsWeakPtr()));
+
+ EXPECT_EQ(0, listener.success_calls());
+ EXPECT_EQ(0, listener.failure_calls());
+ EXPECT_EQ(0, listener.progress_calls());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, listener.success_calls());
+ EXPECT_EQ(0, listener.failure_calls());
+ EXPECT_LE(1, listener.progress_calls());
+
+ std::string contents;
+ ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
+ EXPECT_EQ("This is encrypted with ZipCrypto.\n", contents);
+ EXPECT_EQ(contents.size(), listener.current_progress());
+}
+
+TEST_F(ZipReaderTest, ExtractToFileAsync_WrongCrc) {
+ MockUnzipListener listener;
+
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Wrong CRC.zip")));
+ ASSERT_TRUE(
+ LocateAndOpenEntry(&reader, base::FilePath::FromASCII("Corrupted.txt")));
+ const base::FilePath target_path = test_dir_.AppendASCII("extracted");
+ reader.ExtractCurrentEntryToFilePathAsync(
+ target_path,
+ base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
+ base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
+ base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
+ listener.AsWeakPtr()));
+
+ EXPECT_EQ(0, listener.success_calls());
+ EXPECT_EQ(0, listener.failure_calls());
+ EXPECT_EQ(0, listener.progress_calls());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, listener.success_calls());
+ EXPECT_EQ(1, listener.failure_calls());
+ EXPECT_LE(1, listener.progress_calls());
+
+ std::string contents;
+ ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
+ EXPECT_EQ("This file has been changed after its CRC was computed.\n",
+ contents);
+ EXPECT_EQ(contents.size(), listener.current_progress());
+}
+
// Verifies that the asynchronous extraction to a file works.
TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) {
MockUnzipListener listener;
@@ -490,7 +700,7 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
// sizes from 0 to 7 bytes respectively, being the contents of each file a
// substring of "0123456" starting at '0'.
base::FilePath test_zip_file =
- test_data_dir_.AppendASCII("test_mismatch_size.zip");
+ data_dir_.AppendASCII("test_mismatch_size.zip");
ZipReader reader;
std::string contents;
@@ -515,7 +725,7 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
}
// More than necessary byte read limit: must pass.
- EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents));
+ EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents);
}
reader.Close();
@@ -526,7 +736,7 @@ TEST_F(ZipReaderTest, ExtractPartOfCurrentEntry) {
// sizes from 0 to 7 bytes respectively, being the contents of each file a
// substring of "0123456" starting at '0'.
base::FilePath test_zip_file =
- test_data_dir_.AppendASCII("test_mismatch_size.zip");
+ data_dir_.AppendASCII("test_mismatch_size.zip");
ZipReader reader;
std::string contents;
@@ -564,6 +774,37 @@ TEST_F(ZipReaderTest, ExtractPartOfCurrentEntry) {
reader.Close();
}
+TEST_F(ZipReaderTest, ExtractPosixPermissions) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("test_posix_permissions.zip")));
+ for (auto entry : {"0.txt", "1.txt", "2.txt", "3.txt"}) {
+ ASSERT_TRUE(LocateAndOpenEntry(&reader, base::FilePath::FromASCII(entry)));
+ FilePathWriterDelegate delegate(temp_dir.GetPath().AppendASCII(entry));
+ ASSERT_TRUE(reader.ExtractCurrentEntry(&delegate));
+ }
+ reader.Close();
+
+#if defined(OS_POSIX)
+ // This assumes a umask of at least 0400.
+ int mode = 0;
+ EXPECT_TRUE(base::GetPosixFilePermissions(
+ temp_dir.GetPath().AppendASCII("0.txt"), &mode));
+ EXPECT_EQ(mode & 0700, 0700);
+ EXPECT_TRUE(base::GetPosixFilePermissions(
+ temp_dir.GetPath().AppendASCII("1.txt"), &mode));
+ EXPECT_EQ(mode & 0700, 0600);
+ EXPECT_TRUE(base::GetPosixFilePermissions(
+ temp_dir.GetPath().AppendASCII("2.txt"), &mode));
+ EXPECT_EQ(mode & 0700, 0700);
+ EXPECT_TRUE(base::GetPosixFilePermissions(
+ temp_dir.GetPath().AppendASCII("3.txt"), &mode));
+ EXPECT_EQ(mode & 0700, 0600);
+#endif
+}
+
// This test exposes http://crbug.com/430959, at least on OS X
TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
for (int i = 0; i < 100000; ++i) {
@@ -578,45 +819,40 @@ TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
TEST_F(ZipReaderTest, ExtractCurrentEntryPrepareFailure) {
testing::StrictMock<MockWriterDelegate> mock_writer;
- EXPECT_CALL(mock_writer, PrepareOutput())
- .WillOnce(Return(false));
+ EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(false));
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
ZipReader reader;
ASSERT_TRUE(reader.Open(test_zip_file_));
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ASSERT_FALSE(reader.ExtractCurrentEntry(
- &mock_writer, std::numeric_limits<uint64_t>::max()));
+ ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
}
-// Test that when WriterDelegate::WriteBytes returns false, no other methods on
-// the delegate are called and the extraction fails.
+// Test that when WriterDelegate::WriteBytes returns false, only the OnError
+// method on the delegate is called and the extraction fails.
TEST_F(ZipReaderTest, ExtractCurrentEntryWriteBytesFailure) {
testing::StrictMock<MockWriterDelegate> mock_writer;
- EXPECT_CALL(mock_writer, PrepareOutput())
- .WillOnce(Return(true));
- EXPECT_CALL(mock_writer, WriteBytes(_, _))
- .WillOnce(Return(false));
+ EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(true));
+ EXPECT_CALL(mock_writer, WriteBytes(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(mock_writer, OnError());
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
ZipReader reader;
ASSERT_TRUE(reader.Open(test_zip_file_));
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ASSERT_FALSE(reader.ExtractCurrentEntry(
- &mock_writer, std::numeric_limits<uint64_t>::max()));
+ ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
}
// Test that extraction succeeds when the writer delegate reports all is well.
TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
testing::StrictMock<MockWriterDelegate> mock_writer;
- EXPECT_CALL(mock_writer, PrepareOutput())
- .WillOnce(Return(true));
- EXPECT_CALL(mock_writer, WriteBytes(_, _))
- .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(true));
+ EXPECT_CALL(mock_writer, WriteBytes(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_writer, SetPosixFilePermissions(_));
EXPECT_CALL(mock_writer, SetTimeModified(_));
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
@@ -624,50 +860,84 @@ TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
ASSERT_TRUE(reader.Open(test_zip_file_));
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
- ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer,
- std::numeric_limits<uint64_t>::max()));
+ ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer));
+}
+
+TEST_F(ZipReaderTest, WrongCrc) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Wrong CRC.zip")));
+
+ const ZipReader::Entry* const entry =
+ LocateAndOpenEntry(&reader, base::FilePath::FromASCII("Corrupted.txt"));
+ ASSERT_TRUE(entry);
+
+ std::string contents = "dummy";
+ EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
+ EXPECT_EQ("This file has been changed after its CRC was computed.\n",
+ contents);
+
+ contents = "dummy";
+ EXPECT_FALSE(
+ reader.ExtractCurrentEntryToString(entry->original_size + 1, &contents));
+ EXPECT_EQ("This file has been changed after its CRC was computed.\n",
+ contents);
+
+ contents = "dummy";
+ EXPECT_FALSE(
+ reader.ExtractCurrentEntryToString(entry->original_size, &contents));
+ EXPECT_EQ("This file has been changed after its CRC was computed.\n",
+ contents);
+
+ contents = "dummy";
+ EXPECT_FALSE(
+ reader.ExtractCurrentEntryToString(entry->original_size - 1, &contents));
+ EXPECT_EQ("This file has been changed after its CRC was computed.", contents);
}
class FileWriterDelegateTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
- file_.Initialize(temp_file_path_, (base::File::FLAG_CREATE_ALWAYS |
- base::File::FLAG_READ |
- base::File::FLAG_WRITE |
- base::File::FLAG_TEMPORARY |
- base::File::FLAG_DELETE_ON_CLOSE));
+ file_.Initialize(temp_file_path_,
+ (base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ |
+ base::File::FLAG_WRITE | base::File::FLAG_WIN_TEMPORARY |
+ base::File::FLAG_DELETE_ON_CLOSE));
ASSERT_TRUE(file_.IsValid());
}
- // Writes data to the file, leaving the current position at the end of the
- // write.
- void PopulateFile() {
- static const char kSomeData[] = "this sure is some data.";
- static const size_t kSomeDataLen = sizeof(kSomeData) - 1;
- ASSERT_NE(-1LL, file_.Write(0LL, kSomeData, kSomeDataLen));
- }
-
base::FilePath temp_file_path_;
base::File file_;
};
-TEST_F(FileWriterDelegateTest, WriteToStartAndTruncate) {
- // Write stuff and advance.
- PopulateFile();
+TEST_F(FileWriterDelegateTest, WriteToEnd) {
+ const std::string payload = "This is the actualy payload data.\n";
- // This should rewind, write, then truncate.
- static const char kSomeData[] = "short";
- static const int kSomeDataLen = sizeof(kSomeData) - 1;
{
FileWriterDelegate writer(&file_);
+ EXPECT_EQ(0, writer.file_length());
ASSERT_TRUE(writer.PrepareOutput());
- ASSERT_TRUE(writer.WriteBytes(kSomeData, kSomeDataLen));
+ ASSERT_TRUE(writer.WriteBytes(payload.data(), payload.size()));
+ EXPECT_EQ(payload.size(), writer.file_length());
}
- ASSERT_EQ(kSomeDataLen, file_.GetLength());
- char buf[kSomeDataLen] = {};
- ASSERT_EQ(kSomeDataLen, file_.Read(0LL, buf, kSomeDataLen));
- ASSERT_EQ(std::string(kSomeData), std::string(buf, kSomeDataLen));
+
+ EXPECT_EQ(payload.size(), file_.GetLength());
+}
+
+TEST_F(FileWriterDelegateTest, EmptyOnError) {
+ const std::string payload = "This is the actualy payload data.\n";
+
+ {
+ FileWriterDelegate writer(&file_);
+ EXPECT_EQ(0, writer.file_length());
+ ASSERT_TRUE(writer.PrepareOutput());
+ ASSERT_TRUE(writer.WriteBytes(payload.data(), payload.size()));
+ EXPECT_EQ(payload.size(), writer.file_length());
+ EXPECT_EQ(payload.size(), file_.GetLength());
+ writer.OnError();
+ EXPECT_EQ(0, writer.file_length());
+ }
+
+ EXPECT_EQ(0, file_.GetLength());
}
} // namespace zip