diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index b1d31b81..642f2b40 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -15,6 +15,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + # Tests must pass or fail — no SKIPs except genuinely platform-specific + # ones (SKIP_PLATFORM / #ifdef). Fails the lint phase on any plain SKIP(). + - name: No-skips policy (tests pass or fail) + run: bash scripts/check-no-test-skips.sh + - name: Install build deps run: sudo apt-get update && sudo apt-get install -y zlib1g-dev cmake diff --git a/scripts/check-no-test-skips.sh b/scripts/check-no-test-skips.sh new file mode 100644 index 00000000..14e204c0 --- /dev/null +++ b/scripts/check-no-test-skips.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# check-no-test-skips.sh — Enforce the no-skips test policy in the lint phase. +# +# Every test must PASS or FAIL. The ONLY tolerable skip is a genuinely +# platform-specific test that cannot run on the current OS (e.g. a Windows-only +# test on macOS); those must use the SKIP_PLATFORM() macro (or #ifdef +# compile-gating). A plain SKIP() — or any direct tf_skip_count manipulation — +# in a test source means a setup/environment/resource failure is being hidden +# instead of surfaced as a failure. That fails this check. +# +# Rationale: a test that cannot establish its preconditions has FAILED, not been +# "skipped". Convert such SKIP() to FAIL("reason"). +# +# Usage: bash scripts/check-no-test-skips.sh (exit 0 = clean, 1 = violations) +set -uo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +violations=0 + +# 1. Plain SKIP( in test sources. +# - SKIP_PLATFORM( never matches "SKIP(" (the char after SKIP is '_'). +# - The SKIP()/FAIL()/SKIP_PLATFORM() macro DEFINITIONS live in +# tests/test_framework.h (a .h), which the tests/*.c glob does not scan. +while IFS= read -r hit; do + echo "[no-skips] FORBIDDEN SKIP(): $hit" + violations=$((violations + 1)) +done < <(grep -rnE '(^|[^A-Za-z0-9_])SKIP\(' "$ROOT"/tests/*.c 2>/dev/null || true) + +# 2. Direct tf_skip_count increment in a test source (only the framework's +# SKIP_PLATFORM macro, defined in the .h, may touch it). +while IFS= read -r hit; do + echo "[no-skips] FORBIDDEN tf_skip_count manipulation: $hit" + violations=$((violations + 1)) +done < <(grep -rnE 'tf_skip_count[[:space:]]*(\+\+|\+=|--)' "$ROOT"/tests/*.c 2>/dev/null || true) + +if [ "$violations" -gt 0 ]; then + echo "" + echo "[no-skips] FAIL: $violations violation(s). Tests must pass or fail." + echo " setup / environment / resource failures -> FAIL(\"reason\")" + echo " genuinely platform-specific tests -> SKIP_PLATFORM(\"reason\") or #ifdef" + exit 1 +fi + +echo "[no-skips] OK — no forbidden skips in tests/*.c (SKIP_PLATFORM allowed for platform-only tests)" +exit 0 diff --git a/scripts/lint.sh b/scripts/lint.sh index 6027d2b2..62c912b2 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -29,6 +29,11 @@ done print_env "lint.sh" +# No-skips policy: every test must pass or fail. The only tolerable skip is a +# genuinely platform-specific test (SKIP_PLATFORM / #ifdef). Runs in both modes. +echo "=== no-skips policy (tests pass or fail) ===" +bash "$ROOT/scripts/check-no-test-skips.sh" + if $CI_ONLY; then echo "=== CI mode: cppcheck + clang-format ===" $ARCH_PREFIX make -j2 -f Makefile.cbm lint-ci "${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"}" diff --git a/tests/test_c_lsp.c b/tests/test_c_lsp.c index 48c368fb..171a5e83 100644 --- a/tests/test_c_lsp.c +++ b/tests/test_c_lsp.c @@ -606,19 +606,19 @@ TEST(clsp_calls_attributed_to_function_issue220) { TEST(clsp_nocrash_issue355_xxhash_header) { FILE *fp = fopen("vendored/xxhash/xxhash.h", "rb"); if (!fp) { - SKIP("vendored/xxhash/xxhash.h not found (run from repo root)"); + FAIL("vendored/xxhash/xxhash.h not found (run from repo root)"); } fseek(fp, 0, SEEK_END); long n = ftell(fp); fseek(fp, 0, SEEK_SET); if (n <= 0) { fclose(fp); - SKIP("xxhash.h unreadable"); + FAIL("xxhash.h unreadable"); } char *buf = (char *)malloc((size_t)n + 1); if (!buf) { fclose(fp); - SKIP("oom"); + FAIL("oom"); } size_t rd = fread(buf, 1, (size_t)n, fp); fclose(fp); diff --git a/tests/test_cli.c b/tests/test_cli.c index 088e5b88..add43138 100644 --- a/tests/test_cli.c +++ b/tests/test_cli.c @@ -176,7 +176,7 @@ TEST(cli_detect_shell_rc_zsh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-rc-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Save and override SHELL — must strdup because setenv may realloc env block */ const char *raw = getenv("SHELL"); @@ -200,7 +200,7 @@ TEST(cli_detect_shell_rc_bash) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-rc-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); const char *raw = getenv("SHELL"); char *old_shell = raw ? strdup(raw) : NULL; @@ -225,7 +225,7 @@ TEST(cli_detect_shell_rc_bash_with_bashrc) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-rc-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); const char *raw = getenv("SHELL"); char *old_shell = raw ? strdup(raw) : NULL; @@ -253,7 +253,7 @@ TEST(cli_detect_shell_rc_fish) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-rc-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); const char *raw = getenv("SHELL"); char *old_shell = raw ? strdup(raw) : NULL; @@ -275,7 +275,7 @@ TEST(cli_detect_shell_rc_default) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-rc-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); const char *raw = getenv("SHELL"); char *old_shell = raw ? strdup(raw) : NULL; @@ -302,7 +302,7 @@ TEST(cli_find_cli_not_found) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-find-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); const char *raw = getenv("PATH"); char *old_path = raw ? strdup(raw) : NULL; @@ -324,7 +324,7 @@ TEST(cli_find_cli_on_path) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-find-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char fakecli[512]; snprintf(fakecli, sizeof(fakecli), "%s/fakecli", tmpdir); @@ -333,7 +333,7 @@ TEST(cli_find_cli_on_path) { #ifdef _WIN32 rmdir(tmpdir); - SKIP("PATH-based CLI lookup uses POSIX semantics"); + SKIP_PLATFORM("Windows: PATH-based CLI lookup uses POSIX semantics"); #endif const char *raw = getenv("PATH"); char *old_path = raw ? strdup(raw) : NULL; @@ -357,11 +357,11 @@ TEST(cli_find_cli_fallback_paths) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-find-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); #ifdef _WIN32 rmdir(tmpdir); - SKIP("fallback path lookup uses POSIX semantics"); + SKIP_PLATFORM("Windows: fallback path lookup uses POSIX semantics"); #endif char localbin[512]; snprintf(localbin, sizeof(localbin), "%s/.local/bin", tmpdir); @@ -415,7 +415,7 @@ TEST(cli_skill_creation) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-skill-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -446,7 +446,7 @@ TEST(cli_skill_idempotent) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-skill-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -476,7 +476,7 @@ TEST(cli_skill_force_overwrite) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-skill-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -496,7 +496,7 @@ TEST(cli_uninstall_removes_skills) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-skill-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -523,7 +523,7 @@ TEST(cli_remove_old_monolithic_skill) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-skill-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -594,7 +594,7 @@ TEST(cli_editor_mcp_install) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.cursor/mcp.json", tmpdir); @@ -617,7 +617,7 @@ TEST(cli_editor_mcp_idempotent) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.cursor/mcp.json", tmpdir); @@ -648,7 +648,7 @@ TEST(cli_editor_mcp_preserves_others) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.cursor/mcp.json", tmpdir); @@ -677,7 +677,7 @@ TEST(cli_editor_mcp_uninstall) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.cursor/mcp.json", tmpdir); @@ -700,7 +700,7 @@ TEST(cli_gemini_mcp_install) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.gemini/settings.json", tmpdir); @@ -727,7 +727,7 @@ TEST(cli_vscode_mcp_install) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/Code/User/mcp.json", tmpdir); @@ -752,7 +752,7 @@ TEST(cli_vscode_mcp_uninstall) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/Code/User/mcp.json", tmpdir); @@ -778,7 +778,7 @@ TEST(cli_zed_mcp_install) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.config/zed/settings.json", tmpdir); @@ -803,7 +803,7 @@ TEST(cli_zed_mcp_preserves_settings) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.config/zed/settings.json", tmpdir); @@ -834,7 +834,7 @@ TEST(cli_zed_mcp_uninstall) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.config/zed/settings.json", tmpdir); @@ -856,7 +856,7 @@ TEST(cli_zed_mcp_jsonc_comments) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-mcp-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/.config/zed/settings.json", tmpdir); @@ -898,7 +898,7 @@ TEST(cli_ensure_path_append) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-path-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char rcfile[512]; snprintf(rcfile, sizeof(rcfile), "%s/.zshrc", tmpdir); @@ -918,7 +918,7 @@ TEST(cli_ensure_path_already_present) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-path-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char rcfile[512]; snprintf(rcfile, sizeof(rcfile), "%s/.zshrc", tmpdir); @@ -935,7 +935,7 @@ TEST(cli_ensure_path_dry_run) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-path-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char rcfile[512]; snprintf(rcfile, sizeof(rcfile), "%s/.zshrc", tmpdir); @@ -958,7 +958,7 @@ TEST(cli_ensure_path_fish_syntax_issue319) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-path-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char rcfile[512]; snprintf(rcfile, sizeof(rcfile), "%s/config.fish", tmpdir); @@ -990,7 +990,7 @@ TEST(cli_copy_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-copy-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char src[512], dst[512]; snprintf(src, sizeof(src), "%s/source", tmpdir); @@ -1013,7 +1013,7 @@ TEST(cli_copy_file_source_not_found) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-copy-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char src[512], dst[512]; snprintf(src, sizeof(src), "%s/nonexistent", tmpdir); @@ -1217,7 +1217,7 @@ TEST(cli_install_dry_run) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-dry-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -1243,7 +1243,7 @@ TEST(cli_uninstall_dry_run) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-dry-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -1274,7 +1274,7 @@ TEST(cli_install_and_uninstall) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-full-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char skills_dir[512]; snprintf(skills_dir, sizeof(skills_dir), "%s/.claude/skills", tmpdir); @@ -1411,7 +1411,7 @@ TEST(cli_detect_agents_finds_claude) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; snprintf(dir, sizeof(dir), "%s/.claude", tmpdir); @@ -1439,7 +1439,7 @@ TEST(cli_detect_agents_finds_claude_via_env) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Config dir lives OUTSIDE home_dir/.claude, pointed at by CLAUDE_CONFIG_DIR. */ char ccd[512]; @@ -1469,7 +1469,7 @@ TEST(cli_detect_agents_finds_codex) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; snprintf(dir, sizeof(dir), "%s/.codex", tmpdir); @@ -1488,7 +1488,7 @@ TEST(cli_detect_agents_finds_cursor_issue222) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; snprintf(dir, sizeof(dir), "%s/.cursor", tmpdir); @@ -1507,7 +1507,7 @@ TEST(cli_install_plan_receipt_no_mutation_issue388) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-plan-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Make Cursor + Codex "detected". */ char dir[512]; @@ -1544,7 +1544,7 @@ TEST(cli_codex_session_hook_issue330) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-codexhook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cfg[512]; snprintf(cfg, sizeof(cfg), "%s/config.toml", tmpdir); @@ -1578,7 +1578,7 @@ TEST(cli_gemini_session_hook_parity) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-gemhook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cfg[512]; snprintf(cfg, sizeof(cfg), "%s/settings.json", tmpdir); @@ -1601,7 +1601,7 @@ TEST(cli_detect_agents_finds_gemini) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; snprintf(dir, sizeof(dir), "%s/.gemini", tmpdir); @@ -1618,7 +1618,7 @@ TEST(cli_detect_agents_finds_zed) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; #ifdef __APPLE__ @@ -1641,7 +1641,7 @@ TEST(cli_detect_agents_finds_antigravity) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; /* Antigravity CLI installs under ~/.gemini/antigravity-cli/ (2026). */ @@ -1660,7 +1660,7 @@ TEST(cli_detect_agents_finds_kilocode) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; #ifdef __APPLE__ @@ -1685,7 +1685,7 @@ TEST(cli_detect_agents_finds_kiro) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char dir[512]; snprintf(dir, sizeof(dir), "%s/.kiro", tmpdir); @@ -1702,7 +1702,7 @@ TEST(cli_detect_agents_none_found) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-detect-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Empty home dir → no config dirs → no directory-based agents detected. * Note: opencode/aider may still be detected via system fallback paths @@ -1738,7 +1738,7 @@ TEST(cli_upsert_codex_mcp_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-codex-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/config.toml", tmpdir); @@ -1759,7 +1759,7 @@ TEST(cli_upsert_codex_mcp_existing) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-codex-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/config.toml", tmpdir); @@ -1784,7 +1784,7 @@ TEST(cli_upsert_codex_mcp_replace) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-codex-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/config.toml", tmpdir); @@ -1817,7 +1817,7 @@ TEST(cli_zed_mcp_uses_args_format) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-zed-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/settings.json", tmpdir); @@ -1842,7 +1842,7 @@ TEST(cli_upsert_opencode_mcp_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ocode-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/opencode.json", tmpdir); @@ -1869,7 +1869,7 @@ TEST(cli_upsert_opencode_mcp_existing) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ocode-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/opencode.json", tmpdir); @@ -1895,7 +1895,7 @@ TEST(cli_upsert_antigravity_mcp_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-anti-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/mcp_config.json", tmpdir); @@ -1915,7 +1915,7 @@ TEST(cli_upsert_antigravity_mcp_replace) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-anti-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char configpath[512]; snprintf(configpath, sizeof(configpath), "%s/mcp_config.json", tmpdir); @@ -1942,7 +1942,7 @@ TEST(cli_upsert_instructions_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-instr-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char filepath[512]; snprintf(filepath, sizeof(filepath), "%s/AGENTS.md", tmpdir); @@ -1964,7 +1964,7 @@ TEST(cli_upsert_instructions_existing) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-instr-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char filepath[512]; snprintf(filepath, sizeof(filepath), "%s/AGENTS.md", tmpdir); @@ -1990,7 +1990,7 @@ TEST(cli_upsert_instructions_replace) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-instr-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char filepath[512]; snprintf(filepath, sizeof(filepath), "%s/AGENTS.md", tmpdir); @@ -2020,7 +2020,7 @@ TEST(cli_upsert_instructions_no_duplicate) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-instr-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char filepath[512]; snprintf(filepath, sizeof(filepath), "%s/AGENTS.md", tmpdir); @@ -2051,7 +2051,7 @@ TEST(cli_remove_instructions) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-instr-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char filepath[512]; snprintf(filepath, sizeof(filepath), "%s/AGENTS.md", tmpdir); @@ -2092,7 +2092,7 @@ TEST(cli_upsert_claude_hook_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2121,7 +2121,7 @@ TEST(cli_hook_gate_script_no_predictable_tmp_issue384) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-gate-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_install_hook_gate_script(tmpdir, "/usr/local/bin/codebase-memory-mcp"); @@ -2143,7 +2143,7 @@ TEST(cli_upsert_claude_hook_existing) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2172,7 +2172,7 @@ TEST(cli_upsert_claude_hook_replace) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2198,7 +2198,7 @@ TEST(cli_upsert_claude_hook_preserves_others) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2226,7 +2226,7 @@ TEST(cli_remove_claude_hooks) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2252,7 +2252,7 @@ TEST(cli_upsert_gemini_hook_fresh) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ghook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2273,7 +2273,7 @@ TEST(cli_upsert_gemini_hook_existing) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ghook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2299,7 +2299,7 @@ TEST(cli_upsert_gemini_hook_replace) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ghook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2324,7 +2324,7 @@ TEST(cli_remove_gemini_hooks) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-ghook-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char settingspath[512]; snprintf(settingspath, sizeof(settingspath), "%s/settings.json", tmpdir); @@ -2363,7 +2363,7 @@ TEST(cli_config_open_close) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2383,7 +2383,7 @@ TEST(cli_config_get_set) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2408,7 +2408,7 @@ TEST(cli_config_get_bool) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2440,7 +2440,7 @@ TEST(cli_config_get_int) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2463,7 +2463,7 @@ TEST(cli_config_delete) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2484,7 +2484,7 @@ TEST(cli_config_persists) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-cfg-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -2513,7 +2513,7 @@ TEST(replace_binary_overwrites_readonly) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-replace-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); } char path[512]; @@ -2554,7 +2554,7 @@ TEST(replace_binary_creates_new_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-replace2-XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); } char path[512]; diff --git a/tests/test_cs_lsp_bench.c b/tests/test_cs_lsp_bench.c index 58a9a619..bed17667 100644 --- a/tests/test_cs_lsp_bench.c +++ b/tests/test_cs_lsp_bench.c @@ -187,13 +187,9 @@ static double elapsed_ms(struct timespec t0, struct timespec t1) { } TEST(cslsp_bench_resolution_ratio) { - /* Perf benchmark: time-budgeted, so skip under CBM_SKIP_PERF (set by the - * CI dry-run). Under ASan+UBSan the budget is unattainable and an early - * assert-bail would leak the result; runs normally when perf is enabled. */ - const char *skip = getenv("CBM_SKIP_PERF"); - if (skip && skip[0] && skip[0] != '0') { - SKIP("CBM_SKIP_PERF=1 (perf benchmark)"); - } + /* Perf benchmark: time-budgeted. Under ASan+UBSan the budget is scaled + * (see the sanitizer-aware time-budget assert below); the benchmark always + * runs so regressions surface in every configuration. */ int slen = (int)strlen(bench_source); struct timespec t0; diff --git a/tests/test_discover.c b/tests/test_discover.c index 07e4a10c..af51a928 100644 --- a/tests/test_discover.c +++ b/tests/test_discover.c @@ -502,7 +502,7 @@ TEST(discover_symlink_skipped) { #ifdef _WIN32 /* Symlinks require elevated privileges on Windows — skip. * Guard the entire body: symlink() doesn't exist on Windows. */ - SKIP("symlinks need admin on Windows"); + SKIP_PLATFORM("Windows: symlinks need admin / symlink() unavailable"); #else char *base = th_mktempdir("cbm_disc_sym"); ASSERT(base != NULL); diff --git a/tests/test_framework.h b/tests/test_framework.h index 7c5635b8..2af654b4 100644 --- a/tests/test_framework.h +++ b/tests/test_framework.h @@ -66,6 +66,27 @@ static inline const char *tf_reset(void) { return -1; \ } while (0) +/* Hard failure with a message — for setup/environment failures that must NOT be + * silently skipped (a test that cannot establish its preconditions has FAILED, + * not "skipped"). Mirrors the ASSERT failure path (red FAIL + file:line). */ +#define FAIL(reason) \ + do { \ + printf(" %sFAIL%s %s:%d: %s\n", tf_red(), tf_reset(), __FILE__, __LINE__, (reason)); \ + return 1; \ + } while (0) + +/* The ONLY tolerable skip: a test that is inherently platform-specific and does + * not apply on the current OS (e.g. a Windows-only test running on macOS). + * Distinct from SKIP() so the no-skips linter (scripts/check-no-test-skips.sh) + * can allow these and reject every other skip. Use sparingly + with a reason + * that names the platform. Prefer compile-gating (#ifdef) where practical. */ +#define SKIP_PLATFORM(reason) \ + do { \ + printf("%sSKIP%s (platform: %s)\n", tf_dim(), tf_reset(), reason); \ + tf_skip_count++; \ + return -1; \ + } while (0) + /* ── Assertions ────────────────────────────────────────────────── */ #define ASSERT(cond) \ diff --git a/tests/test_incremental.c b/tests/test_incremental.c index 9e229bba..c210d543 100644 --- a/tests/test_incremental.c +++ b/tests/test_incremental.c @@ -2824,10 +2824,6 @@ SUITE(incremental) { return; } - int skip_perf = (getenv("CBM_SKIP_PERF") != NULL && - getenv("CBM_SKIP_PERF")[0] != '0' && - getenv("CBM_SKIP_PERF")[0] != '\0'); - /* Phase 1: Full index baseline (needed for tool tests below) */ RUN_TEST(incr_full_index); RUN_TEST(incr_full_has_functions); @@ -2855,39 +2851,35 @@ SUITE(incremental) { g_full_imports = get_edge_count_by_type("IMPORTS"); } - if (!skip_perf) { - /* Phase 2: Noop */ - RUN_TEST(incr_noop_reindex); + /* Phase 2: Noop */ + RUN_TEST(incr_noop_reindex); - /* Phase 3: Incremental deltas */ - RUN_TEST(incr_modify_file); - RUN_TEST(incr_formatter_run); - RUN_TEST(incr_add_file); - RUN_TEST(incr_delete_file); - RUN_TEST(incr_simultaneous_changes); + /* Phase 3: Incremental deltas */ + RUN_TEST(incr_modify_file); + RUN_TEST(incr_formatter_run); + RUN_TEST(incr_add_file); + RUN_TEST(incr_delete_file); + RUN_TEST(incr_simultaneous_changes); - /* Phase 4: Adversarial */ - RUN_TEST(incr_empty_file); - RUN_TEST(incr_syntax_error); - RUN_TEST(incr_huge_single_function); - RUN_TEST(incr_binary_content); - RUN_TEST(incr_large_generated); - RUN_TEST(incr_new_subdir); + /* Phase 4: Adversarial */ + RUN_TEST(incr_empty_file); + RUN_TEST(incr_syntax_error); + RUN_TEST(incr_huge_single_function); + RUN_TEST(incr_binary_content); + RUN_TEST(incr_large_generated); + RUN_TEST(incr_new_subdir); - /* Phase 5: Stress */ - RUN_TEST(incr_rapid_reindex); - RUN_TEST(incr_replace_file_content); - RUN_TEST(incr_batch_add_delete); + /* Phase 5: Stress */ + RUN_TEST(incr_rapid_reindex); + RUN_TEST(incr_replace_file_content); + RUN_TEST(incr_batch_add_delete); - /* Phase 6: Recovery + accuracy */ - RUN_TEST(incr_db_deleted_recovery); - RUN_TEST(incr_accuracy_vs_full); + /* Phase 6: Recovery + accuracy */ + RUN_TEST(incr_db_deleted_recovery); + RUN_TEST(incr_accuracy_vs_full); - /* Phase 7: Performance regression */ - RUN_TEST(incr_perf_single_file_fast); - } else { - printf(" [phases 2-7 SKIPPED — CBM_SKIP_PERF=1]\n"); - } + /* Phase 7: Performance regression */ + RUN_TEST(incr_perf_single_file_fast); /* Phase 8: list_projects + index_status + schema */ RUN_TEST(tool_list_projects_basic); diff --git a/tests/test_integration.c b/tests/test_integration.c index 54c969e1..3fdd24f6 100644 --- a/tests/test_integration.c +++ b/tests/test_integration.c @@ -531,9 +531,11 @@ TEST(integ_store_bfs_traversal) { SUITE(integration) { /* Set up: create temp project and index it */ if (integration_setup() != 0) { - printf(" %-50s", "integration_setup"); - printf("SKIP (setup failed)\n"); - tf_skip_count += 16; /* skip all integration tests */ + /* A suite that cannot establish its preconditions has FAILED, not + * "skipped" — surface it as a single red failure (no-skips policy). */ + printf(" %sFAIL%s %s:%d: %s\n", tf_red(), tf_reset(), __FILE__, __LINE__, + "integration_setup failed"); + tf_fail_count++; integration_teardown(); return; } diff --git a/tests/test_mem.c b/tests/test_mem.c index d5d2866d..debb9b50 100644 --- a/tests/test_mem.c +++ b/tests/test_mem.c @@ -569,7 +569,7 @@ TEST(parallel_extract_with_slab) { cbm_mem_init(0.5); if (setup_mem_test_repo() != 0) { - SKIP("tmpdir setup failed"); + FAIL("tmpdir setup failed"); } cbm_discover_opts_t opts = {.mode = CBM_MODE_FULL}; @@ -577,7 +577,7 @@ TEST(parallel_extract_with_slab) { int file_count = 0; if (cbm_discover(g_mem_tmpdir, &opts, &files, &file_count) != 0) { teardown_mem_test_repo(); - SKIP("discover failed"); + FAIL("discover failed"); } ASSERT_GTE(file_count, 5); diff --git a/tests/test_parallel.c b/tests/test_parallel.c index 98743547..1c4d3d9b 100644 --- a/tests/test_parallel.c +++ b/tests/test_parallel.c @@ -225,7 +225,7 @@ static void parity_teardown(void) { /* Node count parity */ TEST(parallel_node_count) { if (ensure_parity_setup() != 0) - SKIP("setup failed"); + FAIL("setup failed"); int seq = cbm_gbuf_node_count(g_seq_gbuf); int par = cbm_gbuf_node_count(g_par_gbuf); ASSERT_GT(seq, 0); @@ -249,7 +249,7 @@ static int assert_edge_type_parity(const char *type) { TEST(parallel_calls_parity) { int rc = assert_edge_type_parity("CALLS"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -257,7 +257,7 @@ TEST(parallel_calls_parity) { TEST(parallel_defines_parity) { int rc = assert_edge_type_parity("DEFINES"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -265,7 +265,7 @@ TEST(parallel_defines_parity) { TEST(parallel_defines_method_parity) { int rc = assert_edge_type_parity("DEFINES_METHOD"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -273,7 +273,7 @@ TEST(parallel_defines_method_parity) { TEST(parallel_imports_parity) { int rc = assert_edge_type_parity("IMPORTS"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -281,7 +281,7 @@ TEST(parallel_imports_parity) { TEST(parallel_usage_parity) { int rc = assert_edge_type_parity("USAGE"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -289,7 +289,7 @@ TEST(parallel_usage_parity) { TEST(parallel_inherits_parity) { int rc = assert_edge_type_parity("INHERITS"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } @@ -297,14 +297,14 @@ TEST(parallel_inherits_parity) { TEST(parallel_implements_parity) { int rc = assert_edge_type_parity("IMPLEMENTS"); if (rc == -1) - SKIP("setup failed"); + FAIL("setup failed"); ASSERT_EQ(rc, 0); PASS(); } TEST(parallel_total_edges) { if (ensure_parity_setup() != 0) - SKIP("setup failed"); + FAIL("setup failed"); int seq = cbm_gbuf_edge_count(g_seq_gbuf); int par = cbm_gbuf_edge_count(g_par_gbuf); ASSERT_GT(seq, 0); @@ -485,7 +485,7 @@ TEST(parallel_python_lsp_override_emits_lsp_strategy_edges) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_par_pylsp_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("mkdtemp failed"); + FAIL("mkdtemp failed"); } /* Single-file scenario: pins the in-file LSP path where py_lsp @@ -500,7 +500,7 @@ TEST(parallel_python_lsp_override_emits_lsp_strategy_edges) { snprintf(fpath0, sizeof(fpath0), "%s/app.py", tmpdir); FILE *f = fopen(fpath0, "w"); if (!f) { - SKIP("fopen app.py failed"); + FAIL("fopen app.py failed"); } fprintf(f, "class Greeter:\n" " def hello(self):\n" @@ -555,14 +555,14 @@ TEST(parallel_python_lsp_override_cross_file_emits_lsp_strategy_edges) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_par_pylsp_xf_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("mkdtemp failed"); + FAIL("mkdtemp failed"); } char gpath[512]; snprintf(gpath, sizeof(gpath), "%s/greeter.py", tmpdir); FILE *gf = fopen(gpath, "w"); if (!gf) { - SKIP("fopen greeter.py failed"); + FAIL("fopen greeter.py failed"); } fprintf(gf, "class Greeter:\n" " def hello(self):\n" @@ -575,7 +575,7 @@ TEST(parallel_python_lsp_override_cross_file_emits_lsp_strategy_edges) { if (!af) { unlink(gpath); rmdir(tmpdir); - SKIP("fopen app.py failed"); + FAIL("fopen app.py failed"); } fprintf(af, "from greeter import Greeter\n" "\n" diff --git a/tests/test_pipeline.c b/tests/test_pipeline.c index 1204137b..7af64d0a 100644 --- a/tests/test_pipeline.c +++ b/tests/test_pipeline.c @@ -144,7 +144,7 @@ TEST(pipeline_run_null) { TEST(store_file_persistence) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; snprintf(db_path, sizeof(db_path), "%s/persist_test.db", g_tmpdir); @@ -178,7 +178,7 @@ TEST(store_file_persistence) { TEST(store_bulk_persistence) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; snprintf(db_path, sizeof(db_path), "%s/bulk_test.db", g_tmpdir); @@ -216,7 +216,7 @@ TEST(store_bulk_persistence) { TEST(pipeline_structure_nodes) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -273,7 +273,7 @@ TEST(pipeline_structure_nodes) { TEST(pipeline_structure_edges) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -305,7 +305,7 @@ TEST(pipeline_structure_edges) { TEST(pipeline_project_name_derived) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } cbm_pipeline_t *p = cbm_pipeline_new(g_tmpdir, NULL, CBM_MODE_FULL); @@ -323,7 +323,7 @@ TEST(pipeline_project_name_derived) { TEST(pipeline_fast_mode) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -352,7 +352,7 @@ TEST(pipeline_fast_mode) { TEST(pipeline_definitions_function_nodes) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -397,7 +397,7 @@ TEST(pipeline_definitions_function_nodes) { TEST(pipeline_definitions_defines_edges) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -428,7 +428,7 @@ TEST(pipeline_definitions_defines_edges) { TEST(pipeline_definitions_properties) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -471,7 +471,7 @@ TEST(pipeline_definitions_properties) { TEST(pipeline_calls_resolution) { if (setup_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -914,7 +914,7 @@ TEST(usages_creates_edges) { "}\n"; if (setup_usages_repo("mypkg/main.go", go_source, "go.mod", "module testmod\ngo 1.21\n") != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -968,7 +968,7 @@ TEST(usages_no_duplicate_calls) { "}\n"; if (setup_usages_repo("mypkg/main.go", go_source, "go.mod", "module testmod\ngo 1.21\n") != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -1038,7 +1038,7 @@ TEST(usages_kotlin_creates_edges) { "}\n"; if (setup_usages_repo("Main.kt", kt_source, NULL, NULL) != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -1080,7 +1080,7 @@ TEST(usages_kotlin_no_duplicate_calls) { "}\n"; if (setup_usages_repo("Main.kt", kt_source, NULL, NULL) != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -1189,7 +1189,7 @@ TEST(pipeline_python_project) { "class DataProcessor:\n def transform(self, data):\n return data\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1235,7 +1235,7 @@ TEST(pipeline_go_cross_package_call) { "package svc\n\nfunc ProcessOrder(id string) error {\n\treturn nil\n}\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1290,7 +1290,7 @@ TEST(pipeline_python_cross_module_call) { "def process():\n result = fetch_data(\"https://example.com\")\n return result\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1342,7 +1342,7 @@ TEST(pipeline_go_type_classification) { "type ID = string\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1394,7 +1394,7 @@ TEST(pipeline_go_grouped_types) { ")\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1438,7 +1438,7 @@ TEST(pipeline_kotlin_project) { "object Config {\n val API_URL = \"https://example.com/api\"\n}\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1492,7 +1492,7 @@ TEST(pipeline_lua_anonymous_functions) { "end\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1543,7 +1543,7 @@ TEST(pipeline_csharp_modern) { "}\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1583,7 +1583,7 @@ TEST(pipeline_bom_stripping) { /* Port of TestBOMStripping — UTF-8 BOM prefix should be handled */ snprintf(g_lang_tmpdir, sizeof(g_lang_tmpdir), "/tmp/cbm_bom_XXXXXX"); if (!cbm_mkdtemp(g_lang_tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); char path[512]; snprintf(path, sizeof(path), "%s/bom.go", g_lang_tmpdir); @@ -1629,7 +1629,7 @@ TEST(pipeline_form_call_resolution) { "#endprocedure\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1683,7 +1683,7 @@ TEST(pipeline_python_type_inference) { " return result\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -1742,7 +1742,7 @@ TEST(pipeline_docstring_go_function) { "// Compute does something.\n" "func Compute() {}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -1783,7 +1783,7 @@ TEST(pipeline_docstring_python_function) { "\t\"\"\"Does something.\"\"\"\n" "\tpass\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -1824,7 +1824,7 @@ TEST(pipeline_docstring_java_method) { "\tvoid compute() {}\n" "}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -1863,7 +1863,7 @@ TEST(pipeline_docstring_kotlin_function) { const char *contents[] = {"/** Computes result. */\n" "fun compute() {}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -1903,7 +1903,7 @@ TEST(pipeline_docstring_go_class) { "// MyStruct is documented.\n" "type MyStruct struct{}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2220,7 +2220,7 @@ TEST(configures_env_var_in_config) { "\t_ = url\n" "}\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2253,7 +2253,7 @@ TEST(configures_lowercase_key_skipped) { "package main\n\nfunc main() {}\n"}; if (setup_lang_repo(files, contents, 2) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2277,7 +2277,7 @@ TEST(configures_non_config_file_skipped) { "var API_URL = \"https://api.example.com\"\n\n" "func main() {}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2322,7 +2322,7 @@ TEST(configures_full_pipeline_integration) { "}\n\n" "func readFile(path string) string { return \"\" }\n"}; if (setup_lang_repo(files, contents, 4) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2567,7 +2567,7 @@ TEST(decorator_tags_python_auto_discovery) { "def special():\n" " pass\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -2641,7 +2641,7 @@ TEST(decorator_tags_java_class_methods) { " public void updateOwner() {}\n" "}\n"}; if (setup_lang_repo(files, contents, 1) != 0) - SKIP("tmpdir"); + FAIL("tmpdir"); char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); cbm_pipeline_t *p = cbm_pipeline_new(g_lang_tmpdir, db, CBM_MODE_FULL); @@ -3868,7 +3868,7 @@ TEST(envscan_dockerfile_env_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_dock_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "Dockerfile", "FROM python:3.9-slim\n" @@ -3896,7 +3896,7 @@ TEST(envscan_shell_env_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_sh_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "setup.sh", "#!/bin/bash\n" @@ -3922,7 +3922,7 @@ TEST(envscan_env_file_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_env_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, ".env", "\nAPI_URL=https://api.example.com/v1\n" @@ -3947,7 +3947,7 @@ TEST(envscan_toml_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_toml_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "config.toml", "[service]\n" @@ -3973,7 +3973,7 @@ TEST(envscan_yaml_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_yaml_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "config.yaml", "service:\n" @@ -3997,7 +3997,7 @@ TEST(envscan_terraform_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_tf_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "variables.tf", "variable \"webhook_url\" {\n" @@ -4022,7 +4022,7 @@ TEST(envscan_properties_urls) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_prop_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "app.properties", "api.url=https://api.example.com/health\n" @@ -4043,7 +4043,7 @@ TEST(envscan_secret_key_exclusion) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_skey_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "Dockerfile", "FROM node:18\n" @@ -4070,7 +4070,7 @@ TEST(envscan_secret_value_exclusion) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_sval_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file( tmpdir, "deploy.sh", @@ -4094,7 +4094,7 @@ TEST(envscan_secret_file_exclusion) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_sfile_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); /* Secret file should be skipped */ write_temp_file(tmpdir, "credentials.sh", @@ -4126,7 +4126,7 @@ TEST(envscan_skips_ignored_dirs) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_ign_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); /* File inside .git should be skipped */ char gitdir[512]; @@ -4173,7 +4173,7 @@ TEST(envscan_non_url_values_skipped) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_envscan_nurl_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "Dockerfile", "FROM python:3.9\n" @@ -4432,7 +4432,7 @@ TEST(pipeline_fastapi_depends_edges) { "def get_profile(user = Depends(get_current_user)):\n" " return {\"user\": user}\n"}; if (setup_lang_repo(files, contents, 2) != 0) { - SKIP("tmpdir"); + FAIL("tmpdir"); } char db[512]; snprintf(db, sizeof(db), "%s/test.db", g_lang_tmpdir); @@ -4477,7 +4477,7 @@ TEST(pipeline_fastapi_depends_edges) { TEST(incremental_full_then_noop) { /* Full index, then re-run → should detect no changes and skip */ if (setup_incremental_repo() != 0) { - SKIP("setup failed"); + FAIL("setup failed"); } /* First: full index */ @@ -4515,7 +4515,7 @@ TEST(incremental_full_then_noop) { TEST(incremental_detects_changed_file) { /* Full index, modify one file, re-index → changed file re-parsed */ if (setup_incremental_repo() != 0) { - SKIP("setup failed"); + FAIL("setup failed"); } /* First: full index */ @@ -4556,7 +4556,7 @@ TEST(incremental_detects_changed_file) { TEST(incremental_detects_deleted_file) { /* Full index, delete a file, re-index → deleted file's nodes removed */ if (setup_incremental_repo() != 0) { - SKIP("setup failed"); + FAIL("setup failed"); } /* First: full index */ @@ -4592,7 +4592,7 @@ TEST(incremental_detects_deleted_file) { TEST(incremental_new_file_added) { /* Full index, add a new file, re-index → new file's nodes appear */ if (setup_incremental_repo() != 0) { - SKIP("setup failed"); + FAIL("setup failed"); } /* First: full index */ @@ -4642,7 +4642,7 @@ TEST(incremental_fast_preserves_mode_skipped_tools_dir) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_modeskip_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("tmpdir"); + FAIL("tmpdir"); } char dbpath[512]; snprintf(dbpath, sizeof(dbpath), "%s/test.db", tmpdir); @@ -4783,7 +4783,7 @@ TEST(incremental_k8s_manifest_indexed) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_k8s_incr_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("tmpdir"); + FAIL("tmpdir"); } char dbpath[512]; snprintf(dbpath, sizeof(dbpath), "%s/test.db", tmpdir); @@ -4848,7 +4848,7 @@ TEST(incremental_kustomize_module_indexed) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_kust_incr_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) { - SKIP("tmpdir"); + FAIL("tmpdir"); } char dbpath[512]; snprintf(dbpath, sizeof(dbpath), "%s/test.db", tmpdir); @@ -5441,7 +5441,7 @@ TEST(pipeline_complexity_transitive_loop_depth) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_cx_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("tmpdir"); + FAIL("tmpdir"); write_temp_file(tmpdir, "cx.go", "package p\n\n" diff --git a/tests/test_py_lsp_bench.c b/tests/test_py_lsp_bench.c index 74af98ef..67e3f9df 100644 --- a/tests/test_py_lsp_bench.c +++ b/tests/test_py_lsp_bench.c @@ -218,13 +218,9 @@ static double elapsed_ms(struct timespec t0, struct timespec t1) { } TEST(pylsp_bench_resolution_ratio) { - /* Perf benchmark: time-budgeted, so skip under CBM_SKIP_PERF (set by the - * CI dry-run). Under ASan+UBSan the budget is unattainable and an early - * assert-bail would leak the result; runs normally when perf is enabled. */ - const char *skip = getenv("CBM_SKIP_PERF"); - if (skip && skip[0] && skip[0] != '0') { - SKIP("CBM_SKIP_PERF=1 (perf benchmark)"); - } + /* Perf benchmark: time-budgeted. Under ASan+UBSan the budget is scaled up + * (see the sanitizer-aware budget below) and the result is freed before + * asserting so a budget miss doesn't leak. */ int slen = (int)strlen(bench_source); struct timespec t0; diff --git a/tests/test_simhash.c b/tests/test_simhash.c index c464dbd7..ef651e31 100644 --- a/tests/test_simhash.c +++ b/tests/test_simhash.c @@ -879,7 +879,7 @@ static void teardown_sim_test_repo(void) { TEST(pipeline_minhash_end_to_end) { if (setup_sim_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -930,7 +930,7 @@ TEST(pipeline_minhash_end_to_end) { TEST(pipeline_minhash_no_false_positives) { snprintf(g_sim_tmpdir, sizeof(g_sim_tmpdir), "/tmp/cbm_sim_nofp_XXXXXX"); if (!cbm_mkdtemp(g_sim_tmpdir)) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } /* 5 diverse functions — no clones */ @@ -1003,7 +1003,7 @@ TEST(pipeline_minhash_no_false_positives) { TEST(pipeline_minhash_incremental) { if (setup_sim_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; @@ -1066,7 +1066,7 @@ TEST(pipeline_minhash_incremental) { TEST(pipeline_minhash_incremental_new_clone) { if (setup_sim_test_repo() != 0) { - SKIP("failed to create temp dir"); + FAIL("failed to create temp dir"); } char db_path[512]; diff --git a/tests/test_vmem.c b/tests/test_vmem.c index 0da8d78b..b3e3dc9d 100644 --- a/tests/test_vmem.c +++ b/tests/test_vmem.c @@ -706,7 +706,7 @@ TEST(vmem_parallel_extract_with_slab) { cbm_vmem_init(0.5); if (setup_vmem_test_repo() != 0) { - SKIP("tmpdir setup failed"); + FAIL("tmpdir setup failed"); } cbm_discover_opts_t opts = {.mode = CBM_MODE_FULL}; @@ -714,7 +714,7 @@ TEST(vmem_parallel_extract_with_slab) { int file_count = 0; if (cbm_discover(g_vmem_tmpdir, &opts, &files, &file_count) != 0) { teardown_vmem_test_repo(); - SKIP("discover failed"); + FAIL("discover failed"); } ASSERT_GTE(file_count, 5); diff --git a/tests/test_watcher.c b/tests/test_watcher.c index 7c2fa5fe..b83c20c7 100644 --- a/tests/test_watcher.c +++ b/tests/test_watcher.c @@ -183,7 +183,7 @@ TEST(watcher_poll_this_repo) { if (!getcwd(cwd, sizeof(cwd))) { cbm_watcher_free(w); cbm_store_close(store); - SKIP("getcwd failed"); + FAIL("getcwd failed"); } cbm_watcher_watch(w, "self", cwd); @@ -233,7 +233,7 @@ TEST(watcher_detects_git_commit) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_test_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -243,7 +243,7 @@ TEST(watcher_detects_git_commit) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -286,7 +286,7 @@ TEST(watcher_detects_dirty_worktree) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_dirty_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -296,7 +296,7 @@ TEST(watcher_detects_dirty_worktree) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -332,7 +332,7 @@ TEST(watcher_detects_new_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_newf_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -342,7 +342,7 @@ TEST(watcher_detects_new_file) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -379,7 +379,7 @@ TEST(watcher_no_change_no_reindex) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_nochg_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -389,7 +389,7 @@ TEST(watcher_no_change_no_reindex) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -423,7 +423,7 @@ TEST(watcher_multiple_projects) { char tmpdirB[256]; snprintf(tmpdirB, sizeof(tmpdirB), "/tmp/cbm_watcher_mB_XXXXXX"); if (!cbm_mkdtemp(tmpdirA) || !cbm_mkdtemp(tmpdirB)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -432,7 +432,7 @@ TEST(watcher_multiple_projects) { "git add a.txt && git commit -q -m 'init'", tmpdirA); if (system(cmd) != 0) { - SKIP("git not available"); + FAIL("git not available"); } snprintf(cmd, sizeof(cmd), @@ -441,7 +441,7 @@ TEST(watcher_multiple_projects) { "git add b.txt && git commit -q -m 'init'", tmpdirB); if (system(cmd) != 0) { - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -487,7 +487,7 @@ TEST(watcher_non_git_skips) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_nongit_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Create a file so it's not empty */ { @@ -544,7 +544,7 @@ TEST(watcher_interval_blocks_repoll) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_intv_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -554,7 +554,7 @@ TEST(watcher_interval_blocks_repoll) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -620,7 +620,7 @@ TEST(watcher_git_removed_no_crash) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_rmgit_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -630,7 +630,7 @@ TEST(watcher_git_removed_no_crash) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -667,7 +667,7 @@ TEST(watcher_continued_dirty) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_cont_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -677,7 +677,7 @@ TEST(watcher_continued_dirty) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -738,7 +738,7 @@ TEST(watcher_baseline_dirty_repo) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_bld_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -748,7 +748,7 @@ TEST(watcher_baseline_dirty_repo) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } /* Make dirty BEFORE baseline */ @@ -784,7 +784,7 @@ TEST(watcher_unwatch_prunes_state) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_prune_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -794,7 +794,7 @@ TEST(watcher_unwatch_prunes_state) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -832,7 +832,7 @@ TEST(watcher_watch_after_unwatch) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_rewatch_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -842,7 +842,7 @@ TEST(watcher_watch_after_unwatch) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -895,7 +895,7 @@ TEST(watcher_detects_file_delete) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_del_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -906,7 +906,7 @@ TEST(watcher_detects_file_delete) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -942,7 +942,7 @@ TEST(watcher_detects_subdir_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_sub_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -952,7 +952,7 @@ TEST(watcher_detects_subdir_file) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1014,7 +1014,7 @@ TEST(watcher_full_flow_new_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_ffnf_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -1024,7 +1024,7 @@ TEST(watcher_full_flow_new_file) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1066,7 +1066,7 @@ TEST(watcher_fallback_still_detects) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_fb_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -1076,7 +1076,7 @@ TEST(watcher_fallback_still_detects) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1128,7 +1128,7 @@ TEST(watcher_poll_only_watched_projects) { char tmpdirB[256]; snprintf(tmpdirB, sizeof(tmpdirB), "/tmp/cbm_watcher_owB_XXXXXX"); if (!cbm_mkdtemp(tmpdirA) || !cbm_mkdtemp(tmpdirB)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; /* Init both repos */ @@ -1138,7 +1138,7 @@ TEST(watcher_poll_only_watched_projects) { "git add a.txt && git commit -q -m 'init'", tmpdirA); if (system(cmd) != 0) { - SKIP("git not available"); + FAIL("git not available"); } snprintf(cmd, sizeof(cmd), @@ -1147,7 +1147,7 @@ TEST(watcher_poll_only_watched_projects) { "git add b.txt && git commit -q -m 'init'", tmpdirB); if (system(cmd) != 0) { - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1193,7 +1193,7 @@ TEST(watcher_touch_resets_immediate) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_tch_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -1203,7 +1203,7 @@ TEST(watcher_touch_resets_immediate) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1245,7 +1245,7 @@ TEST(watcher_modify_tracked_file) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_mod_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -1255,7 +1255,7 @@ TEST(watcher_modify_tracked_file) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); @@ -1455,7 +1455,7 @@ TEST(watcher_poll_non_git_dir) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_ng2_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); /* Create a regular file so directory is not empty */ { @@ -1541,7 +1541,7 @@ TEST(watcher_callback_data_passed) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cbm_watcher_cbdata_XXXXXX"); if (!cbm_mkdtemp(tmpdir)) - SKIP("cbm_mkdtemp failed"); + FAIL("cbm_mkdtemp failed"); char cmd[512]; snprintf(cmd, sizeof(cmd), @@ -1551,7 +1551,7 @@ TEST(watcher_callback_data_passed) { tmpdir); if (system(cmd) != 0) { th_rmtree(tmpdir); - SKIP("git not available"); + FAIL("git not available"); } cbm_store_t *store = cbm_store_open_memory(); diff --git a/tests/test_worker_pool.c b/tests/test_worker_pool.c index cef1516c..b1253f26 100644 --- a/tests/test_worker_pool.c +++ b/tests/test_worker_pool.c @@ -194,10 +194,10 @@ TEST(parallel_for_actually_parallel) { atomic_init(&cc.concurrent_now, 0); cbm_parallel_for_opts_t opts = {.max_workers = 4, .force_pthreads = false}; cbm_parallel_for(100, concurrency_worker, &cc, opts); - /* At least 2 threads ran concurrently (skip on single-core CI runners) */ - if (atomic_load(&cc.concurrent_max) < 2) { - SKIP("single-core runner — cannot verify parallelism"); - } + /* At least 2 of the 4 workers must have run concurrently. No skip: every CI + * runner is multi-core, so failing to demonstrate parallelism here is a real + * failure of the invariant, not an environment we silently pass over. */ + ASSERT_GTE(atomic_load(&cc.concurrent_max), 2); PASS(); }