blob: a137d9dd1bc0b85fb80740f12799eb44f28f9d37 [file] [log] [blame]
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +00001// 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
haven@chromium.org84ed2652014-01-17 00:36:28 +000010#include "base/bind.h"
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000011#include "base/file_util.h"
rvargas@chromium.org0d737652014-02-27 05:58:13 +000012#include "base/files/file.h"
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000013#include "base/files/scoped_temp_dir.h"
14#include "base/logging.h"
15#include "base/md5.h"
16#include "base/path_service.h"
haven@chromium.org84ed2652014-01-17 00:36:28 +000017#include "base/run_loop.h"
joaoe@opera.com00024292014-06-20 18:12:13 +000018#include "base/strings/stringprintf.h"
avi@chromium.org5cb24772013-06-07 22:40:45 +000019#include "base/strings/utf_string_conversions.h"
avi@chromium.org47f1b552013-06-28 15:23:55 +000020#include "base/time/time.h"
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000021#include "testing/gtest/include/gtest/gtest.h"
22#include "testing/platform_test.h"
23#include "third_party/zlib/google/zip_internal.h"
24
25namespace {
26
haven@chromium.org84ed2652014-01-17 00:36:28 +000027const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
28
rvargas@chromium.org0d737652014-02-27 05:58:13 +000029class FileWrapper {
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000030 public:
31 typedef enum {
32 READ_ONLY,
33 READ_WRITE
34 } AccessMode;
35
rvargas@chromium.org0d737652014-02-27 05:58:13 +000036 FileWrapper(const base::FilePath& path, AccessMode mode) {
37 int flags = base::File::FLAG_READ;
38 if (mode == READ_ONLY)
39 flags |= base::File::FLAG_OPEN;
40 else
41 flags |= base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS;
42
43 file_.Initialize(path, flags);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000044 }
45
rvargas@chromium.org0d737652014-02-27 05:58:13 +000046 ~FileWrapper() {}
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000047
rvargas@chromium.org0d737652014-02-27 05:58:13 +000048 base::PlatformFile platform_file() { return file_.GetPlatformFile(); }
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000049
50 private:
rvargas@chromium.org0d737652014-02-27 05:58:13 +000051 base::File file_;
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000052};
53
haven@chromium.org84ed2652014-01-17 00:36:28 +000054// A mock that provides methods that can be used as callbacks in asynchronous
55// unzip functions. Tracks the number of calls and number of bytes reported.
56// Assumes that progress callbacks will be executed in-order.
57class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> {
58 public:
rvargas@chromium.org0d737652014-02-27 05:58:13 +000059 MockUnzipListener()
haven@chromium.org84ed2652014-01-17 00:36:28 +000060 : success_calls_(0),
61 failure_calls_(0),
62 progress_calls_(0),
63 current_progress_(0) {
64 }
65
66 // Success callback for async functions.
67 void OnUnzipSuccess() {
68 success_calls_++;
69 }
70
71 // Failure callback for async functions.
72 void OnUnzipFailure() {
73 failure_calls_++;
74 }
75
76 // Progress callback for async functions.
77 void OnUnzipProgress(int64 progress) {
78 DCHECK(progress > current_progress_);
79 progress_calls_++;
80 current_progress_ = progress;
81 }
82
83 int success_calls() { return success_calls_; }
84 int failure_calls() { return failure_calls_; }
85 int progress_calls() { return progress_calls_; }
86 int current_progress() { return current_progress_; }
87
88 private:
89 int success_calls_;
90 int failure_calls_;
91 int progress_calls_;
92
93 int64 current_progress_;
94};
95
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +000096} // namespace
97
98namespace zip {
99
100// Make the test a PlatformTest to setup autorelease pools properly on Mac.
101class ZipReaderTest : public PlatformTest {
102 protected:
103 virtual void SetUp() {
104 PlatformTest::SetUp();
105
106 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
107 test_dir_ = temp_dir_.path();
108
109 ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_));
110
111 test_zip_file_ = test_data_dir_.AppendASCII("test.zip");
112 evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip");
113 evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII(
114 "evil_via_invalid_utf8.zip");
115 evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII(
116 "evil_via_absolute_file_name.zip");
117
118 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/")));
119 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/")));
120 test_zip_contents_.insert(
121 base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")));
122 test_zip_contents_.insert(
123 base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
124 test_zip_contents_.insert(
125 base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")));
126 test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
127 test_zip_contents_.insert(
128 base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
129 }
130
131 virtual void TearDown() {
132 PlatformTest::TearDown();
133 }
134
135 bool GetTestDataDirectory(base::FilePath* path) {
136 bool success = PathService::Get(base::DIR_SOURCE_ROOT, path);
137 EXPECT_TRUE(success);
138 if (!success)
139 return false;
140 *path = path->AppendASCII("third_party");
141 *path = path->AppendASCII("zlib");
142 *path = path->AppendASCII("google");
143 *path = path->AppendASCII("test");
144 *path = path->AppendASCII("data");
145 return true;
146 }
147
haven@chromium.org84ed2652014-01-17 00:36:28 +0000148 bool CompareFileAndMD5(const base::FilePath& path,
149 const std::string expected_md5) {
150 // Read the output file and compute the MD5.
151 std::string output;
152 if (!base::ReadFileToString(path, &output))
153 return false;
154 const std::string md5 = base::MD5String(output);
155 return expected_md5 == md5;
156 }
157
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000158 // The path to temporary directory used to contain the test operations.
159 base::FilePath test_dir_;
160 // The path to the test data directory where test.zip etc. are located.
161 base::FilePath test_data_dir_;
162 // The path to test.zip in the test data directory.
163 base::FilePath test_zip_file_;
164 // The path to evil.zip in the test data directory.
165 base::FilePath evil_zip_file_;
166 // The path to evil_via_invalid_utf8.zip in the test data directory.
167 base::FilePath evil_via_invalid_utf8_zip_file_;
168 // The path to evil_via_absolute_file_name.zip in the test data directory.
169 base::FilePath evil_via_absolute_file_name_zip_file_;
170 std::set<base::FilePath> test_zip_contents_;
171
172 base::ScopedTempDir temp_dir_;
haven@chromium.org84ed2652014-01-17 00:36:28 +0000173
174 base::MessageLoop message_loop_;
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000175};
176
177TEST_F(ZipReaderTest, Open_ValidZipFile) {
178 ZipReader reader;
179 ASSERT_TRUE(reader.Open(test_zip_file_));
180}
181
182TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) {
183 ZipReader reader;
rvargas@chromium.org0d737652014-02-27 05:58:13 +0000184 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000185 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
186}
187
188TEST_F(ZipReaderTest, Open_NonExistentFile) {
189 ZipReader reader;
190 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip")));
191}
192
193TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) {
194 ZipReader reader;
195 ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh")));
196}
197
198// Iterate through the contents in the test zip file, and compare that the
199// contents collected from the zip reader matches the expected contents.
200TEST_F(ZipReaderTest, Iteration) {
201 std::set<base::FilePath> actual_contents;
202 ZipReader reader;
203 ASSERT_TRUE(reader.Open(test_zip_file_));
204 while (reader.HasMore()) {
205 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
206 actual_contents.insert(reader.current_entry_info()->file_path());
207 ASSERT_TRUE(reader.AdvanceToNextEntry());
208 }
209 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
210 EXPECT_EQ(test_zip_contents_.size(),
211 static_cast<size_t>(reader.num_entries()));
212 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
213 EXPECT_EQ(test_zip_contents_, actual_contents);
214}
215
216// Open the test zip file from a file descriptor, iterate through its contents,
217// and compare that they match the expected contents.
218TEST_F(ZipReaderTest, PlatformFileIteration) {
219 std::set<base::FilePath> actual_contents;
220 ZipReader reader;
rvargas@chromium.org0d737652014-02-27 05:58:13 +0000221 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000222 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
223 while (reader.HasMore()) {
224 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
225 actual_contents.insert(reader.current_entry_info()->file_path());
226 ASSERT_TRUE(reader.AdvanceToNextEntry());
227 }
228 EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
229 EXPECT_EQ(test_zip_contents_.size(),
230 static_cast<size_t>(reader.num_entries()));
231 EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
232 EXPECT_EQ(test_zip_contents_, actual_contents);
233}
234
235TEST_F(ZipReaderTest, LocateAndOpenEntry_ValidFile) {
236 std::set<base::FilePath> actual_contents;
237 ZipReader reader;
238 ASSERT_TRUE(reader.Open(test_zip_file_));
239 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
240 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
241 EXPECT_EQ(target_path, reader.current_entry_info()->file_path());
242}
243
244TEST_F(ZipReaderTest, LocateAndOpenEntry_NonExistentFile) {
245 std::set<base::FilePath> actual_contents;
246 ZipReader reader;
247 ASSERT_TRUE(reader.Open(test_zip_file_));
248 base::FilePath target_path(FILE_PATH_LITERAL("nonexistent.txt"));
249 ASSERT_FALSE(reader.LocateAndOpenEntry(target_path));
250 EXPECT_EQ(NULL, reader.current_entry_info());
251}
252
253TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_RegularFile) {
254 ZipReader reader;
255 ASSERT_TRUE(reader.Open(test_zip_file_));
256 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
257 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
258 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
259 test_dir_.AppendASCII("quux.txt")));
260 // Read the output file ans compute the MD5.
261 std::string output;
brettw@chromium.org997408f2013-08-30 18:23:50 +0000262 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
263 &output));
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000264 const std::string md5 = base::MD5String(output);
haven@chromium.org84ed2652014-01-17 00:36:28 +0000265 EXPECT_EQ(kQuuxExpectedMD5, md5);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000266 // quux.txt should be larger than kZipBufSize so that we can exercise
267 // the loop in ExtractCurrentEntry().
268 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
269}
270
271TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFilePath_RegularFile) {
272 ZipReader reader;
rvargas@chromium.org0d737652014-02-27 05:58:13 +0000273 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000274 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
275 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
276 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
277 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
278 test_dir_.AppendASCII("quux.txt")));
279 // Read the output file and compute the MD5.
280 std::string output;
brettw@chromium.org997408f2013-08-30 18:23:50 +0000281 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
282 &output));
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000283 const std::string md5 = base::MD5String(output);
haven@chromium.org84ed2652014-01-17 00:36:28 +0000284 EXPECT_EQ(kQuuxExpectedMD5, md5);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000285 // quux.txt should be larger than kZipBufSize so that we can exercise
286 // the loop in ExtractCurrentEntry().
287 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
288}
289
290#if defined(OS_POSIX)
291TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFd_RegularFile) {
292 ZipReader reader;
rvargas@chromium.org0d737652014-02-27 05:58:13 +0000293 FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000294 ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
295 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
296 base::FilePath out_path = test_dir_.AppendASCII("quux.txt");
rvargas@chromium.org0d737652014-02-27 05:58:13 +0000297 FileWrapper out_fd_w(out_path, FileWrapper::READ_WRITE);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000298 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
299 ASSERT_TRUE(reader.ExtractCurrentEntryToFd(out_fd_w.platform_file()));
300 // Read the output file and compute the MD5.
301 std::string output;
brettw@chromium.org997408f2013-08-30 18:23:50 +0000302 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
303 &output));
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000304 const std::string md5 = base::MD5String(output);
haven@chromium.org84ed2652014-01-17 00:36:28 +0000305 EXPECT_EQ(kQuuxExpectedMD5, md5);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000306 // quux.txt should be larger than kZipBufSize so that we can exercise
307 // the loop in ExtractCurrentEntry().
308 EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
309}
310#endif
311
312TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) {
313 ZipReader reader;
314 ASSERT_TRUE(reader.Open(test_zip_file_));
315 base::FilePath target_path(FILE_PATH_LITERAL("foo/"));
316 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
317 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
318 test_dir_.AppendASCII("foo")));
319 // The directory should be created.
brettw@chromium.org9a352f62013-07-15 20:18:09 +0000320 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo")));
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000321}
322
323TEST_F(ZipReaderTest, ExtractCurrentEntryIntoDirectory_RegularFile) {
324 ZipReader reader;
325 ASSERT_TRUE(reader.Open(test_zip_file_));
326 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
327 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
328 ASSERT_TRUE(reader.ExtractCurrentEntryIntoDirectory(test_dir_));
329 // Sub directories should be created.
brettw@chromium.org9a352f62013-07-15 20:18:09 +0000330 ASSERT_TRUE(base::DirectoryExists(test_dir_.AppendASCII("foo/bar")));
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000331 // And the file should be created.
332 std::string output;
brettw@chromium.org997408f2013-08-30 18:23:50 +0000333 ASSERT_TRUE(base::ReadFileToString(
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000334 test_dir_.AppendASCII("foo/bar/quux.txt"), &output));
335 const std::string md5 = base::MD5String(output);
haven@chromium.org84ed2652014-01-17 00:36:28 +0000336 EXPECT_EQ(kQuuxExpectedMD5, md5);
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000337}
338
339TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
340 ZipReader reader;
341 ASSERT_TRUE(reader.Open(test_zip_file_));
342 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
343 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
344 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
345
346 EXPECT_EQ(target_path, current_entry_info->file_path());
347 EXPECT_EQ(13527, current_entry_info->original_size());
348
349 // The expected time stamp: 2009-05-29 06:22:20
350 base::Time::Exploded exploded = {}; // Zero-clear.
351 current_entry_info->last_modified().LocalExplode(&exploded);
352 EXPECT_EQ(2009, exploded.year);
353 EXPECT_EQ(5, exploded.month);
354 EXPECT_EQ(29, exploded.day_of_month);
355 EXPECT_EQ(6, exploded.hour);
356 EXPECT_EQ(22, exploded.minute);
357 EXPECT_EQ(20, exploded.second);
358 EXPECT_EQ(0, exploded.millisecond);
359
360 EXPECT_FALSE(current_entry_info->is_unsafe());
361 EXPECT_FALSE(current_entry_info->is_directory());
362}
363
364TEST_F(ZipReaderTest, current_entry_info_DotDotFile) {
365 ZipReader reader;
366 ASSERT_TRUE(reader.Open(evil_zip_file_));
367 base::FilePath target_path(FILE_PATH_LITERAL(
368 "../levilevilevilevilevilevilevilevilevilevilevilevil"));
369 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
370 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
371 EXPECT_EQ(target_path, current_entry_info->file_path());
372
373 // This file is unsafe because of ".." in the file name.
374 EXPECT_TRUE(current_entry_info->is_unsafe());
375 EXPECT_FALSE(current_entry_info->is_directory());
376}
377
378TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) {
379 ZipReader reader;
380 ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_));
381 // The evil file is the 2nd file in the zip file.
382 // We cannot locate by the file name ".\x80.\\evil.txt",
383 // as FilePath may internally convert the string.
384 ASSERT_TRUE(reader.AdvanceToNextEntry());
385 ASSERT_TRUE(reader.OpenCurrentEntryInZip());
386 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
387
388 // This file is unsafe because of invalid UTF-8 in the file name.
389 EXPECT_TRUE(current_entry_info->is_unsafe());
390 EXPECT_FALSE(current_entry_info->is_directory());
391}
392
393TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) {
394 ZipReader reader;
395 ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_));
396 base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt"));
397 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
398 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
399 EXPECT_EQ(target_path, current_entry_info->file_path());
400
401 // This file is unsafe because of the absolute file name.
402 EXPECT_TRUE(current_entry_info->is_unsafe());
403 EXPECT_FALSE(current_entry_info->is_directory());
404}
405
406TEST_F(ZipReaderTest, current_entry_info_Directory) {
407 ZipReader reader;
408 ASSERT_TRUE(reader.Open(test_zip_file_));
409 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/"));
410 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
411 ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
412
413 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
414 current_entry_info->file_path());
415 // The directory size should be zero.
416 EXPECT_EQ(0, current_entry_info->original_size());
417
418 // The expected time stamp: 2009-05-31 15:49:52
419 base::Time::Exploded exploded = {}; // Zero-clear.
420 current_entry_info->last_modified().LocalExplode(&exploded);
421 EXPECT_EQ(2009, exploded.year);
422 EXPECT_EQ(5, exploded.month);
423 EXPECT_EQ(31, exploded.day_of_month);
424 EXPECT_EQ(15, exploded.hour);
425 EXPECT_EQ(49, exploded.minute);
426 EXPECT_EQ(52, exploded.second);
427 EXPECT_EQ(0, exploded.millisecond);
428
429 EXPECT_FALSE(current_entry_info->is_unsafe());
430 EXPECT_TRUE(current_entry_info->is_directory());
431}
432
433// Verifies that the ZipReader class can extract a file from a zip archive
434// stored in memory. This test opens a zip archive in a std::string object,
435// extracts its content, and verifies the content is the same as the expected
436// text.
437TEST_F(ZipReaderTest, OpenFromString) {
438 // A zip archive consisting of one file "test.txt", which is a 16-byte text
439 // file that contains "This is a test.\n".
440 const char kTestData[] =
441 "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\xa4\x66\x24\x41\x13\xe8"
442 "\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00\x1c\x00\x74\x65"
443 "\x73\x74\x2e\x74\x78\x74\x55\x54\x09\x00\x03\x34\x89\x45\x50\x34"
444 "\x89\x45\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13"
445 "\x00\x00\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74"
446 "\x2e\x0a\x50\x4b\x01\x02\x1e\x03\x0a\x00\x00\x00\x00\x00\xa4\x66"
447 "\x24\x41\x13\xe8\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00"
448 "\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa4\x81\x00\x00\x00\x00"
449 "\x74\x65\x73\x74\x2e\x74\x78\x74\x55\x54\x05\x00\x03\x34\x89\x45"
450 "\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00"
451 "\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00"
452 "\x52\x00\x00\x00\x00\x00";
453 std::string data(kTestData, arraysize(kTestData));
454 ZipReader reader;
455 ASSERT_TRUE(reader.OpenFromString(data));
456 base::FilePath target_path(FILE_PATH_LITERAL("test.txt"));
457 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
458 ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
459 test_dir_.AppendASCII("test.txt")));
460
461 std::string actual;
brettw@chromium.org997408f2013-08-30 18:23:50 +0000462 ASSERT_TRUE(base::ReadFileToString(
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000463 test_dir_.AppendASCII("test.txt"), &actual));
464 EXPECT_EQ(std::string("This is a test.\n"), actual);
465}
466
haven@chromium.org84ed2652014-01-17 00:36:28 +0000467// Verifies that the asynchronous extraction to a file works.
468TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
469 MockUnzipListener listener;
470
471 ZipReader reader;
472 base::FilePath target_file = test_dir_.AppendASCII("quux.txt");
473 base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
474 ASSERT_TRUE(reader.Open(test_zip_file_));
475 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
476 reader.ExtractCurrentEntryToFilePathAsync(
477 target_file,
478 base::Bind(&MockUnzipListener::OnUnzipSuccess,
479 listener.AsWeakPtr()),
480 base::Bind(&MockUnzipListener::OnUnzipFailure,
481 listener.AsWeakPtr()),
482 base::Bind(&MockUnzipListener::OnUnzipProgress,
483 listener.AsWeakPtr()));
484
485 EXPECT_EQ(0, listener.success_calls());
486 EXPECT_EQ(0, listener.failure_calls());
487 EXPECT_EQ(0, listener.progress_calls());
488
489 base::RunLoop().RunUntilIdle();
490
491 EXPECT_EQ(1, listener.success_calls());
492 EXPECT_EQ(0, listener.failure_calls());
493 EXPECT_LE(1, listener.progress_calls());
494
495 std::string output;
496 ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
497 &output));
498 const std::string md5 = base::MD5String(output);
499 EXPECT_EQ(kQuuxExpectedMD5, md5);
500
501 int64 file_size = 0;
502 ASSERT_TRUE(base::GetFileSize(target_file, &file_size));
503
504 EXPECT_EQ(file_size, listener.current_progress());
505}
506
507// Verifies that the asynchronous extraction to a file works.
508TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) {
509 MockUnzipListener listener;
510
511 ZipReader reader;
512 base::FilePath target_file = test_dir_.AppendASCII("foo");
513 base::FilePath target_path(FILE_PATH_LITERAL("foo/"));
514 ASSERT_TRUE(reader.Open(test_zip_file_));
515 ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
516 reader.ExtractCurrentEntryToFilePathAsync(
517 target_file,
518 base::Bind(&MockUnzipListener::OnUnzipSuccess,
519 listener.AsWeakPtr()),
520 base::Bind(&MockUnzipListener::OnUnzipFailure,
521 listener.AsWeakPtr()),
522 base::Bind(&MockUnzipListener::OnUnzipProgress,
523 listener.AsWeakPtr()));
524
525 EXPECT_EQ(0, listener.success_calls());
526 EXPECT_EQ(0, listener.failure_calls());
527 EXPECT_EQ(0, listener.progress_calls());
528
529 base::RunLoop().RunUntilIdle();
530
531 EXPECT_EQ(1, listener.success_calls());
532 EXPECT_EQ(0, listener.failure_calls());
533 EXPECT_GE(0, listener.progress_calls());
534
535 ASSERT_TRUE(base::DirectoryExists(target_file));
536}
537
joaoe@opera.com00024292014-06-20 18:12:13 +0000538TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
539 // test_mismatch_size.zip contains files with names from 0.txt to 7.txt with
540 // sizes from 0 to 7 bytes respectively, being the contents of each file a
541 // substring of "0123456" starting at '0'.
542 base::FilePath test_zip_file =
543 test_data_dir_.AppendASCII("test_mismatch_size.zip");
544
545 ZipReader reader;
546 std::string contents;
547 ASSERT_TRUE(reader.Open(test_zip_file));
548
549 for (size_t i = 0; i < 8; i++) {
550 SCOPED_TRACE(base::StringPrintf("Processing %d.txt", static_cast<int>(i)));
551
552 base::FilePath file_name = base::FilePath::FromUTF8Unsafe(
553 base::StringPrintf("%d.txt", static_cast<int>(i)));
554 ASSERT_TRUE(reader.LocateAndOpenEntry(file_name));
555
556 if (i > 1) {
557 // Off by one byte read limit: must fail.
558 EXPECT_FALSE(reader.ExtractCurrentEntryToString(i - 1, &contents));
559 }
560
561 if (i > 0) {
562 // Exact byte read limit: must pass.
563 EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents));
564 EXPECT_EQ(i, contents.size());
565 EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i));
566 }
567
568 // More than necessary byte read limit: must pass.
569 EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents));
570 EXPECT_EQ(i, contents.size());
571 EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i));
572 }
573 reader.Close();
574}
575
alecflett@chromium.orgd6d082e2013-05-03 23:02:57 +0000576} // namespace zip