zip_reader_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "third_party/zlib/google/zip_reader.h" 6 7#include <set> 8#include <string> 9 10#include "base/bind.h" 11#include "base/file_util.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/logging.h" 14#include "base/md5.h" 15#include "base/path_service.h" 16#include "base/platform_file.h" 17#include "base/run_loop.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/time/time.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#include "testing/platform_test.h" 22#include "third_party/zlib/google/zip_internal.h" 23 24namespace { 25 26const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6"; 27 28// Wrap PlatformFiles in a class so that we don't leak them in tests. 29class PlatformFileWrapper { 30 public: 31 typedef enum { 32 READ_ONLY, 33 READ_WRITE 34 } AccessMode; 35 36 PlatformFileWrapper(const base::FilePath& file, AccessMode mode) 37 : file_(base::kInvalidPlatformFileValue) { 38 switch (mode) { 39 case READ_ONLY: 40 file_ = base::CreatePlatformFile(file, 41 base::PLATFORM_FILE_OPEN | 42 base::PLATFORM_FILE_READ, 43 NULL, NULL); 44 break; 45 case READ_WRITE: 46 file_ = base::CreatePlatformFile(file, 47 base::PLATFORM_FILE_CREATE_ALWAYS | 48 base::PLATFORM_FILE_READ | 49 base::PLATFORM_FILE_WRITE, 50 NULL, NULL); 51 break; 52 default: 53 NOTREACHED(); 54 } 55 return; 56 } 57 58 ~PlatformFileWrapper() { 59 base::ClosePlatformFile(file_); 60 } 61 62 base::PlatformFile platform_file() { return file_; } 63 64 private: 65 base::PlatformFile file_; 66}; 67 68// A mock that provides methods that can be used as callbacks in asynchronous 69// unzip functions. Tracks the number of calls and number of bytes reported. 70// Assumes that progress callbacks will be executed in-order. 71class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> { 72 public: 73 MockUnzipListener() 74 : success_calls_(0), 75 failure_calls_(0), 76 progress_calls_(0), 77 current_progress_(0) { 78 } 79 80 // Success callback for async functions. 81 void OnUnzipSuccess() { 82 success_calls_++; 83 } 84 85 // Failure callback for async functions. 86 void OnUnzipFailure() { 87 failure_calls_++; 88 } 89 90 // Progress callback for async functions. 91 void OnUnzipProgress(int64 progress) { 92 DCHECK(progress > current_progress_); 93 progress_calls_++; 94 current_progress_ = progress; 95 } 96 97 int success_calls() { return success_calls_; } 98 int failure_calls() { return failure_calls_; } 99 int progress_calls() { return progress_calls_; } 100 int current_progress() { return current_progress_; } 101 102 private: 103 int success_calls_; 104 int failure_calls_; 105 int progress_calls_; 106 107 int64 current_progress_; 108}; 109 110} // namespace 111 112namespace zip { 113 114// Make the test a PlatformTest to setup autorelease pools properly on Mac. 115class ZipReaderTest : public PlatformTest { 116 protected: 117 virtual void SetUp() { 118 PlatformTest::SetUp(); 119 120 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 121 test_dir_ = temp_dir_.path(); 122 123 ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_)); 124 125 test_zip_file_ = test_data_dir_.AppendASCII("test.zip"); 126 evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip"); 127 evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII( 128 "evil_via_invalid_utf8.zip"); 129 evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII( 130 "evil_via_absolute_file_name.zip"); 131 132 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/"))); 133 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/"))); 134 test_zip_contents_.insert( 135 base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt"))); 136 test_zip_contents_.insert( 137 base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt"))); 138 test_zip_contents_.insert( 139 base::FilePath(FILE_PATH_LITERAL("foo/bar.txt"))); 140 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt"))); 141 test_zip_contents_.insert( 142 base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden"))); 143 } 144 145 virtual void TearDown() { 146 PlatformTest::TearDown(); 147 } 148 149 bool GetTestDataDirectory(base::FilePath* path) { 150 bool success = PathService::Get(base::DIR_SOURCE_ROOT, path); 151 EXPECT_TRUE(success); 152 if (!success) 153 return false; 154 *path = path->AppendASCII("third_party"); 155 *path = path->AppendASCII("zlib"); 156 *path = path->AppendASCII("google"); 157 *path = path->AppendASCII("test"); 158 *path = path->AppendASCII("data"); 159 return true; 160 } 161 162 bool CompareFileAndMD5(const base::FilePath& path, 163 const std::string expected_md5) { 164 // Read the output file and compute the MD5. 165 std::string output; 166 if (!base::ReadFileToString(path, &output)) 167 return false; 168 const std::string md5 = base::MD5String(output); 169 return expected_md5 == md5; 170 } 171 172 // The path to temporary directory used to contain the test operations. 173 base::FilePath test_dir_; 174 // The path to the test data directory where test.zip etc. are located. 175 base::FilePath test_data_dir_; 176 // The path to test.zip in the test data directory. 177 base::FilePath test_zip_file_; 178 // The path to evil.zip in the test data directory. 179 base::FilePath evil_zip_file_; 180 // The path to evil_via_invalid_utf8.zip in the test data directory. 181 base::FilePath evil_via_invalid_utf8_zip_file_; 182 // The path to evil_via_absolute_file_name.zip in the test data directory. 183 base::FilePath evil_via_absolute_file_name_zip_file_; 184 std::set<base::FilePath> test_zip_contents_; 185 186 base::ScopedTempDir temp_dir_; 187 188 base::MessageLoop message_loop_; 189}; 190 191TEST_F(ZipReaderTest, Open_ValidZipFile) { 192 ZipReader reader; 193 ASSERT_TRUE(reader.Open(test_zip_file_)); 194} 195 196TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) { 197 ZipReader reader; 198 PlatformFileWrapper zip_fd_wrapper(test_zip_file_, 199 PlatformFileWrapper::READ_ONLY); 200 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); 201} 202 203TEST_F(ZipReaderTest, Open_NonExistentFile) { 204 ZipReader reader; 205 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip"))); 206} 207 208TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) { 209 ZipReader reader; 210 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh"))); 211} 212 213// Iterate through the contents in the test zip file, and compare that the 214// contents collected from the zip reader matches the expected contents. 215TEST_F(ZipReaderTest, Iteration) { 216 std::set<base::FilePath> actual_contents; 217 ZipReader reader; 218 ASSERT_TRUE(reader.Open(test_zip_file_)); 219 while (reader.HasMore()) { 220 ASSERT_TRUE(reader.OpenCurrentEntryInZip()); 221 actual_contents.insert(reader.current_entry_info()->file_path()); 222 ASSERT_TRUE(reader.AdvanceToNextEntry()); 223 } 224 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further. 225 EXPECT_EQ(test_zip_contents_.size(), 226 static_cast<size_t>(reader.num_entries())); 227 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size()); 228 EXPECT_EQ(test_zip_contents_, actual_contents); 229} 230 231// Open the test zip file from a file descriptor, iterate through its contents, 232// and compare that they match the expected contents. 233TEST_F(ZipReaderTest, PlatformFileIteration) { 234 std::set<base::FilePath> actual_contents; 235 ZipReader reader; 236 PlatformFileWrapper zip_fd_wrapper(test_zip_file_, 237 PlatformFileWrapper::READ_ONLY); 238 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); 239 while (reader.HasMore()) { 240 ASSERT_TRUE(reader.OpenCurrentEntryInZip()); 241 actual_contents.insert(reader.current_entry_info()->file_path()); 242 ASSERT_TRUE(reader.AdvanceToNextEntry()); 243 } 244 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further. 245 EXPECT_EQ(test_zip_contents_.size(), 246 static_cast<size_t>(reader.num_entries())); 247 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size()); 248 EXPECT_EQ(test_zip_contents_, actual_contents); 249} 250 251TEST_F(ZipReaderTest, LocateAndOpenEntry_ValidFile) { 252 std::set<base::FilePath> actual_contents; 253 ZipReader reader; 254 ASSERT_TRUE(reader.Open(test_zip_file_)); 255 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 256 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 257 EXPECT_EQ(target_path, reader.current_entry_info()->file_path()); 258} 259 260TEST_F(ZipReaderTest, LocateAndOpenEntry_NonExistentFile) { 261 std::set<base::FilePath> actual_contents; 262 ZipReader reader; 263 ASSERT_TRUE(reader.Open(test_zip_file_)); 264 base::FilePath target_path(FILE_PATH_LITERAL("nonexistent.txt")); 265 ASSERT_FALSE(reader.LocateAndOpenEntry(target_path)); 266 EXPECT_EQ(NULL, reader.current_entry_info()); 267} 268 269TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_RegularFile) { 270 ZipReader reader; 271 ASSERT_TRUE(reader.Open(test_zip_file_)); 272 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 273 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 274 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( 275 test_dir_.AppendASCII("quux.txt"))); 276 // Read the output file ans compute the MD5. 277 std::string output; 278 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), 279 &output)); 280 const std::string md5 = base::MD5String(output); 281 EXPECT_EQ(kQuuxExpectedMD5, md5); 282 // quux.txt should be larger than kZipBufSize so that we can exercise 283 // the loop in ExtractCurrentEntry(). 284 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); 285} 286 287TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFilePath_RegularFile) { 288 ZipReader reader; 289 PlatformFileWrapper zip_fd_wrapper(test_zip_file_, 290 PlatformFileWrapper::READ_ONLY); 291 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); 292 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 293 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 294 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( 295 test_dir_.AppendASCII("quux.txt"))); 296 // Read the output file and compute the MD5. 297 std::string output; 298 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), 299 &output)); 300 const std::string md5 = base::MD5String(output); 301 EXPECT_EQ(kQuuxExpectedMD5, md5); 302 // quux.txt should be larger than kZipBufSize so that we can exercise 303 // the loop in ExtractCurrentEntry(). 304 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); 305} 306 307#if defined(OS_POSIX) 308TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFd_RegularFile) { 309 ZipReader reader; 310 PlatformFileWrapper zip_fd_wrapper(test_zip_file_, 311 PlatformFileWrapper::READ_ONLY); 312 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); 313 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 314 base::FilePath out_path = test_dir_.AppendASCII("quux.txt"); 315 PlatformFileWrapper out_fd_w(out_path, PlatformFileWrapper::READ_WRITE); 316 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 317 ASSERT_TRUE(reader.ExtractCurrentEntryToFd(out_fd_w.platform_file())); 318 // Read the output file and compute the MD5. 319 std::string output; 320 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), 321 &output)); 322 const std::string md5 = base::MD5String(output); 323 EXPECT_EQ(kQuuxExpectedMD5, md5); 324 // quux.txt should be larger than kZipBufSize so that we can exercise 325 // the loop in ExtractCurrentEntry(). 326 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); 327} 328#endif 329 330TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) { 331 ZipReader reader; 332 ASSERT_TRUE(reader.Open(test_zip_file_)); 333 base::FilePath target_path(FILE_PATH_LITERAL("foo/")); 334 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 335 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( 336 test_dir_.AppendASCII("foo"))); 337 // The directory should be created. 338 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo"))); 339} 340 341TEST_F(ZipReaderTest, ExtractCurrentEntryIntoDirectory_RegularFile) { 342 ZipReader reader; 343 ASSERT_TRUE(reader.Open(test_zip_file_)); 344 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 345 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 346 ASSERT_TRUE(reader.ExtractCurrentEntryIntoDirectory(test_dir_)); 347 // Sub directories should be created. 348 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo/bar"))); 349 // And the file should be created. 350 std::string output; 351 ASSERT_TRUE(base::ReadFileToString( 352 test_dir_.AppendASCII("foo/bar/quux.txt"), &output)); 353 const std::string md5 = base::MD5String(output); 354 EXPECT_EQ(kQuuxExpectedMD5, md5); 355} 356 357TEST_F(ZipReaderTest, current_entry_info_RegularFile) { 358 ZipReader reader; 359 ASSERT_TRUE(reader.Open(test_zip_file_)); 360 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 361 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 362 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info(); 363 364 EXPECT_EQ(target_path, current_entry_info->file_path()); 365 EXPECT_EQ(13527, current_entry_info->original_size()); 366 367 // The expected time stamp: 2009-05-29 06:22:20 368 base::Time::Exploded exploded = {}; // Zero-clear. 369 current_entry_info->last_modified().LocalExplode(&exploded); 370 EXPECT_EQ(2009, exploded.year); 371 EXPECT_EQ(5, exploded.month); 372 EXPECT_EQ(29, exploded.day_of_month); 373 EXPECT_EQ(6, exploded.hour); 374 EXPECT_EQ(22, exploded.minute); 375 EXPECT_EQ(20, exploded.second); 376 EXPECT_EQ(0, exploded.millisecond); 377 378 EXPECT_FALSE(current_entry_info->is_unsafe()); 379 EXPECT_FALSE(current_entry_info->is_directory()); 380} 381 382TEST_F(ZipReaderTest, current_entry_info_DotDotFile) { 383 ZipReader reader; 384 ASSERT_TRUE(reader.Open(evil_zip_file_)); 385 base::FilePath target_path(FILE_PATH_LITERAL( 386 "../levilevilevilevilevilevilevilevilevilevilevilevil")); 387 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 388 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info(); 389 EXPECT_EQ(target_path, current_entry_info->file_path()); 390 391 // This file is unsafe because of ".." in the file name. 392 EXPECT_TRUE(current_entry_info->is_unsafe()); 393 EXPECT_FALSE(current_entry_info->is_directory()); 394} 395 396TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) { 397 ZipReader reader; 398 ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_)); 399 // The evil file is the 2nd file in the zip file. 400 // We cannot locate by the file name ".\x80.\\evil.txt", 401 // as FilePath may internally convert the string. 402 ASSERT_TRUE(reader.AdvanceToNextEntry()); 403 ASSERT_TRUE(reader.OpenCurrentEntryInZip()); 404 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info(); 405 406 // This file is unsafe because of invalid UTF-8 in the file name. 407 EXPECT_TRUE(current_entry_info->is_unsafe()); 408 EXPECT_FALSE(current_entry_info->is_directory()); 409} 410 411TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) { 412 ZipReader reader; 413 ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_)); 414 base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt")); 415 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 416 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info(); 417 EXPECT_EQ(target_path, current_entry_info->file_path()); 418 419 // This file is unsafe because of the absolute file name. 420 EXPECT_TRUE(current_entry_info->is_unsafe()); 421 EXPECT_FALSE(current_entry_info->is_directory()); 422} 423 424TEST_F(ZipReaderTest, current_entry_info_Directory) { 425 ZipReader reader; 426 ASSERT_TRUE(reader.Open(test_zip_file_)); 427 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/")); 428 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 429 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info(); 430 431 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")), 432 current_entry_info->file_path()); 433 // The directory size should be zero. 434 EXPECT_EQ(0, current_entry_info->original_size()); 435 436 // The expected time stamp: 2009-05-31 15:49:52 437 base::Time::Exploded exploded = {}; // Zero-clear. 438 current_entry_info->last_modified().LocalExplode(&exploded); 439 EXPECT_EQ(2009, exploded.year); 440 EXPECT_EQ(5, exploded.month); 441 EXPECT_EQ(31, exploded.day_of_month); 442 EXPECT_EQ(15, exploded.hour); 443 EXPECT_EQ(49, exploded.minute); 444 EXPECT_EQ(52, exploded.second); 445 EXPECT_EQ(0, exploded.millisecond); 446 447 EXPECT_FALSE(current_entry_info->is_unsafe()); 448 EXPECT_TRUE(current_entry_info->is_directory()); 449} 450 451// Verifies that the ZipReader class can extract a file from a zip archive 452// stored in memory. This test opens a zip archive in a std::string object, 453// extracts its content, and verifies the content is the same as the expected 454// text. 455TEST_F(ZipReaderTest, OpenFromString) { 456 // A zip archive consisting of one file "test.txt", which is a 16-byte text 457 // file that contains "This is a test.\n". 458 const char kTestData[] = 459 "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\xa4\x66\x24\x41\x13\xe8" 460 "\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00\x1c\x00\x74\x65" 461 "\x73\x74\x2e\x74\x78\x74\x55\x54\x09\x00\x03\x34\x89\x45\x50\x34" 462 "\x89\x45\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13" 463 "\x00\x00\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74" 464 "\x2e\x0a\x50\x4b\x01\x02\x1e\x03\x0a\x00\x00\x00\x00\x00\xa4\x66" 465 "\x24\x41\x13\xe8\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00" 466 "\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa4\x81\x00\x00\x00\x00" 467 "\x74\x65\x73\x74\x2e\x74\x78\x74\x55\x54\x05\x00\x03\x34\x89\x45" 468 "\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00" 469 "\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00" 470 "\x52\x00\x00\x00\x00\x00"; 471 std::string data(kTestData, arraysize(kTestData)); 472 ZipReader reader; 473 ASSERT_TRUE(reader.OpenFromString(data)); 474 base::FilePath target_path(FILE_PATH_LITERAL("test.txt")); 475 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 476 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( 477 test_dir_.AppendASCII("test.txt"))); 478 479 std::string actual; 480 ASSERT_TRUE(base::ReadFileToString( 481 test_dir_.AppendASCII("test.txt"), &actual)); 482 EXPECT_EQ(std::string("This is a test.\n"), actual); 483} 484 485// Verifies that the asynchronous extraction to a file works. 486TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) { 487 MockUnzipListener listener; 488 489 ZipReader reader; 490 base::FilePath target_file = test_dir_.AppendASCII("quux.txt"); 491 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); 492 ASSERT_TRUE(reader.Open(test_zip_file_)); 493 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 494 reader.ExtractCurrentEntryToFilePathAsync( 495 target_file, 496 base::Bind(&MockUnzipListener::OnUnzipSuccess, 497 listener.AsWeakPtr()), 498 base::Bind(&MockUnzipListener::OnUnzipFailure, 499 listener.AsWeakPtr()), 500 base::Bind(&MockUnzipListener::OnUnzipProgress, 501 listener.AsWeakPtr())); 502 503 EXPECT_EQ(0, listener.success_calls()); 504 EXPECT_EQ(0, listener.failure_calls()); 505 EXPECT_EQ(0, listener.progress_calls()); 506 507 base::RunLoop().RunUntilIdle(); 508 509 EXPECT_EQ(1, listener.success_calls()); 510 EXPECT_EQ(0, listener.failure_calls()); 511 EXPECT_LE(1, listener.progress_calls()); 512 513 std::string output; 514 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), 515 &output)); 516 const std::string md5 = base::MD5String(output); 517 EXPECT_EQ(kQuuxExpectedMD5, md5); 518 519 int64 file_size = 0; 520 ASSERT_TRUE(base::GetFileSize(target_file, &file_size)); 521 522 EXPECT_EQ(file_size, listener.current_progress()); 523} 524 525// Verifies that the asynchronous extraction to a file works. 526TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) { 527 MockUnzipListener listener; 528 529 ZipReader reader; 530 base::FilePath target_file = test_dir_.AppendASCII("foo"); 531 base::FilePath target_path(FILE_PATH_LITERAL("foo/")); 532 ASSERT_TRUE(reader.Open(test_zip_file_)); 533 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); 534 reader.ExtractCurrentEntryToFilePathAsync( 535 target_file, 536 base::Bind(&MockUnzipListener::OnUnzipSuccess, 537 listener.AsWeakPtr()), 538 base::Bind(&MockUnzipListener::OnUnzipFailure, 539 listener.AsWeakPtr()), 540 base::Bind(&MockUnzipListener::OnUnzipProgress, 541 listener.AsWeakPtr())); 542 543 EXPECT_EQ(0, listener.success_calls()); 544 EXPECT_EQ(0, listener.failure_calls()); 545 EXPECT_EQ(0, listener.progress_calls()); 546 547 base::RunLoop().RunUntilIdle(); 548 549 EXPECT_EQ(1, listener.success_calls()); 550 EXPECT_EQ(0, listener.failure_calls()); 551 EXPECT_GE(0, listener.progress_calls()); 552 553 ASSERT_TRUE(base::DirectoryExists(target_file)); 554} 555 556} // namespace zip 557