#define WIN32_LEAN_AND_MEAN #include #include "storage/store.h" #include #include #include static int failures; #define CHECK(value) \ do \ { \ if (!(value)) \ { \ fprintf(stderr, "CHECK failed at line %d: %s\n", __LINE__, #value); \ failures++; \ } \ } \ while (0) int wmain(void) { wchar_t temporary[MAX_PATH], directory[MAX_PATH], log_path[MAX_PATH]; tiny_store_t *store = NULL, *second = NULL; tiny_message_t input, first, second_message; tiny_store_status_t status; HANDLE log; HANDLE blocker; tiny_rebuild_report_t report; LARGE_INTEGER position; unsigned char byte; DWORD count; CHECK(GetTempPathW(MAX_PATH, temporary) > 0); CHECK(GetTempFileNameW(temporary, L"tcm", 0, directory) > 0); DeleteFileW(directory); CHECK(CreateDirectoryW(directory, NULL) != 0); status = tiny_store_open(&store, directory); CHECK(status == TINY_STORE_OK); CHECK(tiny_store_open(&second, directory) == TINY_STORE_BUSY); tiny_message_init(&input); tiny_message_init(&first); tiny_message_init(&second_message); input.session_id = _strdup("unit"); input.content = _strdup("first"); input.role = TINY_ROLE_USER; CHECK(tiny_store_write(store, &input, &first) == TINY_STORE_OK); free(input.content); input.content = _strdup("second"); CHECK(tiny_store_write(store, &input, &second_message) == TINY_STORE_OK); CHECK(strcmp(first.message_id, second_message.message_id) < 0); tiny_message_free(&input); tiny_message_free(&first); tiny_message_free(&second_message); tiny_store_close(store); store = NULL; CHECK(tiny_store_open(&store, directory) == TINY_STORE_OK); CHECK(tiny_store_entry_count(store) == 2); swprintf_s(log_path, MAX_PATH, L"%s\\active.tmp", directory); blocker = CreateFileW( log_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CHECK(blocker != INVALID_HANDLE_VALUE); CHECK(tiny_store_rebuild(store, &report) == TINY_STORE_IO_ERROR); CHECK(tiny_store_entry_count(store) == 2); CloseHandle(blocker); DeleteFileW(log_path); tiny_store_close(store); store = NULL; swprintf_s(log_path, MAX_PATH, L"%s\\active.log", directory); log = CreateFileW( log_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); CHECK(log != INVALID_HANDLE_VALUE); position.QuadPart = -1; CHECK(SetFilePointerEx(log, position, NULL, FILE_END) != 0); CHECK(ReadFile(log, &byte, 1, &count, NULL) != 0 && count == 1); byte ^= 0x5a; position.QuadPart = -1; CHECK(SetFilePointerEx(log, position, NULL, FILE_CURRENT) != 0); CHECK(WriteFile(log, &byte, 1, &count, NULL) != 0 && count == 1); CloseHandle(log); CHECK(tiny_store_open(&store, directory) == TINY_STORE_CORRUPT); DeleteFileW(log_path); swprintf_s(log_path, MAX_PATH, L"%s\\active.tmp", directory); DeleteFileW(log_path); swprintf_s(log_path, MAX_PATH, L"%s\\store.lock", directory); DeleteFileW(log_path); swprintf_s(log_path, MAX_PATH, L"%s\\snapshot.bin", directory); DeleteFileW(log_path); RemoveDirectoryW(directory); return failures == 0 ? 0 : 1; }