diff --git a/src/cli/cli.c b/src/cli/cli.c index 05c9a560..f4595bf7 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -175,16 +175,26 @@ const char *cbm_find_cli(const char *name, const char *home_dir) { char path_copy[4096]; snprintf(path_copy, sizeof(path_copy), "%s", path_env); char *saveptr; +#ifdef _WIN32 + const char *path_sep = ";"; +#else + const char *path_sep = ":"; +#endif // NOLINTNEXTLINE(misc-include-cleaner) — strtok_r provided by standard header - char *dir = strtok_r(path_copy, ":", &saveptr); + char *dir = strtok_r(path_copy, path_sep, &saveptr); while (dir) { snprintf(buf, sizeof(buf), "%s/%s", dir, name); struct stat st; +#ifdef _WIN32 + /* On Windows, S_IXUSR is not meaningful — just check file exists */ + if (stat(buf, &st) == 0) { +#else // NOLINTNEXTLINE(misc-include-cleaner) — S_IXUSR provided by standard header if (stat(buf, &st) == 0 && (st.st_mode & S_IXUSR)) { +#endif return buf; } - dir = strtok_r(NULL, ":", &saveptr); + dir = strtok_r(NULL, path_sep, &saveptr); } } @@ -214,7 +224,11 @@ const char *cbm_find_cli(const char *name, const char *home_dir) { continue; } struct stat st; +#ifdef _WIN32 + if (stat(paths[i], &st) == 0) { +#else if (stat(paths[i], &st) == 0 && (st.st_mode & S_IXUSR)) { +#endif snprintf(buf, sizeof(buf), "%s", paths[i]); return buf; } diff --git a/tests/test_cli.c b/tests/test_cli.c index 0e2434cc..7e5781bd 100644 --- a/tests/test_cli.c +++ b/tests/test_cli.c @@ -315,18 +315,18 @@ TEST(cli_find_cli_not_found) { } TEST(cli_find_cli_on_path) { -#ifdef _WIN32 - SKIP("PATH search differs on Windows"); -#endif /* Port of TestFindCLI_FoundOnPATH */ char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-find-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) SKIP("cbm_mkdtemp failed"); + /* Create a fake CLI binary (no extension — like npm shims on Windows) */ char fakecli[512]; snprintf(fakecli, sizeof(fakecli), "%s/fakecli", tmpdir); write_test_file(fakecli, "#!/bin/sh\n"); +#ifndef _WIN32 chmod(fakecli, 0500); +#endif const char *raw = getenv("PATH"); char *old_path = raw ? strdup(raw) : NULL; @@ -346,9 +346,6 @@ TEST(cli_find_cli_on_path) { } TEST(cli_find_cli_fallback_paths) { -#ifdef _WIN32 - SKIP("shell scripts + chmod not available on Windows"); -#endif /* Port of TestFindCLI_FallbackPaths */ char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-find-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) @@ -358,17 +355,25 @@ TEST(cli_find_cli_fallback_paths) { snprintf(localbin, sizeof(localbin), "%s/.local/bin", tmpdir); test_mkdirp(localbin); + /* Create a fake CLI binary in fallback location (no extension) */ char fakecli[512]; snprintf(fakecli, sizeof(fakecli), "%s/testcli", localbin); write_test_file(fakecli, "#!/bin/sh\n"); +#ifndef _WIN32 chmod(fakecli, 0500); +#endif const char *raw = getenv("PATH"); char *old_path = raw ? strdup(raw) : NULL; +#ifdef _WIN32 + cbm_setenv("PATH", "C:\\nonexistent", 1); +#else cbm_setenv("PATH", "/nonexistent", 1); +#endif const char *result = cbm_find_cli("testcli", tmpdir); - ASSERT_STR_EQ(result, fakecli); + ASSERT(result[0] != '\0'); + ASSERT(strstr(result, "testcli") != NULL); if (old_path) { cbm_setenv("PATH", old_path, 1);