Basic conformance tests create a test source directory with files and execute robocopy on it, checking whether the resulting destination directory, the remaining source directory and the exit code is as expected
Signed-off-by: Florian Eder others.meder@gmail.com --- v5: All wide strings are using debugstr_w in the ok tests, instead of %S in the format string, reduced size of cmd buffer to 511 chars --- programs/robocopy/tests/robocopy.c | 188 ++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-)
diff --git a/programs/robocopy/tests/robocopy.c b/programs/robocopy/tests/robocopy.c index de3d05fd7bc..4dedd2aad8a 100644 --- a/programs/robocopy/tests/robocopy.c +++ b/programs/robocopy/tests/robocopy.c @@ -52,10 +52,153 @@ static DWORD execute_robocopy(const WCHAR *args) return exit_code; }
+static void create_test_file(const WCHAR *relative_path, size_t size, LONGLONG fixed_filetime, long filetime_offset) +{ + HANDLE handle; + WCHAR path[1024]; + wcscpy(path, L"\\?\"); + GetTempPathW(ARRAY_SIZE(path) - 4, &(path[4])); + wcscat(path, relative_path); + handle = CreateFileW(path, FILE_GENERIC_WRITE | FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); + ok(handle != INVALID_HANDLE_VALUE, "creation of %s failed (0x%08x)\n", debugstr_w(path), GetLastError()); + if (size != 0) + { + BYTE *data; + DWORD bytes_written; + data = calloc(size, sizeof(BYTE)); + ok(WriteFile(handle, data, size, &bytes_written, NULL), "writing to %s failed (%d)\n", debugstr_w(path), GetLastError()); + } + if (fixed_filetime != 0) + { + FILETIME time; + LARGE_INTEGER time_as_integer; + time_as_integer.QuadPart = fixed_filetime; + time.dwHighDateTime = time_as_integer.HighPart; + time.dwLowDateTime = time_as_integer.LowPart; + ok(SetFileTime(handle, &time, &time, &time), "filetime manipulation of %s failed (%d)\n", debugstr_w(path), GetLastError()); + } + if (filetime_offset != 0) + { + FILETIME time, modified_time, access_time; + LARGE_INTEGER time_as_integer; + GetFileTime(handle, &time, &modified_time, &access_time); + /* FILETIME is no union with LONGLONG / LONG64, casting could be unsafe */ + time_as_integer.HighPart = time.dwHighDateTime; + time_as_integer.LowPart = time.dwLowDateTime; + /* 1000 * 1000 * 60 * 60 * 24 = 86400000000ns per day */ + time_as_integer.QuadPart += 864000000000LL * filetime_offset; + time.dwHighDateTime = time_as_integer.HighPart; + time.dwLowDateTime = time_as_integer.LowPart; + ok(SetFileTime(handle, &time, &time, &time), "filetime manipulation of %s failed (%d)\n", debugstr_w(path), GetLastError()); + } + CloseHandle(handle); +} + +static void create_test_folder(const WCHAR *relative_path) +{ + WCHAR path[1024]; + wcscpy(path, L"\\?\"); + GetTempPathW(ARRAY_SIZE(path) - 4, &(path[4])); + wcscat(path, relative_path); + CreateDirectoryW(path, NULL); +} + +static void create_test_source_folder(void) +{ + create_test_folder(L"robocopy_source"); + create_test_folder(L"robocopy_source\folderA"); + create_test_folder(L"robocopy_source\folderB"); + create_test_folder(L"robocopy_source\folderC"); + create_test_folder(L"robocopy_source\folderA\folderD"); + create_test_folder(L"robocopy_source\folderA\folderE"); + create_test_file(L"robocopy_source\fileA.a", 4000, 0, -10); + create_test_file(L"robocopy_source\fileB.b", 8000, 0, -2); + create_test_file(L"robocopy_source\folderA\fileC.c", 60, 0, -2); + create_test_file(L"robocopy_source\folderA\fileD.d", 80, 0, 0); + create_test_file(L"robocopy_source\folderA\folderD\fileE.e", 10000, 0, -10); + create_test_file(L"robocopy_source\folderB\fileF.f", 10000, 132223104000000000, 0); + create_test_file(L"robocopy_source\folderB\fileG.g", 200, 132223104000000000, 0); +} + +static void check_file_and_delete(const WCHAR *relative_path, BOOL should_exist) +{ + WCHAR path[1024]; + wcscpy(path, L"\\?\"); + GetTempPathW(ARRAY_SIZE(path) - 4, &(path[4])); + wcscat(path, relative_path); + if (!DeleteFileW(path)) + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + ok(!should_exist, "file "%s" does not exist, but should exist\n", debugstr_w(relative_path)); + else if (GetLastError() == ERROR_PATH_NOT_FOUND) + ok(!should_exist, "file "%s" and the parent directory do not exist, but should exist\n", debugstr_w(relative_path)); + else + ok(FALSE, "file "%s" DeleteFileW returned error %d\n", debugstr_w(relative_path), GetLastError()); + } + else + { + ok(should_exist, "file "%s" should not exist, but does exist\n", debugstr_w(relative_path)); + } +} + +static void check_folder_and_delete(const WCHAR *relative_path, BOOL should_exist) +{ + WCHAR path[1024]; + wcscpy(path, L"\\?\"); + GetTempPathW(ARRAY_SIZE(path) - 4, &(path[4])); + wcscat(path, relative_path); + if (!RemoveDirectoryW(path)) + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + ok(!should_exist, "directory "%s" does not exist, but should exist\n", debugstr_w(relative_path)); + else if (GetLastError() == ERROR_PATH_NOT_FOUND) + ok(!should_exist, "directory "%s" and the parent directory do not exist, but should exist\n", debugstr_w(relative_path)); + else if (GetLastError() == ERROR_DIR_NOT_EMPTY) + ok(FALSE, "directory "%s" is unexpectedly not empty\n", debugstr_w(relative_path)); + else + ok(FALSE, "directory "%s" DeleteFileW returned error %d\n", debugstr_w(relative_path), GetLastError()); + } + else + { + ok(should_exist, "directory "%s" should not exist, but does exist\n", debugstr_w(relative_path)); + } +} + +static void check_basic_copy_test(void) +{ + check_file_and_delete(L"robocopy_source\fileA.a", TRUE); + check_file_and_delete(L"robocopy_source\fileB.b", TRUE); + check_file_and_delete(L"robocopy_source\folderA\fileC.c", TRUE); + check_file_and_delete(L"robocopy_source\folderA\fileD.d", TRUE); + check_file_and_delete(L"robocopy_source\folderA\folderD\fileE.e", TRUE); + check_file_and_delete(L"robocopy_source\folderB\fileF.f", TRUE); + check_file_and_delete(L"robocopy_source\folderB\fileG.g", TRUE); + check_folder_and_delete(L"robocopy_source\folderA\folderD", TRUE); + check_folder_and_delete(L"robocopy_source\folderA\folderE", TRUE); + check_folder_and_delete(L"robocopy_source\folderA", TRUE); + check_folder_and_delete(L"robocopy_source\folderB", TRUE); + check_folder_and_delete(L"robocopy_source\folderC", TRUE); + check_folder_and_delete(L"robocopy_source", TRUE); + + check_file_and_delete(L"robocopy_destination\fileA.a", TRUE); + check_file_and_delete(L"robocopy_destination\fileB.b", TRUE); + todo_wine check_file_and_delete(L"robocopy_destination\folderA\fileC.c", FALSE); + todo_wine check_file_and_delete(L"robocopy_destination\folderA\fileD.d", FALSE); + todo_wine check_file_and_delete(L"robocopy_destination\folderA\folderD\fileE.e", FALSE); + todo_wine check_file_and_delete(L"robocopy_destination\folderB\fileF.f", FALSE); + todo_wine check_file_and_delete(L"robocopy_destination\folderB\fileG.g", FALSE); + todo_wine check_folder_and_delete(L"robocopy_destination\folderA\folderD", FALSE); + check_folder_and_delete(L"robocopy_destination\folderA\folderE", FALSE); + todo_wine check_folder_and_delete(L"robocopy_destination\folderA", FALSE); + todo_wine check_folder_and_delete(L"robocopy_destination\folderB", FALSE); + check_folder_and_delete(L"robocopy_destination\folderC", FALSE); + check_folder_and_delete(L"robocopy_destination", TRUE); +} + START_TEST(robocopy) { DWORD exit_code; - WCHAR temp_path[MAX_PATH]; + WCHAR temp_cmd[512], temp_path[MAX_PATH];
/* robocopy is only available from Vista onwards, abort test if not available */ if (execute_robocopy(L"") == MAXDWORD) return; @@ -84,4 +227,47 @@ START_TEST(robocopy) exit_code = execute_robocopy(L"invalid_folder robocopy_destination"); ok(exit_code == 16, "unexpected exit code %d\n", exit_code); winetest_pop_context(); + + winetest_push_context("basic copy test 1"); + create_test_source_folder(); + exit_code = execute_robocopy(L"robocopy_source robocopy_destination /r:1 /w:0"); + ok(exit_code == 1, "unexpected exit code %d\n", exit_code); + check_basic_copy_test(); + winetest_pop_context(); + + winetest_push_context("basic copy test 2"); + create_test_source_folder(); + exit_code = execute_robocopy(L"./robocopy_source third_folder/../robocopy_destination /r:1 /w:0"); + ok(exit_code == 1, "unexpected exit code %d\n", exit_code); + check_basic_copy_test(); + winetest_pop_context(); + + winetest_push_context("basic copy test 3"); + create_test_source_folder(); + create_test_folder(L"robocopy_destination"); + create_test_file(L"robocopy_destination\fileA.a", 9000, 0, -10); + exit_code = execute_robocopy(L"./robocopy_source robocopy_source/../robocopy_destination /r:1 /w:0"); + ok(exit_code == 1, "unexpected exit code %d\n", exit_code); + check_basic_copy_test(); + winetest_pop_context(); + + winetest_push_context("basic copy test 4"); + create_test_source_folder(); + swprintf(temp_cmd, ARRAY_SIZE(temp_cmd), + L"%s\robocopy_source %s\robocopy_destination /r:1 /w:0", + temp_path, temp_path); + exit_code = execute_robocopy(temp_cmd); + ok(exit_code == 1, "unexpected exit code %d\n", exit_code); + check_basic_copy_test(); + winetest_pop_context(); + + winetest_push_context("basic copy test 5"); + create_test_source_folder(); + swprintf(temp_cmd, ARRAY_SIZE(temp_cmd), + L"%s\third_folder\..\robocopy_source %s\third_folder\..\robocopy_destination /r:1 /w:0", + temp_path, temp_path); + exit_code = execute_robocopy(temp_cmd); + ok(exit_code == 1, "unexpected exit code %d\n", exit_code); + check_basic_copy_test(); + winetest_pop_context(); }