From 4c6a831aa2a57e2bcc20aa3fc2f1b7172f5be285 Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Mon, 29 Jun 2026 02:36:40 +0900 Subject: feat: 会話メモリのプロトタイプを実装 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6種類のMCPツールと入力検証を追加 - バイナリログ、スナップショット、復旧、圧縮処理を実装 - Unicode n-gram検索とドメインモデルを追加 - 単体テストと統合テストを追加 - アーキテクチャと実装状況を文書化 - Cコードの記述スタイルを統一 --- tests/storage_test.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/storage_test.c (limited to 'tests/storage_test.c') diff --git a/tests/storage_test.c b/tests/storage_test.c new file mode 100644 index 0000000..bac0f0b --- /dev/null +++ b/tests/storage_test.c @@ -0,0 +1,97 @@ +#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; +} -- cgit v1.2.3