blob: 96c4aa578c6ab32c4e73e67817a79eb7ce541461 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h"
#include <limits>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/contrib/minizip/unzip.h"
namespace chrome_cleaner {
namespace {
const char kTestContent[] = "Hello World";
const base::Time::Exploded kTestFileTime = {
// Year
2018,
// Month
1,
// Day of week
1,
// Day of month
1,
// Hour
2,
// Minute
3,
// Second
5,
// Millisecond
0,
};
// The zip should be encrypted and use UTF-8 encoding.
const uint16_t kExpectedZipFlag = 0x1 | (0x1 << 11);
const int64_t kReadBufferSize = 4096;
// The |day_of_week| in |base::Time::Exploded| won't be set correctly.
// TODO(veranika): This is copied from
// https://cs.chromium.org/chromium/src/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc.
// It would be better to move it to //base.
base::Time::Exploded ExplodeDosTime(const uint32_t dos_time) {
base::Time::Exploded time_part;
uint32_t remain_part = dos_time;
// 0-4bits, second divied by 2.
time_part.second = (remain_part & 0x1F) * 2;
remain_part >>= 5;
// 5-10bits, minute (0–59).
time_part.minute = remain_part & 0x3F;
remain_part >>= 6;
// 11-15bits, hour (0–23 on a 24-hour clock).
time_part.hour = remain_part & 0x1F;
remain_part >>= 5;
// 16-20bits, day of the month (1-31).
time_part.day_of_month = remain_part & 0x1F;
remain_part >>= 5;
// 21-24bits, month (1-23).
time_part.month = remain_part & 0xF;
remain_part >>= 4;
// 25-31bits, year offset from 1980.
time_part.year = (remain_part & 0x7F) + 1980;
return time_part;
}
} // namespace
ZipArchiverTestFile::ZipArchiverTestFile() : initialized_(false) {}
ZipArchiverTestFile::~ZipArchiverTestFile() = default;
void ZipArchiverTestFile::Initialize() {
// Can not be reinitialized.
CHECK(!initialized_);
initialized_ = true;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(
base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &src_file_path_));
ASSERT_EQ(static_cast<size_t>(base::WriteFile(src_file_path_, kTestContent,
strlen(kTestContent))),
strlen(kTestContent));
// Set a fixed timestamp, so the modified time will be identical in every
// test.
base::Time file_time;
ASSERT_TRUE(base::Time::FromLocalExploded(kTestFileTime, &file_time));
ASSERT_TRUE(base::TouchFile(src_file_path_, file_time, file_time));
}
const base::FilePath& ZipArchiverTestFile::GetSourceFilePath() const {
return src_file_path_;
}
const base::FilePath& ZipArchiverTestFile::GetTempDirPath() const {
return temp_dir_.GetPath();
}
void ZipArchiverTestFile::ExpectValidZipFile(
const base::FilePath& zip_file_path,
const std::string& filename_in_zip,
const std::string& password) {
unzFile unzip_object = unzOpen64(zip_file_path.AsUTF8Unsafe().c_str());
ASSERT_NE(unzip_object, nullptr);
EXPECT_EQ(unzLocateFile(unzip_object, filename_in_zip.c_str(),
/*iCaseSensitivity=*/1),
UNZ_OK);
unz_file_info64 file_info;
const size_t filename_length = strlen(filename_in_zip.c_str());
std::vector<char> filename(filename_length + 1);
ASSERT_GT(std::numeric_limits<Cr_z_uLong>::max(), filename.size());
EXPECT_EQ(unzGetCurrentFileInfo64(
unzip_object, &file_info, filename.data(),
static_cast<Cr_z_uLong>(filename.size()),
/*extraField=*/nullptr, /*extraFieldBufferSize=*/0,
/*szComment=*/nullptr, /*commentBufferSize=*/0),
UNZ_OK);
EXPECT_EQ(file_info.flag & kExpectedZipFlag, kExpectedZipFlag);
// The compression method should be STORE(0).
EXPECT_EQ(file_info.compression_method, 0UL);
EXPECT_EQ(file_info.uncompressed_size, strlen(kTestContent));
EXPECT_EQ(file_info.size_filename, filename_in_zip.size());
EXPECT_STREQ(filename.data(), filename_in_zip.c_str());
base::Time::Exploded file_time = ExplodeDosTime(file_info.dosDate);
EXPECT_EQ(file_time.year, kTestFileTime.year);
EXPECT_EQ(file_time.month, kTestFileTime.month);
EXPECT_EQ(file_time.day_of_month, kTestFileTime.day_of_month);
EXPECT_EQ(file_time.hour, kTestFileTime.hour);
EXPECT_EQ(file_time.minute, kTestFileTime.minute);
// Dos time has a resolution of 2 seconds.
EXPECT_EQ(file_time.second, (kTestFileTime.second / 2) * 2);
EXPECT_EQ(unzOpenCurrentFilePassword(unzip_object, password.c_str()), UNZ_OK);
const size_t content_length = strlen(kTestContent);
std::vector<char> content;
uint8_t read_buffer[kReadBufferSize];
while (true) {
int read_size =
unzReadCurrentFile(unzip_object, read_buffer, kReadBufferSize);
EXPECT_GE(read_size, 0);
if (read_size == 0) {
break;
}
content.insert(content.end(), read_buffer, read_buffer + read_size);
if (content.size() > content_length) {
break;
}
}
EXPECT_EQ(content.size(), content_length);
EXPECT_EQ(std::string(content.begin(), content.end()), kTestContent);
EXPECT_EQ(unzCloseCurrentFile(unzip_object), UNZ_OK);
ASSERT_EQ(unzClose(unzip_object), UNZ_OK);
}
} // namespace chrome_cleaner