Skip to content

Commit 4d6bd4d

Browse files
committed
fix(tests,windows): repair PR #12 Windows failures and status JSON errors
1. tests/test_index_resilience.c: the `outside` buffer in index_metrics_out_outside_root_refused was 64 bytes. On Windows cbm_mkdtemp expands the template into a ~86-byte temp path via strcpy, overflowing the buffer. Enlarged to 256 bytes. The other metrics_out test and the extra/metrics buffers (300 bytes) were checked and are large enough. 2. tests/test_cli.c: four Windows legacy-hook migration tests called cbm_install_agent_configs, which in this fork installs skills only, so cbm_remove_owned_legacy_hook_script never ran. They now call cbm_install_agent_hooks_for_testing; other calls are unchanged. 3. src/foundation/compat_fs.c: the Windows cbm_opendir returned NULL without setting errno when FindFirstFileW failed. execute_projects in src/operations/read.c treats NULL with errno != ENOENT as an unreadable cache directory, so `projects` failed on Windows when the cache directory did not exist. GetLastError() is now mapped: FILE_NOT_FOUND/PATH_NOT_FOUND -> ENOENT, ACCESS_DENIED -> EACCES, ERROR_DIRECTORY -> ENOTDIR, otherwise EIO. 4. src/main.c: the daemon status JSON printer ignored the return values of the yyjson add calls and could print partial or empty JSON. The results are now combined; on failure it prints "error: could not build status JSON" to stderr, and a NULL from yyjson_mut_write prints "error: could not serialize status JSON". The function stays void.
1 parent 637678e commit 4d6bd4d

4 files changed

Lines changed: 38 additions & 17 deletions

File tree

‎src/foundation/compat_fs.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ cbm_dir_t *cbm_opendir(const char *path) {
7777

7878
d->find_handle = FindFirstFileW(d->wide_pattern, &d->find_data);
7979
if (d->find_handle == INVALID_HANDLE_VALUE) {
80+
/* Map the Win32 error so callers can tell a missing directory
81+
* (ENOENT) from a real failure, as on POSIX. */
82+
DWORD werr = GetLastError();
83+
if (werr == ERROR_FILE_NOT_FOUND || werr == ERROR_PATH_NOT_FOUND) {
84+
errno = ENOENT;
85+
} else if (werr == ERROR_ACCESS_DENIED) {
86+
errno = EACCES;
87+
} else if (werr == ERROR_DIRECTORY) {
88+
errno = ENOTDIR;
89+
} else {
90+
errno = EIO;
91+
}
8092
free(d);
8193
return NULL;
8294
}

‎src/main.c‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,21 +2166,30 @@ static void main_daemon_ctl_print_status_json(bool active,
21662166
return;
21672167
}
21682168
yyjson_mut_doc_set_root(doc, root);
2169-
yyjson_mut_obj_add_bool(doc, root, "active", true);
2170-
yyjson_mut_obj_add_str(doc, root, "status", "active");
2171-
yyjson_mut_obj_add_bool(doc, root, "permanent", status->permanent);
2172-
yyjson_mut_obj_add_uint(doc, root, "pid", (unsigned long)status->daemon_pid);
2173-
yyjson_mut_obj_add_uint(doc, root, "clients", (unsigned)status->client_count);
2174-
yyjson_mut_obj_add_uint(doc, root, "committed_clients", (unsigned)status->committed_clients);
2175-
yyjson_mut_obj_add_bool(doc, root, "stopping", status->stopping);
2176-
yyjson_mut_obj_add_strcpy(doc, root, "version", status->semantic_version);
2177-
yyjson_mut_obj_add_strcpy(doc, root, "build", status->build_fingerprint);
2169+
bool ok = true;
2170+
ok = ok && yyjson_mut_obj_add_bool(doc, root, "active", true);
2171+
ok = ok && yyjson_mut_obj_add_str(doc, root, "status", "active");
2172+
ok = ok && yyjson_mut_obj_add_bool(doc, root, "permanent", status->permanent);
2173+
ok = ok && yyjson_mut_obj_add_uint(doc, root, "pid", (unsigned long)status->daemon_pid);
2174+
ok = ok && yyjson_mut_obj_add_uint(doc, root, "clients", (unsigned)status->client_count);
2175+
ok = ok && yyjson_mut_obj_add_uint(doc, root, "committed_clients",
2176+
(unsigned)status->committed_clients);
2177+
ok = ok && yyjson_mut_obj_add_bool(doc, root, "stopping", status->stopping);
2178+
ok = ok && yyjson_mut_obj_add_strcpy(doc, root, "version", status->semantic_version);
2179+
ok = ok && yyjson_mut_obj_add_strcpy(doc, root, "build", status->build_fingerprint);
2180+
if (!ok) {
2181+
yyjson_mut_doc_free(doc);
2182+
(void)fprintf(stderr, "error: could not build status JSON\n");
2183+
return;
2184+
}
21782185
char *json = yyjson_mut_write(doc, 0, NULL);
21792186
yyjson_mut_doc_free(doc);
2180-
if (json) {
2181-
printf("%s\n", json);
2182-
free(json);
2187+
if (!json) {
2188+
(void)fprintf(stderr, "error: could not serialize status JSON\n");
2189+
return;
21832190
}
2191+
printf("%s\n", json);
2192+
free(json);
21842193
}
21852194

21862195
#ifdef _WIN32

‎tests/test_cli.c‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8908,7 +8908,7 @@ TEST(cli_windows_claude_lifecycle_migrates_only_exact_owned_legacy_state) {
89088908
free(initial_json);
89098909
yyjson_mut_doc_free(initial_doc);
89108910

8911-
int install_rc = seeded ? cbm_install_agent_configs(tmpdir, binary_path, false, false) : -1;
8911+
int install_rc = seeded ? cbm_install_agent_hooks_for_testing(tmpdir, binary_path, false, false) : -1;
89128912
char *installed_settings = read_test_file_alloc(settings_path);
89138913
yyjson_doc *installed_doc =
89148914
installed_settings ? yyjson_read(installed_settings, strlen(installed_settings), 0) : NULL;
@@ -9009,7 +9009,7 @@ TEST(cli_windows_claude_hook_scripts_migrate_and_uninstall_all_owned_shapes) {
90099009
};
90109010
char *current_scripts[sizeof(current_names) / sizeof(current_names[0])] = {0};
90119011

9012-
int initial_install_rc = cbm_install_agent_configs(tmpdir, binary_path, false, false);
9012+
int initial_install_rc = cbm_install_agent_hooks_for_testing(tmpdir, binary_path, false, false);
90139013
bool current_scripts_ready = initial_install_rc == 0;
90149014
for (size_t i = 0U; i < sizeof(current_names) / sizeof(current_names[0]); i++) {
90159015
char current_path[768];
@@ -9022,7 +9022,7 @@ TEST(cli_windows_claude_hook_scripts_migrate_and_uninstall_all_owned_shapes) {
90229022
}
90239023

90249024
int current_upgrade_rc =
9025-
current_scripts_ready ? cbm_install_agent_configs(tmpdir, binary_path, false, false) : -1;
9025+
current_scripts_ready ? cbm_install_agent_hooks_for_testing(tmpdir, binary_path, false, false) : -1;
90269026
bool current_legacy_removed = current_upgrade_rc == 0;
90279027
for (size_t i = 0U; i < sizeof(legacy_names) / sizeof(legacy_names[0]); i++) {
90289028
char current_path[768];
@@ -9049,7 +9049,7 @@ TEST(cli_windows_claude_hook_scripts_migrate_and_uninstall_all_owned_shapes) {
90499049
}
90509050

90519051
int released_upgrade_rc =
9052-
released_ready ? cbm_install_agent_configs(tmpdir, binary_path, false, false) : -1;
9052+
released_ready ? cbm_install_agent_hooks_for_testing(tmpdir, binary_path, false, false) : -1;
90539053
bool released_legacy_removed = released_upgrade_rc == 0;
90549054
for (size_t i = 0U; i < sizeof(legacy_names) / sizeof(legacy_names[0]); i++) {
90559055
char legacy_path[768];

‎tests/test_index_resilience.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ TEST(index_metrics_out_outside_root_refused) {
809809
FAIL("mkdtemp failed");
810810
}
811811
rh_to_fwd_slashes(lp.tmpdir);
812-
char outside[64];
812+
char outside[256];
813813
snprintf(outside, sizeof(outside), "/tmp/cbm_resil_out_XXXXXX");
814814
if (!cbm_mkdtemp(outside)) {
815815
FAIL("mkdtemp failed");

0 commit comments

Comments
 (0)