OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "third_party/zlib/google/zip_reader.h" | 5 #include "third_party/zlib/google/zip_reader.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/files/file.h" | 11 #include "base/files/file.h" |
12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
13 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/md5.h" | 15 #include "base/md5.h" |
16 #include "base/path_service.h" | 16 #include "base/path_service.h" |
17 #include "base/run_loop.h" | 17 #include "base/run_loop.h" |
18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
21 #include "testing/gmock/include/gmock/gmock.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
23 #include "testing/platform_test.h" | 22 #include "testing/platform_test.h" |
24 #include "third_party/zlib/google/zip_internal.h" | 23 #include "third_party/zlib/google/zip_internal.h" |
25 | 24 |
26 using ::testing::Return; | |
27 using ::testing::_; | |
28 | |
29 namespace { | 25 namespace { |
30 | 26 |
31 const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6"; | 27 const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6"; |
32 | 28 |
33 class FileWrapper { | 29 class FileWrapper { |
34 public: | 30 public: |
35 typedef enum { | 31 typedef enum { |
36 READ_ONLY, | 32 READ_ONLY, |
37 READ_WRITE | 33 READ_WRITE |
38 } AccessMode; | 34 } AccessMode; |
39 | 35 |
40 FileWrapper(const base::FilePath& path, AccessMode mode) { | 36 FileWrapper(const base::FilePath& path, AccessMode mode) { |
41 int flags = base::File::FLAG_READ; | 37 int flags = base::File::FLAG_READ; |
42 if (mode == READ_ONLY) | 38 if (mode == READ_ONLY) |
43 flags |= base::File::FLAG_OPEN; | 39 flags |= base::File::FLAG_OPEN; |
44 else | 40 else |
45 flags |= base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS; | 41 flags |= base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS; |
46 | 42 |
47 file_.Initialize(path, flags); | 43 file_.Initialize(path, flags); |
48 } | 44 } |
49 | 45 |
50 ~FileWrapper() {} | 46 ~FileWrapper() {} |
51 | 47 |
52 base::PlatformFile platform_file() { return file_.GetPlatformFile(); } | 48 base::PlatformFile platform_file() { return file_.GetPlatformFile(); } |
53 | 49 |
54 base::File* file() { return &file_; } | |
55 | |
56 private: | 50 private: |
57 base::File file_; | 51 base::File file_; |
58 }; | 52 }; |
59 | 53 |
60 // A mock that provides methods that can be used as callbacks in asynchronous | 54 // 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. | 55 // unzip functions. Tracks the number of calls and number of bytes reported. |
62 // Assumes that progress callbacks will be executed in-order. | 56 // Assumes that progress callbacks will be executed in-order. |
63 class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> { | 57 class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> { |
64 public: | 58 public: |
65 MockUnzipListener() | 59 MockUnzipListener() |
(...skipping 26 matching lines...) Expand all Loading... |
92 int current_progress() { return current_progress_; } | 86 int current_progress() { return current_progress_; } |
93 | 87 |
94 private: | 88 private: |
95 int success_calls_; | 89 int success_calls_; |
96 int failure_calls_; | 90 int failure_calls_; |
97 int progress_calls_; | 91 int progress_calls_; |
98 | 92 |
99 int64 current_progress_; | 93 int64 current_progress_; |
100 }; | 94 }; |
101 | 95 |
102 class MockWriterDelegate : public zip::WriterDelegate { | |
103 public: | |
104 MOCK_METHOD0(PrepareOutput, bool()); | |
105 MOCK_METHOD2(WriteBytes, bool(const char*, int)); | |
106 }; | |
107 | |
108 } // namespace | 96 } // namespace |
109 | 97 |
110 namespace zip { | 98 namespace zip { |
111 | 99 |
112 // Make the test a PlatformTest to setup autorelease pools properly on Mac. | 100 // Make the test a PlatformTest to setup autorelease pools properly on Mac. |
113 class ZipReaderTest : public PlatformTest { | 101 class ZipReaderTest : public PlatformTest { |
114 protected: | 102 protected: |
115 virtual void SetUp() { | 103 virtual void SetUp() { |
116 PlatformTest::SetUp(); | 104 PlatformTest::SetUp(); |
117 | 105 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 std::string output; | 280 std::string output; |
293 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), | 281 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), |
294 &output)); | 282 &output)); |
295 const std::string md5 = base::MD5String(output); | 283 const std::string md5 = base::MD5String(output); |
296 EXPECT_EQ(kQuuxExpectedMD5, md5); | 284 EXPECT_EQ(kQuuxExpectedMD5, md5); |
297 // quux.txt should be larger than kZipBufSize so that we can exercise | 285 // quux.txt should be larger than kZipBufSize so that we can exercise |
298 // the loop in ExtractCurrentEntry(). | 286 // the loop in ExtractCurrentEntry(). |
299 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); | 287 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); |
300 } | 288 } |
301 | 289 |
302 TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFile_RegularFile) { | 290 #if defined(OS_POSIX) |
| 291 TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFd_RegularFile) { |
303 ZipReader reader; | 292 ZipReader reader; |
304 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY); | 293 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY); |
305 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); | 294 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); |
306 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); | 295 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); |
307 base::FilePath out_path = test_dir_.AppendASCII("quux.txt"); | 296 base::FilePath out_path = test_dir_.AppendASCII("quux.txt"); |
308 FileWrapper out_fd_w(out_path, FileWrapper::READ_WRITE); | 297 FileWrapper out_fd_w(out_path, FileWrapper::READ_WRITE); |
309 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); | 298 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); |
310 ASSERT_TRUE(reader.ExtractCurrentEntryToFile(out_fd_w.file())); | 299 ASSERT_TRUE(reader.ExtractCurrentEntryToFd(out_fd_w.platform_file())); |
311 // Read the output file and compute the MD5. | 300 // Read the output file and compute the MD5. |
312 std::string output; | 301 std::string output; |
313 ASSERT_TRUE(base::ReadFileToString(out_path, &output)); | 302 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), |
| 303 &output)); |
314 const std::string md5 = base::MD5String(output); | 304 const std::string md5 = base::MD5String(output); |
315 EXPECT_EQ(kQuuxExpectedMD5, md5); | 305 EXPECT_EQ(kQuuxExpectedMD5, md5); |
316 // quux.txt should be larger than kZipBufSize so that we can exercise | 306 // quux.txt should be larger than kZipBufSize so that we can exercise |
317 // the loop in ExtractCurrentEntry(). | 307 // the loop in ExtractCurrentEntry(). |
318 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); | 308 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size()); |
319 } | 309 } |
| 310 #endif |
320 | 311 |
321 TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) { | 312 TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) { |
322 ZipReader reader; | 313 ZipReader reader; |
323 ASSERT_TRUE(reader.Open(test_zip_file_)); | 314 ASSERT_TRUE(reader.Open(test_zip_file_)); |
324 base::FilePath target_path(FILE_PATH_LITERAL("foo/")); | 315 base::FilePath target_path(FILE_PATH_LITERAL("foo/")); |
325 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); | 316 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); |
326 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( | 317 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath( |
327 test_dir_.AppendASCII("foo"))); | 318 test_dir_.AppendASCII("foo"))); |
328 // The directory should be created. | 319 // The directory should be created. |
329 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo"))); | 320 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo"))); |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 | 575 |
585 // This test exposes http://crbug.com/430959, at least on OS X | 576 // This test exposes http://crbug.com/430959, at least on OS X |
586 TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) { | 577 TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) { |
587 for (int i = 0; i < 100000; ++i) { | 578 for (int i = 0; i < 100000; ++i) { |
588 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY); | 579 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY); |
589 ZipReader reader; | 580 ZipReader reader; |
590 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); | 581 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); |
591 } | 582 } |
592 } | 583 } |
593 | 584 |
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; | |
598 | |
599 EXPECT_CALL(mock_writer, PrepareOutput()) | |
600 .WillOnce(Return(false)); | |
601 | |
602 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); | |
603 ZipReader reader; | |
604 | |
605 ASSERT_TRUE(reader.Open(test_zip_file_)); | |
606 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); | |
607 ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer)); | |
608 } | |
609 | |
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; | |
614 | |
615 EXPECT_CALL(mock_writer, PrepareOutput()) | |
616 .WillOnce(Return(true)); | |
617 EXPECT_CALL(mock_writer, WriteBytes(_, _)) | |
618 .WillOnce(Return(false)); | |
619 | |
620 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); | |
621 ZipReader reader; | |
622 | |
623 ASSERT_TRUE(reader.Open(test_zip_file_)); | |
624 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); | |
625 ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer)); | |
626 } | |
627 | |
628 // Test that extraction succeeds when the writer delegate reports all is well. | |
629 TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) { | |
630 testing::StrictMock<MockWriterDelegate> mock_writer; | |
631 | |
632 EXPECT_CALL(mock_writer, PrepareOutput()) | |
633 .WillOnce(Return(true)); | |
634 EXPECT_CALL(mock_writer, WriteBytes(_, _)) | |
635 .WillRepeatedly(Return(true)); | |
636 | |
637 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt")); | |
638 ZipReader reader; | |
639 | |
640 ASSERT_TRUE(reader.Open(test_zip_file_)); | |
641 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path)); | |
642 ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer)); | |
643 } | |
644 | |
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()); | |
655 } | |
656 | |
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)); | |
663 } | |
664 | |
665 base::FilePath temp_file_path_; | |
666 base::File file_; | |
667 }; | |
668 | |
669 TEST_F(FileWriterDelegateTest, WriteToStartAndTruncate) { | |
670 // Write stuff and advance. | |
671 PopulateFile(); | |
672 | |
673 // This should rewind, write, then truncate. | |
674 static const char kSomeData[] = "short"; | |
675 static const int kSomeDataLen = sizeof(kSomeData) - 1; | |
676 { | |
677 FileWriterDelegate writer(&file_); | |
678 ASSERT_TRUE(writer.PrepareOutput()); | |
679 ASSERT_TRUE(writer.WriteBytes(kSomeData, kSomeDataLen)); | |
680 } | |
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)); | |
685 } | |
686 | |
687 } // namespace zip | 585 } // namespace zip |
OLD | NEW |