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 <windows.h> 6 7 #include <fstream> 8 9 #include "base/base_paths.h" 10 #include "base/files/file_util.h" 11 #include "base/files/memory_mapped_file.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/path_service.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "chrome/installer/util/installer_util_test_common.h" 17 #include "chrome/installer/util/move_tree_work_item.h" 18 #include "chrome/installer/util/work_item.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace { 22 class MoveTreeWorkItemTest : public testing::Test { 23 protected: 24 virtual void SetUp() { 25 ASSERT_TRUE(temp_from_dir_.CreateUniqueTempDir()); 26 ASSERT_TRUE(temp_to_dir_.CreateUniqueTempDir()); 27 } 28 29 base::ScopedTempDir temp_from_dir_; 30 base::ScopedTempDir temp_to_dir_; 31 }; 32 33 // Simple function to dump some text into a new file. 34 void CreateTextFile(const std::wstring& filename, 35 const std::wstring& contents) { 36 std::wofstream file; 37 file.open(base::UTF16ToASCII(filename).c_str()); 38 ASSERT_TRUE(file.is_open()); 39 file << contents; 40 file.close(); 41 } 42 43 // Simple function to read text from a file. 44 std::wstring ReadTextFile(const base::FilePath& path) { 45 WCHAR contents[64]; 46 std::wifstream file; 47 file.open(base::UTF16ToASCII(path.value()).c_str()); 48 EXPECT_TRUE(file.is_open()); 49 file.getline(contents, arraysize(contents)); 50 file.close(); 51 return std::wstring(contents); 52 } 53 54 const wchar_t kTextContent1[] = L"Gooooooooooooooooooooogle"; 55 const wchar_t kTextContent2[] = L"Overwrite Me"; 56 }; // namespace 57 58 // Move one directory from source to destination when destination does not 59 // exist. 60 TEST_F(MoveTreeWorkItemTest, MoveDirectory) { 61 // Create two level deep source dir 62 base::FilePath from_dir1(temp_from_dir_.path()); 63 from_dir1 = from_dir1.AppendASCII("From_Dir1"); 64 base::CreateDirectory(from_dir1); 65 ASSERT_TRUE(base::PathExists(from_dir1)); 66 67 base::FilePath from_dir2(from_dir1); 68 from_dir2 = from_dir2.AppendASCII("From_Dir2"); 69 base::CreateDirectory(from_dir2); 70 ASSERT_TRUE(base::PathExists(from_dir2)); 71 72 base::FilePath from_file(from_dir2); 73 from_file = from_file.AppendASCII("From_File"); 74 CreateTextFile(from_file.value(), kTextContent1); 75 ASSERT_TRUE(base::PathExists(from_file)); 76 77 // Generate destination path 78 base::FilePath to_dir(temp_from_dir_.path()); 79 to_dir = to_dir.AppendASCII("To_Dir"); 80 ASSERT_FALSE(base::PathExists(to_dir)); 81 82 base::FilePath to_file(to_dir); 83 to_file = to_file.AppendASCII("From_Dir2"); 84 to_file = to_file.AppendASCII("From_File"); 85 ASSERT_FALSE(base::PathExists(to_file)); 86 87 // test Do() 88 scoped_ptr<MoveTreeWorkItem> work_item( 89 WorkItem::CreateMoveTreeWorkItem(from_dir1, 90 to_dir, 91 temp_to_dir_.path(), 92 WorkItem::ALWAYS_MOVE)); 93 EXPECT_TRUE(work_item->Do()); 94 95 EXPECT_FALSE(base::PathExists(from_dir1)); 96 EXPECT_TRUE(base::PathExists(to_dir)); 97 EXPECT_TRUE(base::PathExists(to_file)); 98 99 // test rollback() 100 work_item->Rollback(); 101 102 EXPECT_TRUE(base::PathExists(from_dir1)); 103 EXPECT_TRUE(base::PathExists(from_file)); 104 EXPECT_FALSE(base::PathExists(to_dir)); 105 } 106 107 // Move one directory from source to destination when destination already 108 // exists. 109 TEST_F(MoveTreeWorkItemTest, MoveDirectoryDestExists) { 110 // Create two level deep source dir 111 base::FilePath from_dir1(temp_from_dir_.path()); 112 from_dir1 = from_dir1.AppendASCII("From_Dir1"); 113 base::CreateDirectory(from_dir1); 114 ASSERT_TRUE(base::PathExists(from_dir1)); 115 116 base::FilePath from_dir2(from_dir1); 117 from_dir2 = from_dir2.AppendASCII("From_Dir2"); 118 base::CreateDirectory(from_dir2); 119 ASSERT_TRUE(base::PathExists(from_dir2)); 120 121 base::FilePath from_file(from_dir2); 122 from_file = from_file.AppendASCII("From_File"); 123 CreateTextFile(from_file.value(), kTextContent1); 124 ASSERT_TRUE(base::PathExists(from_file)); 125 126 // Create destination path 127 base::FilePath to_dir(temp_from_dir_.path()); 128 to_dir = to_dir.AppendASCII("To_Dir"); 129 base::CreateDirectory(to_dir); 130 ASSERT_TRUE(base::PathExists(to_dir)); 131 132 base::FilePath orig_to_file(to_dir); 133 orig_to_file = orig_to_file.AppendASCII("To_File"); 134 CreateTextFile(orig_to_file.value(), kTextContent2); 135 ASSERT_TRUE(base::PathExists(orig_to_file)); 136 137 base::FilePath new_to_file(to_dir); 138 new_to_file = new_to_file.AppendASCII("From_Dir2"); 139 new_to_file = new_to_file.AppendASCII("From_File"); 140 ASSERT_FALSE(base::PathExists(new_to_file)); 141 142 // test Do(), don't check for duplicates. 143 scoped_ptr<MoveTreeWorkItem> work_item( 144 WorkItem::CreateMoveTreeWorkItem(from_dir1, 145 to_dir, 146 temp_to_dir_.path(), 147 WorkItem::ALWAYS_MOVE)); 148 EXPECT_TRUE(work_item->Do()); 149 150 EXPECT_FALSE(base::PathExists(from_dir1)); 151 EXPECT_TRUE(base::PathExists(to_dir)); 152 EXPECT_TRUE(base::PathExists(new_to_file)); 153 EXPECT_FALSE(base::PathExists(orig_to_file)); 154 155 // test rollback() 156 work_item->Rollback(); 157 158 EXPECT_TRUE(base::PathExists(from_dir1)); 159 EXPECT_TRUE(base::PathExists(to_dir)); 160 EXPECT_FALSE(base::PathExists(new_to_file)); 161 EXPECT_TRUE(base::PathExists(orig_to_file)); 162 EXPECT_EQ(0, ReadTextFile(orig_to_file).compare(kTextContent2)); 163 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 164 } 165 166 // Move one file from source to destination when destination does not 167 // exist. 168 TEST_F(MoveTreeWorkItemTest, MoveAFile) { 169 // Create a file inside source dir 170 base::FilePath from_dir(temp_from_dir_.path()); 171 from_dir = from_dir.AppendASCII("From_Dir"); 172 base::CreateDirectory(from_dir); 173 ASSERT_TRUE(base::PathExists(from_dir)); 174 175 base::FilePath from_file(from_dir); 176 from_file = from_file.AppendASCII("From_File"); 177 CreateTextFile(from_file.value(), kTextContent1); 178 ASSERT_TRUE(base::PathExists(from_file)); 179 180 // Generate destination file name 181 base::FilePath to_file(temp_from_dir_.path()); 182 to_file = to_file.AppendASCII("To_File"); 183 ASSERT_FALSE(base::PathExists(to_file)); 184 185 // test Do() 186 scoped_ptr<MoveTreeWorkItem> work_item( 187 WorkItem::CreateMoveTreeWorkItem(from_file, 188 to_file, 189 temp_to_dir_.path(), 190 WorkItem::ALWAYS_MOVE)); 191 EXPECT_TRUE(work_item->Do()); 192 193 EXPECT_TRUE(base::PathExists(from_dir)); 194 EXPECT_FALSE(base::PathExists(from_file)); 195 EXPECT_TRUE(base::PathExists(to_file)); 196 EXPECT_EQ(0, ReadTextFile(to_file).compare(kTextContent1)); 197 198 // test rollback() 199 work_item->Rollback(); 200 201 EXPECT_TRUE(base::PathExists(from_dir)); 202 EXPECT_TRUE(base::PathExists(from_file)); 203 EXPECT_FALSE(base::PathExists(to_file)); 204 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 205 } 206 207 // Move one file from source to destination when destination already 208 // exists. 209 TEST_F(MoveTreeWorkItemTest, MoveFileDestExists) { 210 // Create a file inside source dir 211 base::FilePath from_dir(temp_from_dir_.path()); 212 from_dir = from_dir.AppendASCII("From_Dir"); 213 base::CreateDirectory(from_dir); 214 ASSERT_TRUE(base::PathExists(from_dir)); 215 216 base::FilePath from_file(from_dir); 217 from_file = from_file.AppendASCII("From_File"); 218 CreateTextFile(from_file.value(), kTextContent1); 219 ASSERT_TRUE(base::PathExists(from_file)); 220 221 // Create destination path 222 base::FilePath to_dir(temp_from_dir_.path()); 223 to_dir = to_dir.AppendASCII("To_Dir"); 224 base::CreateDirectory(to_dir); 225 ASSERT_TRUE(base::PathExists(to_dir)); 226 227 base::FilePath to_file(to_dir); 228 to_file = to_file.AppendASCII("To_File"); 229 CreateTextFile(to_file.value(), kTextContent2); 230 ASSERT_TRUE(base::PathExists(to_file)); 231 232 // test Do() 233 scoped_ptr<MoveTreeWorkItem> work_item( 234 WorkItem::CreateMoveTreeWorkItem(from_file, 235 to_dir, 236 temp_to_dir_.path(), 237 WorkItem::ALWAYS_MOVE)); 238 EXPECT_TRUE(work_item->Do()); 239 240 EXPECT_TRUE(base::PathExists(from_dir)); 241 EXPECT_FALSE(base::PathExists(from_file)); 242 EXPECT_TRUE(base::PathExists(to_dir)); 243 EXPECT_FALSE(base::PathExists(to_file)); 244 EXPECT_EQ(0, ReadTextFile(to_dir).compare(kTextContent1)); 245 246 // test rollback() 247 work_item->Rollback(); 248 249 EXPECT_TRUE(base::PathExists(from_dir)); 250 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 251 EXPECT_TRUE(base::PathExists(to_dir)); 252 EXPECT_EQ(0, ReadTextFile(to_file).compare(kTextContent2)); 253 } 254 255 // Move one file from source to destination when destination already 256 // exists and is in use. 257 TEST_F(MoveTreeWorkItemTest, MoveFileDestInUse) { 258 // Create a file inside source dir 259 base::FilePath from_dir(temp_from_dir_.path()); 260 from_dir = from_dir.AppendASCII("From_Dir"); 261 base::CreateDirectory(from_dir); 262 ASSERT_TRUE(base::PathExists(from_dir)); 263 264 base::FilePath from_file(from_dir); 265 from_file = from_file.AppendASCII("From_File"); 266 CreateTextFile(from_file.value(), kTextContent1); 267 ASSERT_TRUE(base::PathExists(from_file)); 268 269 // Create an executable in destination path by copying ourself to it. 270 base::FilePath to_dir(temp_from_dir_.path()); 271 to_dir = to_dir.AppendASCII("To_Dir"); 272 base::CreateDirectory(to_dir); 273 ASSERT_TRUE(base::PathExists(to_dir)); 274 275 wchar_t exe_full_path_str[MAX_PATH]; 276 ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH); 277 base::FilePath exe_full_path(exe_full_path_str); 278 base::FilePath to_file(to_dir); 279 to_file = to_file.AppendASCII("To_File"); 280 base::CopyFile(exe_full_path, to_file); 281 ASSERT_TRUE(base::PathExists(to_file)); 282 283 // Run the executable in destination path 284 STARTUPINFOW si = {sizeof(si)}; 285 PROCESS_INFORMATION pi = {0}; 286 ASSERT_TRUE(::CreateProcess(NULL, 287 const_cast<wchar_t*>(to_file.value().c_str()), 288 NULL, NULL, FALSE, 289 CREATE_NO_WINDOW | CREATE_SUSPENDED, 290 NULL, NULL, &si, &pi)); 291 292 // test Do() 293 scoped_ptr<MoveTreeWorkItem> work_item( 294 WorkItem::CreateMoveTreeWorkItem(from_file, 295 to_file, 296 temp_to_dir_.path(), 297 WorkItem::ALWAYS_MOVE)); 298 EXPECT_TRUE(work_item->Do()); 299 300 EXPECT_TRUE(base::PathExists(from_dir)); 301 EXPECT_FALSE(base::PathExists(from_file)); 302 EXPECT_TRUE(base::PathExists(to_dir)); 303 EXPECT_EQ(0, ReadTextFile(to_file).compare(kTextContent1)); 304 305 // test rollback() 306 work_item->Rollback(); 307 308 EXPECT_TRUE(base::PathExists(from_dir)); 309 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 310 EXPECT_TRUE(base::PathExists(to_dir)); 311 EXPECT_TRUE(base::ContentsEqual(exe_full_path, to_file)); 312 313 TerminateProcess(pi.hProcess, 0); 314 EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0); 315 CloseHandle(pi.hProcess); 316 CloseHandle(pi.hThread); 317 } 318 319 // Move one file that is in use to destination. 320 TEST_F(MoveTreeWorkItemTest, MoveFileInUse) { 321 // Create an executable for source by copying ourself to a new source dir. 322 base::FilePath from_dir(temp_from_dir_.path()); 323 from_dir = from_dir.AppendASCII("From_Dir"); 324 base::CreateDirectory(from_dir); 325 ASSERT_TRUE(base::PathExists(from_dir)); 326 327 wchar_t exe_full_path_str[MAX_PATH]; 328 ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH); 329 base::FilePath exe_full_path(exe_full_path_str); 330 base::FilePath from_file(from_dir); 331 from_file = from_file.AppendASCII("From_File"); 332 base::CopyFile(exe_full_path, from_file); 333 ASSERT_TRUE(base::PathExists(from_file)); 334 335 // Create a destination source dir and generate destination file name. 336 base::FilePath to_dir(temp_from_dir_.path()); 337 to_dir = to_dir.AppendASCII("To_Dir"); 338 base::CreateDirectory(to_dir); 339 ASSERT_TRUE(base::PathExists(to_dir)); 340 341 base::FilePath to_file(to_dir); 342 to_file = to_file.AppendASCII("To_File"); 343 CreateTextFile(to_file.value(), kTextContent1); 344 ASSERT_TRUE(base::PathExists(to_file)); 345 346 // Run the executable in source path 347 STARTUPINFOW si = {sizeof(si)}; 348 PROCESS_INFORMATION pi = {0}; 349 ASSERT_TRUE(::CreateProcess(NULL, 350 const_cast<wchar_t*>(from_file.value().c_str()), 351 NULL, NULL, FALSE, 352 CREATE_NO_WINDOW | CREATE_SUSPENDED, 353 NULL, NULL, &si, &pi)); 354 355 // test Do() 356 scoped_ptr<MoveTreeWorkItem> work_item( 357 WorkItem::CreateMoveTreeWorkItem(from_file, 358 to_file, 359 temp_to_dir_.path(), 360 WorkItem::ALWAYS_MOVE)); 361 EXPECT_TRUE(work_item->Do()); 362 363 EXPECT_TRUE(base::PathExists(from_dir)); 364 EXPECT_FALSE(base::PathExists(from_file)); 365 EXPECT_TRUE(base::PathExists(to_dir)); 366 EXPECT_TRUE(base::ContentsEqual(exe_full_path, to_file)); 367 368 // Close the process and make sure all the conditions after Do() are 369 // still true. 370 TerminateProcess(pi.hProcess, 0); 371 EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0); 372 CloseHandle(pi.hProcess); 373 CloseHandle(pi.hThread); 374 375 EXPECT_TRUE(base::PathExists(from_dir)); 376 EXPECT_FALSE(base::PathExists(from_file)); 377 EXPECT_TRUE(base::PathExists(to_dir)); 378 EXPECT_TRUE(base::ContentsEqual(exe_full_path, to_file)); 379 380 // test rollback() 381 work_item->Rollback(); 382 383 EXPECT_TRUE(base::PathExists(from_dir)); 384 EXPECT_TRUE(base::ContentsEqual(exe_full_path, from_file)); 385 EXPECT_TRUE(base::PathExists(to_dir)); 386 EXPECT_EQ(0, ReadTextFile(to_file).compare(kTextContent1)); 387 } 388 389 // Move one directory from source to destination when destination already 390 // exists. 391 TEST_F(MoveTreeWorkItemTest, MoveDirectoryDestExistsCheckForDuplicatesFull) { 392 // Create two level deep source dir 393 base::FilePath from_dir1(temp_from_dir_.path()); 394 from_dir1 = from_dir1.AppendASCII("From_Dir1"); 395 base::CreateDirectory(from_dir1); 396 ASSERT_TRUE(base::PathExists(from_dir1)); 397 398 base::FilePath from_dir2(from_dir1); 399 from_dir2 = from_dir2.AppendASCII("From_Dir2"); 400 base::CreateDirectory(from_dir2); 401 ASSERT_TRUE(base::PathExists(from_dir2)); 402 403 base::FilePath from_file(from_dir2); 404 from_file = from_file.AppendASCII("From_File"); 405 CreateTextFile(from_file.value(), kTextContent1); 406 ASSERT_TRUE(base::PathExists(from_file)); 407 408 // // Create a file hierarchy identical to the one in the source directory. 409 base::FilePath to_dir(temp_from_dir_.path()); 410 to_dir = to_dir.AppendASCII("To_Dir"); 411 ASSERT_TRUE(installer::test::CopyFileHierarchy(from_dir1, to_dir)); 412 413 // Lock one of the files in the to destination directory to prevent moves. 414 base::FilePath orig_to_file( 415 to_dir.AppendASCII("From_Dir2").AppendASCII("From_File")); 416 base::MemoryMappedFile mapped_file; 417 EXPECT_TRUE(mapped_file.Initialize(orig_to_file)); 418 419 // First check that we can't do the regular Move(). 420 scoped_ptr<MoveTreeWorkItem> work_item( 421 WorkItem::CreateMoveTreeWorkItem(from_dir1, 422 to_dir, 423 temp_to_dir_.path(), 424 WorkItem::ALWAYS_MOVE)); 425 EXPECT_FALSE(work_item->Do()); 426 work_item->Rollback(); 427 428 // Now test Do() with the check for duplicates. This should pass. 429 work_item.reset( 430 WorkItem::CreateMoveTreeWorkItem(from_dir1, 431 to_dir, 432 temp_to_dir_.path(), 433 WorkItem::CHECK_DUPLICATES)); 434 EXPECT_TRUE(work_item->Do()); 435 436 // Make sure that we "moved" the files, i.e. that the source directory isn't 437 // there anymore, 438 EXPECT_FALSE(base::PathExists(from_dir1)); 439 // Make sure that the original directory structure and file are still present. 440 EXPECT_TRUE(base::PathExists(to_dir)); 441 EXPECT_TRUE(base::PathExists(orig_to_file)); 442 // Make sure that the backup path is not empty. 443 EXPECT_FALSE(base::IsDirectoryEmpty(temp_to_dir_.path())); 444 445 // Check that the work item believes the source to have been moved. 446 EXPECT_TRUE(work_item->source_moved_to_backup_); 447 EXPECT_FALSE(work_item->moved_to_dest_path_); 448 EXPECT_FALSE(work_item->moved_to_backup_); 449 450 // test rollback() 451 work_item->Rollback(); 452 453 // Once we rollback all the original files should still be there, as should 454 // the source files. 455 EXPECT_TRUE(base::PathExists(from_dir1)); 456 EXPECT_TRUE(base::PathExists(to_dir)); 457 EXPECT_TRUE(base::PathExists(orig_to_file)); 458 EXPECT_EQ(0, ReadTextFile(orig_to_file).compare(kTextContent1)); 459 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 460 } 461 462 // Move one directory from source to destination when destination already 463 // exists but contains only a subset of the files in source. 464 TEST_F(MoveTreeWorkItemTest, MoveDirectoryDestExistsCheckForDuplicatesPartial) { 465 // Create two level deep source dir 466 base::FilePath from_dir1(temp_from_dir_.path()); 467 from_dir1 = from_dir1.AppendASCII("From_Dir1"); 468 base::CreateDirectory(from_dir1); 469 ASSERT_TRUE(base::PathExists(from_dir1)); 470 471 base::FilePath from_dir2(from_dir1); 472 from_dir2 = from_dir2.AppendASCII("From_Dir2"); 473 base::CreateDirectory(from_dir2); 474 ASSERT_TRUE(base::PathExists(from_dir2)); 475 476 base::FilePath from_file(from_dir2); 477 from_file = from_file.AppendASCII("From_File"); 478 CreateTextFile(from_file.value(), kTextContent1); 479 ASSERT_TRUE(base::PathExists(from_file)); 480 481 base::FilePath from_file2(from_dir2); 482 from_file2 = from_file2.AppendASCII("From_File2"); 483 CreateTextFile(from_file2.value(), kTextContent2); 484 ASSERT_TRUE(base::PathExists(from_file2)); 485 486 // Create destination path 487 base::FilePath to_dir(temp_from_dir_.path()); 488 to_dir = to_dir.AppendASCII("To_Dir"); 489 base::CreateDirectory(to_dir); 490 ASSERT_TRUE(base::PathExists(to_dir)); 491 492 // Create a sub-directory of the same name as in the source directory. 493 base::FilePath to_dir2(to_dir); 494 to_dir2 = to_dir2.AppendASCII("From_Dir2"); 495 base::CreateDirectory(to_dir2); 496 ASSERT_TRUE(base::PathExists(to_dir2)); 497 498 // Create one of the files in the to sub-directory, but not the other. 499 base::FilePath orig_to_file(to_dir2); 500 orig_to_file = orig_to_file.AppendASCII("From_File"); 501 CreateTextFile(orig_to_file.value(), kTextContent1); 502 ASSERT_TRUE(base::PathExists(orig_to_file)); 503 504 // test Do(), check for duplicates. 505 scoped_ptr<MoveTreeWorkItem> work_item( 506 WorkItem::CreateMoveTreeWorkItem(from_dir1, 507 to_dir, 508 temp_to_dir_.path(), 509 WorkItem::CHECK_DUPLICATES)); 510 EXPECT_TRUE(work_item->Do()); 511 512 // Make sure that we "moved" the files, i.e. that the source directory isn't 513 // there anymore, 514 EXPECT_FALSE(base::PathExists(from_dir1)); 515 // Make sure that the original directory structure and file are still present. 516 EXPECT_TRUE(base::PathExists(to_dir)); 517 EXPECT_TRUE(base::PathExists(orig_to_file)); 518 // Make sure that the backup path is not empty. 519 EXPECT_FALSE(base::IsDirectoryEmpty(temp_to_dir_.path())); 520 // Make sure that the "new" file is also present. 521 base::FilePath new_to_file2(to_dir2); 522 new_to_file2 = new_to_file2.AppendASCII("From_File2"); 523 EXPECT_TRUE(base::PathExists(new_to_file2)); 524 525 // Check that the work item believes that this was a regular move. 526 EXPECT_FALSE(work_item->source_moved_to_backup_); 527 EXPECT_TRUE(work_item->moved_to_dest_path_); 528 EXPECT_TRUE(work_item->moved_to_backup_); 529 530 // test rollback() 531 work_item->Rollback(); 532 533 // Once we rollback all the original files should still be there, as should 534 // the source files. 535 EXPECT_TRUE(base::PathExists(from_dir1)); 536 EXPECT_TRUE(base::PathExists(to_dir)); 537 EXPECT_TRUE(base::PathExists(orig_to_file)); 538 EXPECT_EQ(0, ReadTextFile(orig_to_file).compare(kTextContent1)); 539 EXPECT_EQ(0, ReadTextFile(from_file).compare(kTextContent1)); 540 541 // Also, after rollback the new "to" file should be gone. 542 EXPECT_FALSE(base::PathExists(new_to_file2)); 543 } 544