1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/files/file.h"
15 #include "base/files/file_enumerator.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_temp_dir.h"
19 #include "base/logging.h"
20 #include "base/macros.h"
21 #include "base/path_service.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "build/build_config.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/platform_test.h"
27 #include "third_party/zlib/google/zip.h"
28 #include "third_party/zlib/google/zip_reader.h"
29
30 namespace {
31
CreateFile(const std::string & content,base::FilePath * file_path,base::File * file)32 bool CreateFile(const std::string& content,
33 base::FilePath* file_path,
34 base::File* file) {
35 if (!base::CreateTemporaryFile(file_path))
36 return false;
37
38 if (base::WriteFile(*file_path, content.data(), content.size()) == -1)
39 return false;
40
41 *file = base::File(
42 *file_path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
43 return file->IsValid();
44 }
45
46 // A virtual file system containing:
47 // /test
48 // /test/foo.txt
49 // /test/bar/bar1.txt
50 // /test/bar/bar2.txt
51 // Used to test providing a custom zip::FileAccessor when unzipping.
52 class VirtualFileSystem : public zip::FileAccessor {
53 public:
54 static constexpr char kFooContent[] = "This is foo.";
55 static constexpr char kBar1Content[] = "This is bar.";
56 static constexpr char kBar2Content[] = "This is bar too.";
57
VirtualFileSystem()58 VirtualFileSystem() {
59 base::FilePath test_dir(FILE_PATH_LITERAL("/test"));
60 base::FilePath foo_txt_path = test_dir.Append(FILE_PATH_LITERAL("foo.txt"));
61
62 base::FilePath file_path;
63 base::File file;
64 bool success = CreateFile(kFooContent, &file_path, &file);
65 DCHECK(success);
66 files_[foo_txt_path] = std::move(file);
67
68 base::FilePath bar_dir = test_dir.Append(FILE_PATH_LITERAL("bar"));
69 base::FilePath bar1_txt_path =
70 bar_dir.Append(FILE_PATH_LITERAL("bar1.txt"));
71 success = CreateFile(kBar1Content, &file_path, &file);
72 DCHECK(success);
73 files_[bar1_txt_path] = std::move(file);
74
75 base::FilePath bar2_txt_path =
76 bar_dir.Append(FILE_PATH_LITERAL("bar2.txt"));
77 success = CreateFile(kBar2Content, &file_path, &file);
78 DCHECK(success);
79 files_[bar2_txt_path] = std::move(file);
80
81 file_tree_[test_dir] = std::vector<DirectoryContentEntry>{
82 DirectoryContentEntry(foo_txt_path, /*is_dir=*/false),
83 DirectoryContentEntry(bar_dir, /*is_dir=*/true)};
84 file_tree_[bar_dir] = std::vector<DirectoryContentEntry>{
85 DirectoryContentEntry(bar1_txt_path, /*is_dir=*/false),
86 DirectoryContentEntry(bar2_txt_path, /*is_dir=*/false)};
87 }
88 ~VirtualFileSystem() override = default;
89
90 private:
OpenFilesForReading(const std::vector<base::FilePath> & paths)91 std::vector<base::File> OpenFilesForReading(
92 const std::vector<base::FilePath>& paths) override {
93 std::vector<base::File> files;
94 for (const auto& path : paths) {
95 auto iter = files_.find(path);
96 files.push_back(iter == files_.end() ? base::File()
97 : std::move(iter->second));
98 }
99 return files;
100 }
101
DirectoryExists(const base::FilePath & file)102 bool DirectoryExists(const base::FilePath& file) override {
103 return file_tree_.count(file) == 1 && files_.count(file) == 0;
104 }
105
ListDirectoryContent(const base::FilePath & dir)106 std::vector<DirectoryContentEntry> ListDirectoryContent(
107 const base::FilePath& dir) override {
108 auto iter = file_tree_.find(dir);
109 if (iter == file_tree_.end()) {
110 NOTREACHED();
111 return std::vector<DirectoryContentEntry>();
112 }
113 return iter->second;
114 }
115
GetLastModifiedTime(const base::FilePath & path)116 base::Time GetLastModifiedTime(const base::FilePath& path) override {
117 return base::Time::FromDoubleT(172097977); // Some random date.
118 }
119
120 std::map<base::FilePath, std::vector<DirectoryContentEntry>> file_tree_;
121 std::map<base::FilePath, base::File> files_;
122
123 DISALLOW_COPY_AND_ASSIGN(VirtualFileSystem);
124 };
125
126 // static
127 constexpr char VirtualFileSystem::kFooContent[];
128 constexpr char VirtualFileSystem::kBar1Content[];
129 constexpr char VirtualFileSystem::kBar2Content[];
130
131 // Make the test a PlatformTest to setup autorelease pools properly on Mac.
132 class ZipTest : public PlatformTest {
133 protected:
134 enum ValidYearType {
135 VALID_YEAR,
136 INVALID_YEAR
137 };
138
SetUp()139 virtual void SetUp() {
140 PlatformTest::SetUp();
141
142 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
143 test_dir_ = temp_dir_.GetPath();
144
145 base::FilePath zip_path(test_dir_);
146 zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("foo.txt")));
147 zip_path = zip_path.Append(FILE_PATH_LITERAL("foo"));
148 zip_contents_.insert(zip_path);
149 zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("bar.txt")));
150 zip_path = zip_path.Append(FILE_PATH_LITERAL("bar"));
151 zip_contents_.insert(zip_path);
152 zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("baz.txt")));
153 zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("quux.txt")));
154 zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL(".hidden")));
155
156 // Include a subset of files in |zip_file_list_| to test ZipFiles().
157 zip_file_list_.push_back(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
158 zip_file_list_.push_back(
159 base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
160 zip_file_list_.push_back(
161 base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
162 }
163
TearDown()164 virtual void TearDown() {
165 PlatformTest::TearDown();
166 }
167
GetTestDataDirectory(base::FilePath * path)168 bool GetTestDataDirectory(base::FilePath* path) {
169 bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, path);
170 EXPECT_TRUE(success);
171 if (!success)
172 return false;
173 *path = path->AppendASCII("third_party");
174 *path = path->AppendASCII("zlib");
175 *path = path->AppendASCII("google");
176 *path = path->AppendASCII("test");
177 *path = path->AppendASCII("data");
178 return true;
179 }
180
TestUnzipFile(const base::FilePath::StringType & filename,bool expect_hidden_files)181 void TestUnzipFile(const base::FilePath::StringType& filename,
182 bool expect_hidden_files) {
183 base::FilePath test_dir;
184 ASSERT_TRUE(GetTestDataDirectory(&test_dir));
185 TestUnzipFile(test_dir.Append(filename), expect_hidden_files);
186 }
187
TestUnzipFile(const base::FilePath & path,bool expect_hidden_files)188 void TestUnzipFile(const base::FilePath& path, bool expect_hidden_files) {
189 ASSERT_TRUE(base::PathExists(path)) << "no file " << path.value();
190 ASSERT_TRUE(zip::Unzip(path, test_dir_));
191
192 base::FilePath original_dir;
193 ASSERT_TRUE(GetTestDataDirectory(&original_dir));
194 original_dir = original_dir.AppendASCII("test");
195
196 base::FileEnumerator files(test_dir_, true,
197 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
198 base::FilePath unzipped_entry_path = files.Next();
199 size_t count = 0;
200 while (!unzipped_entry_path.value().empty()) {
201 EXPECT_EQ(zip_contents_.count(unzipped_entry_path), 1U)
202 << "Couldn't find " << unzipped_entry_path.value();
203 count++;
204
205 if (base::PathExists(unzipped_entry_path) &&
206 !base::DirectoryExists(unzipped_entry_path)) {
207 // It's a file, check its contents are what we zipped.
208 // TODO(774156): figure out why the commented out EXPECT_TRUE below
209 // fails on the build bots (but not on the try-bots).
210 base::FilePath relative_path;
211 bool append_relative_path_success =
212 test_dir_.AppendRelativePath(unzipped_entry_path, &relative_path);
213 if (!append_relative_path_success) {
214 LOG(ERROR) << "Append relative path failed, params: "
215 << test_dir_.value() << " and "
216 << unzipped_entry_path.value();
217 }
218 base::FilePath original_path = original_dir.Append(relative_path);
219 LOG(ERROR) << "Comparing original " << original_path.value()
220 << " and unzipped file " << unzipped_entry_path.value()
221 << " result: "
222 << base::ContentsEqual(original_path, unzipped_entry_path);
223 // EXPECT_TRUE(base::ContentsEqual(original_path, unzipped_entry_path))
224 // << "Contents differ between original " << original_path.value()
225 // << " and unzipped file " << unzipped_entry_path.value();
226 }
227 unzipped_entry_path = files.Next();
228 }
229
230 size_t expected_count = 0;
231 for (std::set<base::FilePath>::iterator iter = zip_contents_.begin();
232 iter != zip_contents_.end(); ++iter) {
233 if (expect_hidden_files || iter->BaseName().value()[0] != '.')
234 ++expected_count;
235 }
236
237 EXPECT_EQ(expected_count, count);
238 }
239
240 // This function does the following:
241 // 1) Creates a test.txt file with the given last modification timestamp
242 // 2) Zips test.txt and extracts it back into a different location.
243 // 3) Confirms that test.txt in the output directory has the specified
244 // last modification timestamp if it is valid (|valid_year| is true).
245 // If the timestamp is not supported by the zip format, the last
246 // modification defaults to the current time.
TestTimeStamp(const char * date_time,ValidYearType valid_year)247 void TestTimeStamp(const char* date_time, ValidYearType valid_year) {
248 SCOPED_TRACE(std::string("TestTimeStamp(") + date_time + ")");
249 base::ScopedTempDir temp_dir;
250 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
251
252 base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip");
253 base::FilePath src_dir = temp_dir.GetPath().AppendASCII("input");
254 base::FilePath out_dir = temp_dir.GetPath().AppendASCII("output");
255
256 base::FilePath src_file = src_dir.AppendASCII("test.txt");
257 base::FilePath out_file = out_dir.AppendASCII("test.txt");
258
259 EXPECT_TRUE(base::CreateDirectory(src_dir));
260 EXPECT_TRUE(base::CreateDirectory(out_dir));
261
262 base::Time test_mtime;
263 ASSERT_TRUE(base::Time::FromString(date_time, &test_mtime));
264
265 // Adjusting the current timestamp to the resolution that the zip file
266 // supports, which is 2 seconds. Note that between this call to Time::Now()
267 // and zip::Zip() the clock can advance a bit, hence the use of EXPECT_GE.
268 base::Time::Exploded now_parts;
269 base::Time::Now().LocalExplode(&now_parts);
270 now_parts.second = now_parts.second & ~1;
271 now_parts.millisecond = 0;
272 base::Time now_time;
273 EXPECT_TRUE(base::Time::FromLocalExploded(now_parts, &now_time));
274
275 EXPECT_EQ(1, base::WriteFile(src_file, "1", 1));
276 EXPECT_TRUE(base::TouchFile(src_file, base::Time::Now(), test_mtime));
277
278 EXPECT_TRUE(zip::Zip(src_dir, zip_file, true));
279 ASSERT_TRUE(zip::Unzip(zip_file, out_dir));
280
281 base::File::Info file_info;
282 EXPECT_TRUE(base::GetFileInfo(out_file, &file_info));
283 EXPECT_EQ(file_info.size, 1);
284
285 if (valid_year == VALID_YEAR) {
286 EXPECT_EQ(file_info.last_modified, test_mtime);
287 } else {
288 // Invalid date means the modification time will default to 'now'.
289 EXPECT_GE(file_info.last_modified, now_time);
290 }
291 }
292
293 // The path to temporary directory used to contain the test operations.
294 base::FilePath test_dir_;
295
296 base::ScopedTempDir temp_dir_;
297
298 // Hard-coded contents of a known zip file.
299 std::set<base::FilePath> zip_contents_;
300
301 // Hard-coded list of relative paths for a zip file created with ZipFiles.
302 std::vector<base::FilePath> zip_file_list_;
303 };
304
TEST_F(ZipTest,Unzip)305 TEST_F(ZipTest, Unzip) {
306 TestUnzipFile(FILE_PATH_LITERAL("test.zip"), true);
307 }
308
TEST_F(ZipTest,UnzipUncompressed)309 TEST_F(ZipTest, UnzipUncompressed) {
310 TestUnzipFile(FILE_PATH_LITERAL("test_nocompress.zip"), true);
311 }
312
TEST_F(ZipTest,UnzipEvil)313 TEST_F(ZipTest, UnzipEvil) {
314 base::FilePath path;
315 ASSERT_TRUE(GetTestDataDirectory(&path));
316 path = path.AppendASCII("evil.zip");
317 // Unzip the zip file into a sub directory of test_dir_ so evil.zip
318 // won't create a persistent file outside test_dir_ in case of a
319 // failure.
320 base::FilePath output_dir = test_dir_.AppendASCII("out");
321 ASSERT_FALSE(zip::Unzip(path, output_dir));
322 base::FilePath evil_file = output_dir;
323 evil_file = evil_file.AppendASCII(
324 "../levilevilevilevilevilevilevilevilevilevilevilevil");
325 ASSERT_FALSE(base::PathExists(evil_file));
326 }
327
TEST_F(ZipTest,UnzipEvil2)328 TEST_F(ZipTest, UnzipEvil2) {
329 base::FilePath path;
330 ASSERT_TRUE(GetTestDataDirectory(&path));
331 // The zip file contains an evil file with invalid UTF-8 in its file
332 // name.
333 path = path.AppendASCII("evil_via_invalid_utf8.zip");
334 // See the comment at UnzipEvil() for why we do this.
335 base::FilePath output_dir = test_dir_.AppendASCII("out");
336 // This should fail as it contains an evil file.
337 ASSERT_FALSE(zip::Unzip(path, output_dir));
338 base::FilePath evil_file = output_dir;
339 evil_file = evil_file.AppendASCII("../evil.txt");
340 ASSERT_FALSE(base::PathExists(evil_file));
341 }
342
TEST_F(ZipTest,UnzipWithFilter)343 TEST_F(ZipTest, UnzipWithFilter) {
344 auto filter = base::BindRepeating([](const base::FilePath& path) {
345 return path.BaseName().MaybeAsASCII() == "foo.txt";
346 });
347 base::FilePath path;
348 ASSERT_TRUE(GetTestDataDirectory(&path));
349 ASSERT_TRUE(zip::UnzipWithFilterCallback(path.AppendASCII("test.zip"),
350 test_dir_, filter, false));
351 // Only foo.txt should have been extracted. The following paths should not
352 // be extracted:
353 // foo/
354 // foo/bar.txt
355 // foo/bar/
356 // foo/bar/.hidden
357 // foo/bar/baz.txt
358 // foo/bar/quux.txt
359 ASSERT_TRUE(base::PathExists(test_dir_.AppendASCII("foo.txt")));
360 base::FileEnumerator extractedFiles(
361 test_dir_,
362 false, // Do not enumerate recursively - the file must be in the root.
363 base::FileEnumerator::FileType::FILES);
364 int extracted_count = 0;
365 while (!extractedFiles.Next().empty())
366 ++extracted_count;
367 ASSERT_EQ(1, extracted_count);
368
369 base::FileEnumerator extractedDirs(
370 test_dir_,
371 false, // Do not enumerate recursively - we require zero directories.
372 base::FileEnumerator::FileType::DIRECTORIES);
373 extracted_count = 0;
374 while (!extractedDirs.Next().empty())
375 ++extracted_count;
376 ASSERT_EQ(0, extracted_count);
377 }
378
TEST_F(ZipTest,UnzipWithDelegates)379 TEST_F(ZipTest, UnzipWithDelegates) {
380 auto filter =
381 base::BindRepeating([](const base::FilePath& path) { return true; });
382 auto dir_creator = base::BindRepeating(
383 [](const base::FilePath& extract_dir, const base::FilePath& entry_path) {
384 return base::CreateDirectory(extract_dir.Append(entry_path));
385 },
386 test_dir_);
387 auto writer = base::BindRepeating(
388 [](const base::FilePath& extract_dir, const base::FilePath& entry_path)
389 -> std::unique_ptr<zip::WriterDelegate> {
390 return std::make_unique<zip::FilePathWriterDelegate>(
391 extract_dir.Append(entry_path));
392 },
393 test_dir_);
394 base::FilePath path;
395 ASSERT_TRUE(GetTestDataDirectory(&path));
396 base::File file(path.AppendASCII("test.zip"),
397 base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
398 ASSERT_TRUE(zip::UnzipWithFilterAndWriters(file.GetPlatformFile(), writer,
399 dir_creator, filter, false));
400 base::FilePath dir = test_dir_;
401 base::FilePath dir_foo = dir.AppendASCII("foo");
402 base::FilePath dir_foo_bar = dir_foo.AppendASCII("bar");
403 ASSERT_TRUE(base::PathExists(dir.AppendASCII("foo.txt")));
404 ASSERT_TRUE(base::PathExists(dir_foo));
405 ASSERT_TRUE(base::PathExists(dir_foo.AppendASCII("bar.txt")));
406 ASSERT_TRUE(base::PathExists(dir_foo_bar));
407 ASSERT_TRUE(base::PathExists(dir_foo_bar.AppendASCII(".hidden")));
408 ASSERT_TRUE(base::PathExists(dir_foo_bar.AppendASCII("baz.txt")));
409 ASSERT_TRUE(base::PathExists(dir_foo_bar.AppendASCII("quux.txt")));
410 }
411
TEST_F(ZipTest,Zip)412 TEST_F(ZipTest, Zip) {
413 base::FilePath src_dir;
414 ASSERT_TRUE(GetTestDataDirectory(&src_dir));
415 src_dir = src_dir.AppendASCII("test");
416
417 base::ScopedTempDir temp_dir;
418 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
419 base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip");
420
421 EXPECT_TRUE(zip::Zip(src_dir, zip_file, /*include_hidden_files=*/true));
422 TestUnzipFile(zip_file, true);
423 }
424
TEST_F(ZipTest,ZipIgnoreHidden)425 TEST_F(ZipTest, ZipIgnoreHidden) {
426 base::FilePath src_dir;
427 ASSERT_TRUE(GetTestDataDirectory(&src_dir));
428 src_dir = src_dir.AppendASCII("test");
429
430 base::ScopedTempDir temp_dir;
431 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
432 base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip");
433
434 EXPECT_TRUE(zip::Zip(src_dir, zip_file, /*include_hidden_files=*/false));
435 TestUnzipFile(zip_file, false);
436 }
437
TEST_F(ZipTest,ZipNonASCIIDir)438 TEST_F(ZipTest, ZipNonASCIIDir) {
439 base::FilePath src_dir;
440 ASSERT_TRUE(GetTestDataDirectory(&src_dir));
441 src_dir = src_dir.AppendASCII("test");
442
443 base::ScopedTempDir temp_dir;
444 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
445 // Append 'Тест' (in cyrillic).
446 base::FilePath src_dir_russian = temp_dir.GetPath().Append(
447 base::FilePath::FromUTF8Unsafe("\xD0\xA2\xD0\xB5\xD1\x81\xD1\x82"));
448 base::CopyDirectory(src_dir, src_dir_russian, true);
449 base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out_russian.zip");
450
451 EXPECT_TRUE(zip::Zip(src_dir_russian, zip_file, true));
452 TestUnzipFile(zip_file, true);
453 }
454
TEST_F(ZipTest,ZipTimeStamp)455 TEST_F(ZipTest, ZipTimeStamp) {
456 // The dates tested are arbitrary, with some constraints. The zip format can
457 // only store years from 1980 to 2107 and an even number of seconds, due to it
458 // using the ms dos date format.
459
460 // Valid arbitrary date.
461 TestTimeStamp("23 Oct 1997 23:22:20", VALID_YEAR);
462
463 // Date before 1980, zip format limitation, must default to unix epoch.
464 TestTimeStamp("29 Dec 1979 21:00:10", INVALID_YEAR);
465
466 // Despite the minizip headers telling the maximum year should be 2044, it
467 // can actually go up to 2107. Beyond that, the dos date format cannot store
468 // the year (2107-1980=127). To test that limit, the input file needs to be
469 // touched, but the code that modifies the file access and modification times
470 // relies on time_t which is defined as long, therefore being in many
471 // platforms just a 4-byte integer, like 32-bit Mac OSX or linux. As such, it
472 // suffers from the year-2038 bug. Therefore 2038 is the highest we can test
473 // in all platforms reliably.
474 TestTimeStamp("02 Jan 2038 23:59:58", VALID_YEAR);
475 }
476
477 #if defined(OS_POSIX)
TEST_F(ZipTest,ZipFiles)478 TEST_F(ZipTest, ZipFiles) {
479 base::FilePath src_dir;
480 ASSERT_TRUE(GetTestDataDirectory(&src_dir));
481 src_dir = src_dir.AppendASCII("test");
482
483 base::ScopedTempDir temp_dir;
484 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
485 base::FilePath zip_name = temp_dir.GetPath().AppendASCII("out.zip");
486
487 base::File zip_file(zip_name,
488 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
489 ASSERT_TRUE(zip_file.IsValid());
490 EXPECT_TRUE(zip::ZipFiles(src_dir, zip_file_list_,
491 zip_file.GetPlatformFile()));
492 zip_file.Close();
493
494 zip::ZipReader reader;
495 EXPECT_TRUE(reader.Open(zip_name));
496 EXPECT_EQ(zip_file_list_.size(), static_cast<size_t>(reader.num_entries()));
497 for (size_t i = 0; i < zip_file_list_.size(); ++i) {
498 EXPECT_TRUE(reader.HasMore());
499 EXPECT_TRUE(reader.OpenCurrentEntryInZip());
500 const zip::ZipReader::EntryInfo* entry_info = reader.current_entry_info();
501 EXPECT_EQ(entry_info->file_path(), zip_file_list_[i]);
502 reader.AdvanceToNextEntry();
503 }
504 }
505 #endif // defined(OS_POSIX)
506
TEST_F(ZipTest,UnzipFilesWithIncorrectSize)507 TEST_F(ZipTest, UnzipFilesWithIncorrectSize) {
508 base::FilePath test_data_folder;
509 ASSERT_TRUE(GetTestDataDirectory(&test_data_folder));
510
511 // test_mismatch_size.zip contains files with names from 0.txt to 7.txt with
512 // sizes from 0 to 7 bytes respectively, but the metadata in the zip file says
513 // the uncompressed size is 3 bytes. The ZipReader and minizip code needs to
514 // be clever enough to get all the data out.
515 base::FilePath test_zip_file =
516 test_data_folder.AppendASCII("test_mismatch_size.zip");
517
518 base::ScopedTempDir scoped_temp_dir;
519 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
520 const base::FilePath& temp_dir = scoped_temp_dir.GetPath();
521
522 ASSERT_TRUE(zip::Unzip(test_zip_file, temp_dir));
523 EXPECT_TRUE(base::DirectoryExists(temp_dir.AppendASCII("d")));
524
525 for (int i = 0; i < 8; i++) {
526 SCOPED_TRACE(base::StringPrintf("Processing %d.txt", i));
527 base::FilePath file_path = temp_dir.AppendASCII(
528 base::StringPrintf("%d.txt", i));
529 int64_t file_size = -1;
530 EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
531 EXPECT_EQ(static_cast<int64_t>(i), file_size);
532 }
533 }
534
TEST_F(ZipTest,ZipWithFileAccessor)535 TEST_F(ZipTest, ZipWithFileAccessor) {
536 base::FilePath zip_file;
537 ASSERT_TRUE(base::CreateTemporaryFile(&zip_file));
538 zip::ZipParams params(base::FilePath(FILE_PATH_LITERAL("/test")), zip_file);
539 params.set_file_accessor(std::make_unique<VirtualFileSystem>());
540 ASSERT_TRUE(zip::Zip(params));
541
542 base::ScopedTempDir scoped_temp_dir;
543 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
544 const base::FilePath& temp_dir = scoped_temp_dir.GetPath();
545 ASSERT_TRUE(zip::Unzip(zip_file, temp_dir));
546 base::FilePath bar_dir = temp_dir.Append(FILE_PATH_LITERAL("bar"));
547 EXPECT_TRUE(base::DirectoryExists(bar_dir));
548 std::string file_content;
549 EXPECT_TRUE(base::ReadFileToString(
550 temp_dir.Append(FILE_PATH_LITERAL("foo.txt")), &file_content));
551 EXPECT_EQ(VirtualFileSystem::kFooContent, file_content);
552 EXPECT_TRUE(base::ReadFileToString(
553 bar_dir.Append(FILE_PATH_LITERAL("bar1.txt")), &file_content));
554 EXPECT_EQ(VirtualFileSystem::kBar1Content, file_content);
555 EXPECT_TRUE(base::ReadFileToString(
556 bar_dir.Append(FILE_PATH_LITERAL("bar2.txt")), &file_content));
557 EXPECT_EQ(VirtualFileSystem::kBar2Content, file_content);
558 }
559
560 } // namespace
561