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