| // Copyright 2003-2009 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ======================================================================== |
| // |
| // File unittest |
| |
| #include "omaha/common/file.h" |
| #include "omaha/common/logging.h" |
| #include "omaha/common/string.h" |
| #include "omaha/common/timer.h" |
| #include "omaha/common/tr_rand.h" |
| #include "omaha/common/utils.h" |
| #include "omaha/testing/unit_test.h" |
| |
| namespace omaha { |
| |
| // TODO(omaha): test error-prone functions such as ReadLineAnsi |
| |
| void SimpleTest(bool async) { |
| File f; |
| |
| char buf[1000] = "test"; |
| uint32 len1 = 4; |
| |
| char buf2[1000] = "aaaa"; |
| uint32 len2 = 4; |
| |
| char buf3[1000] = "bbbb"; |
| uint32 len3 = 4; |
| |
| char buf4[1000] = " "; |
| uint32 len4 = 4; |
| |
| CString s(_T("test")); |
| CString testfile(_T("testfile.1")); |
| |
| ASSERT_SUCCEEDED(f.Open(testfile, true, async)); |
| uint32 pos = 0; |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf), |
| len1, |
| 0, |
| NULL)); |
| pos += len1; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.WriteAt(pos, |
| reinterpret_cast<byte*>(buf3), |
| len3, |
| 0, |
| NULL)); |
| pos += len3; |
| |
| ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf4), len1, 0, NULL)); |
| ASSERT_STREQ(buf, buf4); |
| |
| ASSERT_SUCCEEDED(f.ReadAt(4, reinterpret_cast<byte*>(buf4), len3, 0, NULL)); |
| ASSERT_STREQ(buf3, buf4); |
| |
| ASSERT_SUCCEEDED(f.WriteAt(1, reinterpret_cast<byte*>(buf3), 2, 0, NULL)); |
| |
| ASSERT_SUCCEEDED(f.WriteAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL)); |
| ASSERT_SUCCEEDED(f.ReadAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL)); |
| |
| ASSERT_SUCCEEDED(f.WriteAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL)); |
| |
| ASSERT_SUCCEEDED(f.SeekFromBegin(0)); |
| |
| ASSERT_SUCCEEDED(f.ReadAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL)); |
| |
| ASSERT_SUCCEEDED(f.Close()); |
| |
| ASSERT_SUCCEEDED(f.Open(L"testfile.1", false, false)); |
| ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf), 16, 0, NULL)); |
| buf[17] = '\0'; |
| |
| uint64 size_on_disk = 0; |
| ASSERT_SUCCEEDED(f.GetSizeOnDisk(&size_on_disk)); |
| ASSERT_EQ(size_on_disk, 32); |
| |
| ASSERT_SUCCEEDED(f.Close()); |
| |
| ASSERT_TRUE(File::Exists(testfile)); |
| ASSERT_SUCCEEDED(File::Remove(testfile)); |
| ASSERT_FALSE(File::Exists(testfile)); |
| } |
| |
| void FileWriteCreate(uint32 file_size) { |
| Timer time(true); |
| CString testfile; |
| testfile.Format(L"testfile%u", file_size); |
| |
| File f; |
| ASSERT_SUCCEEDED(f.Open(testfile, true, false)); |
| ASSERT_SUCCEEDED(f.SetLength(file_size, false)); |
| |
| uint32 write_size = 512; |
| |
| byte *buf2 = new byte[write_size]; |
| |
| for (uint32 j = 0; j < file_size - write_size; j += write_size) { |
| for (uint32 i = 0; i < write_size; i++) { |
| buf2[i] = static_cast<byte>(tr_rand() % 255); |
| } |
| ASSERT_SUCCEEDED(f.WriteAt(j, buf2, write_size, 0, NULL)); |
| } |
| |
| f.Sync(); |
| f.Close(); |
| } |
| |
| void FileWriteTimeTest(uint32 file_size, |
| uint32 number_writes, |
| uint32 write_size) { |
| Timer time(true); |
| CString testfile; |
| testfile.Format(L"testfile%u", file_size); |
| |
| File f; |
| ASSERT_SUCCEEDED(f.Open(testfile, true, false)); |
| |
| byte *buf = new byte[write_size]; |
| |
| for (uint32 i = 0; i < number_writes; i++) { |
| for (uint32 j = 0; j < write_size; j++) { |
| buf[j] = static_cast<byte>(tr_rand() % 255); |
| } |
| uint32 pos = (tr_rand() * 65536 + tr_rand()) % (file_size - write_size); |
| ASSERT_SUCCEEDED(f.WriteAt(pos, buf, write_size, 0, NULL)); |
| } |
| |
| delete[] buf; |
| |
| ASSERT_SUCCEEDED(f.Sync()); |
| ASSERT_SUCCEEDED(f.Close()); |
| } |
| |
| TEST(FileTest, File) { |
| SimpleTest(false); |
| |
| int header = 123; |
| int header2 = 0; |
| |
| File f2; |
| ASSERT_SUCCEEDED(f2.Open(L"testfile.3", true, false)); |
| ASSERT_SUCCEEDED(f2.WriteAt(0, |
| reinterpret_cast<byte*>(&header), |
| sizeof(header), |
| 0, |
| NULL)); |
| ASSERT_SUCCEEDED(f2.ReadAt(0, |
| reinterpret_cast<byte*>(&header2), |
| sizeof(header), |
| 0, |
| NULL)); |
| ASSERT_EQ(header, header2); |
| |
| uint64 size_on_disk = 0; |
| |
| ASSERT_SUCCEEDED(f2.GetSizeOnDisk(&size_on_disk)); |
| ASSERT_EQ(size_on_disk, sizeof(header)); |
| ASSERT_SUCCEEDED(f2.Close()); |
| |
| const int kLevel = 1; |
| for (uint32 file_size = 2 * 1024 * 1024; |
| file_size <= 2 * 1024 * 1024; |
| file_size *= 2) { |
| for (uint32 number_writes = 100; |
| number_writes <= (300 * static_cast<uint32>(kLevel)); |
| number_writes *= 2) { |
| uint32 write_size = 128; |
| FileWriteTimeTest(file_size, number_writes, write_size); |
| } |
| } |
| |
| // Test File::Copy, File::Move, File::CopyWildcards |
| { |
| CString windows_dir; |
| CString temp_dir; |
| DWORD dw = ::GetEnvironmentVariable( |
| L"SystemRoot", |
| windows_dir.GetBufferSetLength(MAX_PATH), |
| MAX_PATH); |
| windows_dir.ReleaseBuffer(); |
| ASSERT_TRUE(dw); |
| dw = ::GetEnvironmentVariable(L"TEMP", |
| temp_dir.GetBufferSetLength(MAX_PATH), |
| MAX_PATH); |
| temp_dir.ReleaseBuffer(); |
| ASSERT_TRUE(dw); |
| CString known_file1(windows_dir + L"\\NOTEPAD.EXE"); |
| CString known_file2(windows_dir + L"\\REGEDIT.EXE"); |
| CString temp_file1(temp_dir + L"\\FOO.TMP"); |
| CString temp_file2(temp_dir + L"\\BAR.TMP"); |
| uint32 known_size1 = 0; |
| uint32 known_size2 = 0; |
| uint32 temp_size1 = 0; |
| |
| // Start with neither file existing |
| if (File::Exists(temp_file1)) |
| File::Remove(temp_file1); |
| if (File::Exists(temp_file2)) |
| File::Remove(temp_file2); |
| ASSERT_FALSE(File::Exists(temp_file1)); |
| ASSERT_FALSE(File::Exists(temp_file2)); |
| ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file1, &known_size1)); |
| ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file2, &known_size2)); |
| ASSERT_NE(known_size1, known_size2); |
| |
| // Copy to create a file, move it to 2nd file, then remove 2nd file |
| ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false)); |
| ASSERT_TRUE(File::Exists(temp_file1)); |
| ASSERT_SUCCEEDED(File::Move(temp_file1, temp_file2, false)); |
| ASSERT_FALSE(File::Exists(temp_file1)); |
| ASSERT_TRUE(File::Exists(temp_file2)); |
| ASSERT_SUCCEEDED(File::Remove(temp_file2)); |
| ASSERT_FALSE(File::Exists(temp_file2)); |
| |
| // Try copying a file on top of a file - with and without |
| // replace_existing_file=true |
| ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false)); |
| ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1)); |
| ASSERT_EQ(temp_size1, known_size1); |
| ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, false)); |
| ASSERT_TRUE(File::Exists(temp_file1)); |
| ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1)); |
| ASSERT_EQ(temp_size1, known_size1); |
| ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, true)); |
| ASSERT_TRUE(File::Exists(temp_file1)); |
| ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1)); |
| ASSERT_EQ(temp_size1, known_size2); |
| ASSERT_SUCCEEDED(File::Remove(temp_file1)); |
| |
| // Try copying a bunch of files |
| CString known_file3(windows_dir + L"\\twunk_32.exe"); |
| CString known_file4(windows_dir + L"\\twunk_16.exe"); |
| CString temp_file3(temp_dir + L"\\twunk_32.exe"); |
| CString temp_file4(temp_dir + L"\\twunk_16.exe"); |
| if (File::Exists(temp_file3)) |
| File::Remove(temp_file3); |
| if (File::Exists(temp_file4)) |
| File::Remove(temp_file4); |
| ASSERT_TRUE(File::Exists(known_file3)); |
| ASSERT_TRUE(File::Exists(known_file4)); |
| ASSERT_FALSE(File::Exists(temp_file3)); |
| ASSERT_FALSE(File::Exists(temp_file4)); |
| ASSERT_SUCCEEDED(File::CopyWildcards(windows_dir, |
| temp_dir, |
| L"twunk*.exe", |
| true)); |
| ASSERT_TRUE(File::Exists(temp_file3)); |
| ASSERT_TRUE(File::Exists(temp_file4)); |
| ASSERT_SUCCEEDED(File::Remove(temp_file3)); |
| ASSERT_SUCCEEDED(File::Remove(temp_file4)); |
| |
| std::vector<CString> matching_files; |
| ASSERT_SUCCEEDED(File::GetWildcards(windows_dir, |
| L"twunk*.exe", |
| &matching_files)); |
| ASSERT_EQ(matching_files.size(), 2); |
| ASSERT_TRUE(matching_files[0] == known_file3 || |
| matching_files[0] == known_file4); |
| ASSERT_TRUE(matching_files[1] == known_file3 || |
| matching_files[1] == known_file4); |
| ASSERT_TRUE(matching_files[0] != matching_files[1]); |
| } |
| } |
| |
| |
| TEST(FileTest, FileChangeWatcher) { |
| CString temp_dir; |
| ASSERT_TRUE(::GetEnvironmentVariable(L"TEMP", |
| temp_dir.GetBufferSetLength(MAX_PATH), |
| MAX_PATH) != 0); |
| temp_dir.ReleaseBuffer(); |
| temp_dir = String_MakeEndWith(temp_dir, _T("\\"), false /* ignore_case */); |
| temp_dir = temp_dir + _T("omaha_unittest") + itostr(tr_rand() % 255); |
| EXPECT_SUCCEEDED(CreateDir(temp_dir, 0)); |
| |
| // watch the directory for changes |
| FileWatcher watcher(temp_dir, false, FILE_NOTIFY_CHANGE_LAST_WRITE); |
| EXPECT_SUCCEEDED(watcher.EnsureEventSetup()); |
| EXPECT_FALSE(watcher.HasChangeOccurred()); |
| |
| // |
| // verify that the watcher got set-up correctly the first time |
| // |
| |
| // do something in the dir |
| File f; |
| int header1 = 94; |
| ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.1"), true, false)); |
| ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header1), |
| sizeof(header1), 0, NULL)); |
| ASSERT_SUCCEEDED(f.Sync()); |
| ASSERT_SUCCEEDED(f.Close()); |
| |
| // Did we noticed that something happened? |
| EXPECT_TRUE(watcher.HasChangeOccurred()); |
| EXPECT_SUCCEEDED(watcher.EnsureEventSetup()); |
| EXPECT_FALSE(watcher.HasChangeOccurred()); |
| |
| // |
| // verify that the watcher got set-up correctly the second time |
| // |
| |
| // do something in the dir |
| byte header2 = 2; |
| ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.2"), true, false)); |
| ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header2), |
| sizeof(header2), 0, NULL)); |
| ASSERT_SUCCEEDED(f.Sync()); |
| ASSERT_SUCCEEDED(f.Close()); |
| |
| // Did we noticed that something happened? |
| EXPECT_TRUE(watcher.HasChangeOccurred()); |
| EXPECT_SUCCEEDED(watcher.EnsureEventSetup()); |
| EXPECT_FALSE(watcher.HasChangeOccurred()); |
| |
| EXPECT_SUCCEEDED(DeleteDirectory(temp_dir)); |
| } |
| |
| } // namespace omaha |
| |