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"
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"
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"
26 const static std::string kQuuxExpectedMD5
= "d1ae4ac8a17a0e09317113ab284b57a6";
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
;
40 flags
|= base::File::FLAG_WRITE
| base::File::FLAG_CREATE_ALWAYS
;
42 file_
.Initialize(path
, flags
);
47 base::PlatformFile
platform_file() { return file_
.GetPlatformFile(); }
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.
56 class MockUnzipListener
: public base::SupportsWeakPtr
<MockUnzipListener
> {
62 current_progress_(0) {
65 // Success callback for async functions.
66 void OnUnzipSuccess() {
70 // Failure callback for async functions.
71 void OnUnzipFailure() {
75 // Progress callback for async functions.
76 void OnUnzipProgress(int64 progress
) {
77 DCHECK(progress
> current_progress_
);
79 current_progress_
= progress
;
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_
; }
92 int64 current_progress_
;
99 // Make the test a PlatformTest to setup autorelease pools properly on Mac.
100 class ZipReaderTest
: public PlatformTest
{
102 virtual void SetUp() {
103 PlatformTest::SetUp();
105 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
106 test_dir_
= temp_dir_
.path();
108 ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_
));
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");
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")));
130 virtual void TearDown() {
131 PlatformTest::TearDown();
134 bool GetTestDataDirectory(base::FilePath
* path
) {
135 bool success
= PathService::Get(base::DIR_SOURCE_ROOT
, path
);
136 EXPECT_TRUE(success
);
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");
147 bool CompareFileAndMD5(const base::FilePath
& path
,
148 const std::string expected_md5
) {
149 // Read the output file and compute the MD5.
151 if (!base::ReadFileToString(path
, &output
))
153 const std::string md5
= base::MD5String(output
);
154 return expected_md5
== md5
;
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_
;
171 base::ScopedTempDir temp_dir_
;
173 base::MessageLoop message_loop_
;
176 TEST_F(ZipReaderTest
, Open_ValidZipFile
) {
178 ASSERT_TRUE(reader
.Open(test_zip_file_
));
181 TEST_F(ZipReaderTest
, Open_ValidZipPlatformFile
) {
183 FileWrapper
zip_fd_wrapper(test_zip_file_
, FileWrapper::READ_ONLY
);
184 ASSERT_TRUE(reader
.OpenFromPlatformFile(zip_fd_wrapper
.platform_file()));
187 TEST_F(ZipReaderTest
, Open_NonExistentFile
) {
189 ASSERT_FALSE(reader
.Open(test_data_dir_
.AppendASCII("nonexistent.zip")));
192 TEST_F(ZipReaderTest
, Open_ExistentButNonZipFile
) {
194 ASSERT_FALSE(reader
.Open(test_data_dir_
.AppendASCII("create_test_zip.sh")));
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.
199 TEST_F(ZipReaderTest
, Iteration
) {
200 std::set
<base::FilePath
> actual_contents
;
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());
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
);
215 // Open the test zip file from a file descriptor, iterate through its contents,
216 // and compare that they match the expected contents.
217 TEST_F(ZipReaderTest
, PlatformFileIteration
) {
218 std::set
<base::FilePath
> actual_contents
;
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());
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
);
234 TEST_F(ZipReaderTest
, LocateAndOpenEntry_ValidFile
) {
235 std::set
<base::FilePath
> actual_contents
;
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());
243 TEST_F(ZipReaderTest
, LocateAndOpenEntry_NonExistentFile
) {
244 std::set
<base::FilePath
> actual_contents
;
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());
252 TEST_F(ZipReaderTest
, ExtractCurrentEntryToFilePath_RegularFile
) {
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.
261 ASSERT_TRUE(base::ReadFileToString(test_dir_
.AppendASCII("quux.txt"),
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());
270 TEST_F(ZipReaderTest
, PlatformFileExtractCurrentEntryToFilePath_RegularFile
) {
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.
280 ASSERT_TRUE(base::ReadFileToString(test_dir_
.AppendASCII("quux.txt"),
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());
289 #if defined(OS_POSIX)
290 TEST_F(ZipReaderTest
, PlatformFileExtractCurrentEntryToFd_RegularFile
) {
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.
301 ASSERT_TRUE(base::ReadFileToString(test_dir_
.AppendASCII("quux.txt"),
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());
311 TEST_F(ZipReaderTest
, ExtractCurrentEntryToFilePath_Directory
) {
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")));
322 TEST_F(ZipReaderTest
, ExtractCurrentEntryIntoDirectory_RegularFile
) {
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.
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
);
338 TEST_F(ZipReaderTest
, current_entry_info_RegularFile
) {
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();
345 EXPECT_EQ(target_path
, current_entry_info
->file_path());
346 EXPECT_EQ(13527, current_entry_info
->original_size());
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
);
359 EXPECT_FALSE(current_entry_info
->is_unsafe());
360 EXPECT_FALSE(current_entry_info
->is_directory());
363 TEST_F(ZipReaderTest
, current_entry_info_DotDotFile
) {
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());
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());
377 TEST_F(ZipReaderTest
, current_entry_info_InvalidUTF8File
) {
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();
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());
392 TEST_F(ZipReaderTest
, current_entry_info_AbsoluteFile
) {
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());
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());
405 TEST_F(ZipReaderTest
, current_entry_info_Directory
) {
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();
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());
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
);
428 EXPECT_FALSE(current_entry_info
->is_unsafe());
429 EXPECT_TRUE(current_entry_info
->is_directory());
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
436 TEST_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
));
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")));
461 ASSERT_TRUE(base::ReadFileToString(
462 test_dir_
.AppendASCII("test.txt"), &actual
));
463 EXPECT_EQ(std::string("This is a test.\n"), actual
);
466 // Verifies that the asynchronous extraction to a file works.
467 TEST_F(ZipReaderTest
, ExtractToFileAsync_RegularFile
) {
468 MockUnzipListener listener
;
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(
477 base::Bind(&MockUnzipListener::OnUnzipSuccess
,
478 listener
.AsWeakPtr()),
479 base::Bind(&MockUnzipListener::OnUnzipFailure
,
480 listener
.AsWeakPtr()),
481 base::Bind(&MockUnzipListener::OnUnzipProgress
,
482 listener
.AsWeakPtr()));
484 EXPECT_EQ(0, listener
.success_calls());
485 EXPECT_EQ(0, listener
.failure_calls());
486 EXPECT_EQ(0, listener
.progress_calls());
488 base::RunLoop().RunUntilIdle();
490 EXPECT_EQ(1, listener
.success_calls());
491 EXPECT_EQ(0, listener
.failure_calls());
492 EXPECT_LE(1, listener
.progress_calls());
495 ASSERT_TRUE(base::ReadFileToString(test_dir_
.AppendASCII("quux.txt"),
497 const std::string md5
= base::MD5String(output
);
498 EXPECT_EQ(kQuuxExpectedMD5
, md5
);
501 ASSERT_TRUE(base::GetFileSize(target_file
, &file_size
));
503 EXPECT_EQ(file_size
, listener
.current_progress());
506 // Verifies that the asynchronous extraction to a file works.
507 TEST_F(ZipReaderTest
, ExtractToFileAsync_Directory
) {
508 MockUnzipListener listener
;
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(
517 base::Bind(&MockUnzipListener::OnUnzipSuccess
,
518 listener
.AsWeakPtr()),
519 base::Bind(&MockUnzipListener::OnUnzipFailure
,
520 listener
.AsWeakPtr()),
521 base::Bind(&MockUnzipListener::OnUnzipProgress
,
522 listener
.AsWeakPtr()));
524 EXPECT_EQ(0, listener
.success_calls());
525 EXPECT_EQ(0, listener
.failure_calls());
526 EXPECT_EQ(0, listener
.progress_calls());
528 base::RunLoop().RunUntilIdle();
530 EXPECT_EQ(1, listener
.success_calls());
531 EXPECT_EQ(0, listener
.failure_calls());
532 EXPECT_GE(0, listener
.progress_calls());
534 ASSERT_TRUE(base::DirectoryExists(target_file
));