Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / zlib / google / zip_reader_unittest.cc
blob89b4ac52e32607ebf361c4c6341168b37dd71db1
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.
5 #include "third_party/zlib/google/zip_reader.h"
7 #include <set>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/files/file.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/logging.h"
15 #include "base/md5.h"
16 #include "base/path_service.h"
17 #include "base/run_loop.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "testing/platform_test.h"
24 #include "third_party/zlib/google/zip_internal.h"
26 using ::testing::Return;
27 using ::testing::_;
29 namespace {
31 const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
33 class FileWrapper {
34 public:
35 typedef enum {
36 READ_ONLY,
37 READ_WRITE
38 } AccessMode;
40 FileWrapper(const base::FilePath& path, AccessMode mode) {
41 int flags = base::File::FLAG_READ;
42 if (mode == READ_ONLY)
43 flags |= base::File::FLAG_OPEN;
44 else
45 flags |= base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS;
47 file_.Initialize(path, flags);
50 ~FileWrapper() {}
52 base::PlatformFile platform_file() { return file_.GetPlatformFile(); }
54 base::File* file() { return &file_; }
56 private:
57 base::File file_;
60 // A mock that provides methods that can be used as callbacks in asynchronous
61 // unzip functions. Tracks the number of calls and number of bytes reported.
62 // Assumes that progress callbacks will be executed in-order.
63 class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> {
64 public:
65 MockUnzipListener()
66 : success_calls_(0),
67 failure_calls_(0),
68 progress_calls_(0),
69 current_progress_(0) {
72 // Success callback for async functions.
73 void OnUnzipSuccess() {
74 success_calls_++;
77 // Failure callback for async functions.
78 void OnUnzipFailure() {
79 failure_calls_++;
82 // Progress callback for async functions.
83 void OnUnzipProgress(int64 progress) {
84 DCHECK(progress > current_progress_);
85 progress_calls_++;
86 current_progress_ = progress;
89 int success_calls() { return success_calls_; }
90 int failure_calls() { return failure_calls_; }
91 int progress_calls() { return progress_calls_; }
92 int current_progress() { return current_progress_; }
94 private:
95 int success_calls_;
96 int failure_calls_;
97 int progress_calls_;
99 int64 current_progress_;
102 class MockWriterDelegate : public zip::WriterDelegate {
103 public:
104 MOCK_METHOD0(PrepareOutput, bool());
105 MOCK_METHOD2(WriteBytes, bool(const char*, int));
108 } // namespace
110 namespace zip {
112 // Make the test a PlatformTest to setup autorelease pools properly on Mac.
113 class ZipReaderTest : public PlatformTest {
114 protected:
115 virtual void SetUp() {
116 PlatformTest::SetUp();
118 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
119 test_dir_ = temp_dir_.path();
121 ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_));
123 test_zip_file_ = test_data_dir_.AppendASCII("test.zip");
124 evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip");
125 evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII(
126 "evil_via_invalid_utf8.zip");
127 evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII(
128 "evil_via_absolute_file_name.zip");
130 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/")));
131 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/")));
132 test_zip_contents_.insert(
133 base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")));
134 test_zip_contents_.insert(
135 base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
136 test_zip_contents_.insert(
137 base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")));
138 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
139 test_zip_contents_.insert(
140 base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
143 virtual void TearDown() {
144 PlatformTest::TearDown();
147 bool GetTestDataDirectory(base::FilePath* path) {
148 bool success = PathService::Get(base::DIR_SOURCE_ROOT, path);
149 EXPECT_TRUE(success);
150 if (!success)
151 return false;
152 *path = path->AppendASCII("third_party");
153 *path = path->AppendASCII("zlib");
154 *path = path->AppendASCII("google");
155 *path = path->AppendASCII("test");
156 *path = path->AppendASCII("data");
157 return true;
160 bool CompareFileAndMD5(const base::FilePath& path,
161 const std::string expected_md5) {
162 // Read the output file and compute the MD5.
163 std::string output;
164 if (!base::ReadFileToString(path, &output))
165 return false;
166 const std::string md5 = base::MD5String(output);
167 return expected_md5 == md5;
170 // The path to temporary directory used to contain the test operations.
171 base::FilePath test_dir_;
172 // The path to the test data directory where test.zip etc. are located.
173 base::FilePath test_data_dir_;
174 // The path to test.zip in the test data directory.
175 base::FilePath test_zip_file_;
176 // The path to evil.zip in the test data directory.
177 base::FilePath evil_zip_file_;
178 // The path to evil_via_invalid_utf8.zip in the test data directory.
179 base::FilePath evil_via_invalid_utf8_zip_file_;
180 // The path to evil_via_absolute_file_name.zip in the test data directory.
181 base::FilePath evil_via_absolute_file_name_zip_file_;
182 std::set<base::FilePath> test_zip_contents_;
184 base::ScopedTempDir temp_dir_;
186 base::MessageLoop message_loop_;
189 TEST_F(ZipReaderTest, Open_ValidZipFile) {
190 ZipReader reader;
191 ASSERT_TRUE(reader.Open(test_zip_file_));
194 TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) {
195 ZipReader reader;
196 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
197 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
200 TEST_F(ZipReaderTest, Open_NonExistentFile) {
201 ZipReader reader;
202 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip")));
205 TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) {
206 ZipReader reader;
207 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh")));
210 // Iterate through the contents in the test zip file, and compare that the
211 // contents collected from the zip reader matches the expected contents.
212 TEST_F(ZipReaderTest, Iteration) {
213 std::set<base::FilePath> actual_contents;
214 ZipReader reader;
215 ASSERT_TRUE(reader.Open(test_zip_file_));
216 while (reader.HasMore()) {
217 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
218 actual_contents.insert(reader.current_entry_info()->file_path());
219 ASSERT_TRUE(reader.AdvanceToNextEntry());
221 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
222 EXPECT_EQ(test_zip_contents_.size(),
223 static_cast<size_t>(reader.num_entries()));
224 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
225 EXPECT_EQ(test_zip_contents_, actual_contents);
228 // Open the test zip file from a file descriptor, iterate through its contents,
229 // and compare that they match the expected contents.
230 TEST_F(ZipReaderTest, PlatformFileIteration) {
231 std::set<base::FilePath> actual_contents;
232 ZipReader reader;
233 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
234 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
235 while (reader.HasMore()) {
236 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
237 actual_contents.insert(reader.current_entry_info()->file_path());
238 ASSERT_TRUE(reader.AdvanceToNextEntry());
240 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
241 EXPECT_EQ(test_zip_contents_.size(),
242 static_cast<size_t>(reader.num_entries()));
243 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
244 EXPECT_EQ(test_zip_contents_, actual_contents);
247 TEST_F(ZipReaderTest, LocateAndOpenEntry_ValidFile) {
248 std::set<base::FilePath> actual_contents;
249 ZipReader reader;
250 ASSERT_TRUE(reader.Open(test_zip_file_));
251 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
252 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
253 EXPECT_EQ(target_path, reader.current_entry_info()->file_path());
256 TEST_F(ZipReaderTest, LocateAndOpenEntry_NonExistentFile) {
257 std::set<base::FilePath> actual_contents;
258 ZipReader reader;
259 ASSERT_TRUE(reader.Open(test_zip_file_));
260 base::FilePath target_path(FILE_PATH_LITERAL("nonexistent.txt"));
261 ASSERT_FALSE(reader.LocateAndOpenEntry(target_path));
262 EXPECT_EQ(NULL, reader.current_entry_info());
265 TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_RegularFile) {
266 ZipReader reader;
267 ASSERT_TRUE(reader.Open(test_zip_file_));
268 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
269 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
270 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
271 test_dir_.AppendASCII("quux.txt")));
272 // Read the output file ans compute the MD5.
273 std::string output;
274 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
275 &output));
276 const std::string md5 = base::MD5String(output);
277 EXPECT_EQ(kQuuxExpectedMD5, md5);
278 // quux.txt should be larger than kZipBufSize so that we can exercise
279 // the loop in ExtractCurrentEntry().
280 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
283 TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFilePath_RegularFile) {
284 ZipReader reader;
285 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
286 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
287 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
288 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
289 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
290 test_dir_.AppendASCII("quux.txt")));
291 // Read the output file and compute the MD5.
292 std::string output;
293 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
294 &output));
295 const std::string md5 = base::MD5String(output);
296 EXPECT_EQ(kQuuxExpectedMD5, md5);
297 // quux.txt should be larger than kZipBufSize so that we can exercise
298 // the loop in ExtractCurrentEntry().
299 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
302 TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFile_RegularFile) {
303 ZipReader reader;
304 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
305 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
306 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
307 base::FilePath out_path = test_dir_.AppendASCII("quux.txt");
308 FileWrapper out_fd_w(out_path, FileWrapper::READ_WRITE);
309 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
310 ASSERT_TRUE(reader.ExtractCurrentEntryToFile(out_fd_w.file()));
311 // Read the output file and compute the MD5.
312 std::string output;
313 ASSERT_TRUE(base::ReadFileToString(out_path, &output));
314 const std::string md5 = base::MD5String(output);
315 EXPECT_EQ(kQuuxExpectedMD5, md5);
316 // quux.txt should be larger than kZipBufSize so that we can exercise
317 // the loop in ExtractCurrentEntry().
318 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
321 TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) {
322 ZipReader reader;
323 ASSERT_TRUE(reader.Open(test_zip_file_));
324 base::FilePath target_path(FILE_PATH_LITERAL("foo/"));
325 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
326 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
327 test_dir_.AppendASCII("foo")));
328 // The directory should be created.
329 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo")));
332 TEST_F(ZipReaderTest, ExtractCurrentEntryIntoDirectory_RegularFile) {
333 ZipReader reader;
334 ASSERT_TRUE(reader.Open(test_zip_file_));
335 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
336 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
337 ASSERT_TRUE(reader.ExtractCurrentEntryIntoDirectory(test_dir_));
338 // Sub directories should be created.
339 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo/bar")));
340 // And the file should be created.
341 std::string output;
342 ASSERT_TRUE(base::ReadFileToString(
343 test_dir_.AppendASCII("foo/bar/quux.txt"), &output));
344 const std::string md5 = base::MD5String(output);
345 EXPECT_EQ(kQuuxExpectedMD5, md5);
348 TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
349 ZipReader reader;
350 ASSERT_TRUE(reader.Open(test_zip_file_));
351 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
352 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
353 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
355 EXPECT_EQ(target_path, current_entry_info->file_path());
356 EXPECT_EQ(13527, current_entry_info->original_size());
358 // The expected time stamp: 2009-05-29 06:22:20
359 base::Time::Exploded exploded = {}; // Zero-clear.
360 current_entry_info->last_modified().LocalExplode(&exploded);
361 EXPECT_EQ(2009, exploded.year);
362 EXPECT_EQ(5, exploded.month);
363 EXPECT_EQ(29, exploded.day_of_month);
364 EXPECT_EQ(6, exploded.hour);
365 EXPECT_EQ(22, exploded.minute);
366 EXPECT_EQ(20, exploded.second);
367 EXPECT_EQ(0, exploded.millisecond);
369 EXPECT_FALSE(current_entry_info->is_unsafe());
370 EXPECT_FALSE(current_entry_info->is_directory());
373 TEST_F(ZipReaderTest, current_entry_info_DotDotFile) {
374 ZipReader reader;
375 ASSERT_TRUE(reader.Open(evil_zip_file_));
376 base::FilePath target_path(FILE_PATH_LITERAL(
377 "../levilevilevilevilevilevilevilevilevilevilevilevil"));
378 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
379 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
380 EXPECT_EQ(target_path, current_entry_info->file_path());
382 // This file is unsafe because of ".." in the file name.
383 EXPECT_TRUE(current_entry_info->is_unsafe());
384 EXPECT_FALSE(current_entry_info->is_directory());
387 TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) {
388 ZipReader reader;
389 ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_));
390 // The evil file is the 2nd file in the zip file.
391 // We cannot locate by the file name ".\x80.\\evil.txt",
392 // as FilePath may internally convert the string.
393 ASSERT_TRUE(reader.AdvanceToNextEntry());
394 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
395 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
397 // This file is unsafe because of invalid UTF-8 in the file name.
398 EXPECT_TRUE(current_entry_info->is_unsafe());
399 EXPECT_FALSE(current_entry_info->is_directory());
402 TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) {
403 ZipReader reader;
404 ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_));
405 base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt"));
406 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
407 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
408 EXPECT_EQ(target_path, current_entry_info->file_path());
410 // This file is unsafe because of the absolute file name.
411 EXPECT_TRUE(current_entry_info->is_unsafe());
412 EXPECT_FALSE(current_entry_info->is_directory());
415 TEST_F(ZipReaderTest, current_entry_info_Directory) {
416 ZipReader reader;
417 ASSERT_TRUE(reader.Open(test_zip_file_));
418 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/"));
419 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
420 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
422 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
423 current_entry_info->file_path());
424 // The directory size should be zero.
425 EXPECT_EQ(0, current_entry_info->original_size());
427 // The expected time stamp: 2009-05-31 15:49:52
428 base::Time::Exploded exploded = {}; // Zero-clear.
429 current_entry_info->last_modified().LocalExplode(&exploded);
430 EXPECT_EQ(2009, exploded.year);
431 EXPECT_EQ(5, exploded.month);
432 EXPECT_EQ(31, exploded.day_of_month);
433 EXPECT_EQ(15, exploded.hour);
434 EXPECT_EQ(49, exploded.minute);
435 EXPECT_EQ(52, exploded.second);
436 EXPECT_EQ(0, exploded.millisecond);
438 EXPECT_FALSE(current_entry_info->is_unsafe());
439 EXPECT_TRUE(current_entry_info->is_directory());
442 // Verifies that the ZipReader class can extract a file from a zip archive
443 // stored in memory. This test opens a zip archive in a std::string object,
444 // extracts its content, and verifies the content is the same as the expected
445 // text.
446 TEST_F(ZipReaderTest, OpenFromString) {
447 // A zip archive consisting of one file "test.txt", which is a 16-byte text
448 // file that contains "This is a test.\n".
449 const char kTestData[] =
450 "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\xa4\x66\x24\x41\x13\xe8"
451 "\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00\x1c\x00\x74\x65"
452 "\x73\x74\x2e\x74\x78\x74\x55\x54\x09\x00\x03\x34\x89\x45\x50\x34"
453 "\x89\x45\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13"
454 "\x00\x00\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74"
455 "\x2e\x0a\x50\x4b\x01\x02\x1e\x03\x0a\x00\x00\x00\x00\x00\xa4\x66"
456 "\x24\x41\x13\xe8\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00"
457 "\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa4\x81\x00\x00\x00\x00"
458 "\x74\x65\x73\x74\x2e\x74\x78\x74\x55\x54\x05\x00\x03\x34\x89\x45"
459 "\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00"
460 "\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00"
461 "\x52\x00\x00\x00\x00\x00";
462 std::string data(kTestData, arraysize(kTestData));
463 ZipReader reader;
464 ASSERT_TRUE(reader.OpenFromString(data));
465 base::FilePath target_path(FILE_PATH_LITERAL("test.txt"));
466 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
467 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
468 test_dir_.AppendASCII("test.txt")));
470 std::string actual;
471 ASSERT_TRUE(base::ReadFileToString(
472 test_dir_.AppendASCII("test.txt"), &actual));
473 EXPECT_EQ(std::string("This is a test.\n"), actual);
476 // Verifies that the asynchronous extraction to a file works.
477 TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
478 MockUnzipListener listener;
480 ZipReader reader;
481 base::FilePath target_file = test_dir_.AppendASCII("quux.txt");
482 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
483 ASSERT_TRUE(reader.Open(test_zip_file_));
484 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
485 reader.ExtractCurrentEntryToFilePathAsync(
486 target_file,
487 base::Bind(&MockUnzipListener::OnUnzipSuccess,
488 listener.AsWeakPtr()),
489 base::Bind(&MockUnzipListener::OnUnzipFailure,
490 listener.AsWeakPtr()),
491 base::Bind(&MockUnzipListener::OnUnzipProgress,
492 listener.AsWeakPtr()));
494 EXPECT_EQ(0, listener.success_calls());
495 EXPECT_EQ(0, listener.failure_calls());
496 EXPECT_EQ(0, listener.progress_calls());
498 base::RunLoop().RunUntilIdle();
500 EXPECT_EQ(1, listener.success_calls());
501 EXPECT_EQ(0, listener.failure_calls());
502 EXPECT_LE(1, listener.progress_calls());
504 std::string output;
505 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
506 &output));
507 const std::string md5 = base::MD5String(output);
508 EXPECT_EQ(kQuuxExpectedMD5, md5);
510 int64 file_size = 0;
511 ASSERT_TRUE(base::GetFileSize(target_file, &file_size));
513 EXPECT_EQ(file_size, listener.current_progress());
516 // Verifies that the asynchronous extraction to a file works.
517 TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) {
518 MockUnzipListener listener;
520 ZipReader reader;
521 base::FilePath target_file = test_dir_.AppendASCII("foo");
522 base::FilePath target_path(FILE_PATH_LITERAL("foo/"));
523 ASSERT_TRUE(reader.Open(test_zip_file_));
524 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
525 reader.ExtractCurrentEntryToFilePathAsync(
526 target_file,
527 base::Bind(&MockUnzipListener::OnUnzipSuccess,
528 listener.AsWeakPtr()),
529 base::Bind(&MockUnzipListener::OnUnzipFailure,
530 listener.AsWeakPtr()),
531 base::Bind(&MockUnzipListener::OnUnzipProgress,
532 listener.AsWeakPtr()));
534 EXPECT_EQ(0, listener.success_calls());
535 EXPECT_EQ(0, listener.failure_calls());
536 EXPECT_EQ(0, listener.progress_calls());
538 base::RunLoop().RunUntilIdle();
540 EXPECT_EQ(1, listener.success_calls());
541 EXPECT_EQ(0, listener.failure_calls());
542 EXPECT_GE(0, listener.progress_calls());
544 ASSERT_TRUE(base::DirectoryExists(target_file));
547 TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
548 // test_mismatch_size.zip contains files with names from 0.txt to 7.txt with
549 // sizes from 0 to 7 bytes respectively, being the contents of each file a
550 // substring of "0123456" starting at '0'.
551 base::FilePath test_zip_file =
552 test_data_dir_.AppendASCII("test_mismatch_size.zip");
554 ZipReader reader;
555 std::string contents;
556 ASSERT_TRUE(reader.Open(test_zip_file));
558 for (size_t i = 0; i < 8; i++) {
559 SCOPED_TRACE(base::StringPrintf("Processing %d.txt", static_cast<int>(i)));
561 base::FilePath file_name = base::FilePath::FromUTF8Unsafe(
562 base::StringPrintf("%d.txt", static_cast<int>(i)));
563 ASSERT_TRUE(reader.LocateAndOpenEntry(file_name));
565 if (i > 1) {
566 // Off by one byte read limit: must fail.
567 EXPECT_FALSE(reader.ExtractCurrentEntryToString(i - 1, &contents));
570 if (i > 0) {
571 // Exact byte read limit: must pass.
572 EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents));
573 EXPECT_EQ(i, contents.size());
574 EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i));
577 // More than necessary byte read limit: must pass.
578 EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents));
579 EXPECT_EQ(i, contents.size());
580 EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i));
582 reader.Close();
585 // This test exposes http://crbug.com/430959, at least on OS X
586 TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
587 for (int i = 0; i < 100000; ++i) {
588 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
589 ZipReader reader;
590 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
594 // Test that when WriterDelegate::PrepareMock returns false, no other methods on
595 // the delegate are called and the extraction fails.
596 TEST_F(ZipReaderTest, ExtractCurrentEntryPrepareFailure) {
597 testing::StrictMock<MockWriterDelegate> mock_writer;
599 EXPECT_CALL(mock_writer, PrepareOutput())
600 .WillOnce(Return(false));
602 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
603 ZipReader reader;
605 ASSERT_TRUE(reader.Open(test_zip_file_));
606 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
607 ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
610 // Test that when WriterDelegate::WriteBytes returns false, no other methods on
611 // the delegate are called and the extraction fails.
612 TEST_F(ZipReaderTest, ExtractCurrentEntryWriteBytesFailure) {
613 testing::StrictMock<MockWriterDelegate> mock_writer;
615 EXPECT_CALL(mock_writer, PrepareOutput())
616 .WillOnce(Return(true));
617 EXPECT_CALL(mock_writer, WriteBytes(_, _))
618 .WillOnce(Return(false));
620 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
621 ZipReader reader;
623 ASSERT_TRUE(reader.Open(test_zip_file_));
624 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
625 ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
628 // Test that extraction succeeds when the writer delegate reports all is well.
629 TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
630 testing::StrictMock<MockWriterDelegate> mock_writer;
632 EXPECT_CALL(mock_writer, PrepareOutput())
633 .WillOnce(Return(true));
634 EXPECT_CALL(mock_writer, WriteBytes(_, _))
635 .WillRepeatedly(Return(true));
637 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
638 ZipReader reader;
640 ASSERT_TRUE(reader.Open(test_zip_file_));
641 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
642 ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer));
645 class FileWriterDelegateTest : public ::testing::Test {
646 protected:
647 void SetUp() override {
648 ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
649 file_.Initialize(temp_file_path_, (base::File::FLAG_CREATE_ALWAYS |
650 base::File::FLAG_READ |
651 base::File::FLAG_WRITE |
652 base::File::FLAG_TEMPORARY |
653 base::File::FLAG_DELETE_ON_CLOSE));
654 ASSERT_TRUE(file_.IsValid());
657 // Writes data to the file, leaving the current position at the end of the
658 // write.
659 void PopulateFile() {
660 static const char kSomeData[] = "this sure is some data.";
661 static const size_t kSomeDataLen = sizeof(kSomeData) - 1;
662 ASSERT_NE(-1LL, file_.Write(0LL, kSomeData, kSomeDataLen));
665 base::FilePath temp_file_path_;
666 base::File file_;
669 TEST_F(FileWriterDelegateTest, WriteToStartAndTruncate) {
670 // Write stuff and advance.
671 PopulateFile();
673 // This should rewind, write, then truncate.
674 static const char kSomeData[] = "short";
675 static const int kSomeDataLen = sizeof(kSomeData) - 1;
677 FileWriterDelegate writer(&file_);
678 ASSERT_TRUE(writer.PrepareOutput());
679 ASSERT_TRUE(writer.WriteBytes(kSomeData, kSomeDataLen));
681 ASSERT_EQ(kSomeDataLen, file_.GetLength());
682 char buf[kSomeDataLen] = {};
683 ASSERT_EQ(kSomeDataLen, file_.Read(0LL, buf, kSomeDataLen));
684 ASSERT_EQ(std::string(kSomeData), std::string(buf, kSomeDataLen));
687 } // namespace zip