• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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