#!/usr/bin/env bash # tests/test_fixes.sh - unit tests for code-review fixes in ai-setup.sh # Run: bash tests/test_fixes.sh set -euo pipefail SCRIPT="$(cd "$(dirname "$0")/.." && pwd)/scripts/ai-setup.sh" GLOBAL_RULES_SOURCE="$(cd "$(dirname "$0")/.." && pwd)/home-configs/GLOBAL_RULES.md" PASS=0; FAIL=0 ok() { echo "[PASS] $1"; PASS=$((PASS+1)); } fail() { echo "[FAIL] $1"; FAIL=$((FAIL+1)); } # Extract sections GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT") KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$SCRIPT") GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT") HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT") # ── ai-gpt: auto-install codex ──────────────────────────────────────────── test_gpt_autoinstall() { if echo "$GPT_SECTION" | grep -q 'curl -fsSL https://chatgpt.com/codex/install.sh'; then ok "ai-gpt: auto-installs codex via official install script" else fail "ai-gpt: missing codex auto-install" fi } # ── ai-gpt: no proxy logic (simplified launcher) ────────────────────────── test_gpt_no_proxy() { if echo "$GPT_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then fail "ai-gpt: still contains proxy logic (ANTHROPIC_BASE_URL)" else ok "ai-gpt: proxy logic removed (no ANTHROPIC_BASE_URL)" fi } # ── ai-kimi: launches claude with Kimi backend ──────────────────────────── test_kimi_claude_launcher() { if echo "$KIMI_SECTION" | grep -q 'claude --dangerously-skip-permissions' \ && echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then ok "ai-kimi: launches claude with ANTHROPIC_BASE_URL set" else fail "ai-kimi: must launch claude with ANTHROPIC_BASE_URL" fi } # ── ai-kimi: uses official Kimi API ────────────────────────────────────── test_kimi_official_api() { if echo "$KIMI_SECTION" | grep -q 'api.kimi.com/coding' \ && echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=kimi-k2.7' \ && echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL=kimi-k2.6' \ && ! echo "$KIMI_SECTION" | grep -q 'artemox'; then ok "ai-kimi: uses official Kimi API (K2.7 opus/sonnet, K2.6 haiku)" else fail "ai-kimi: must use official Kimi API (api.kimi.com/coding) with K2.7 opus/sonnet, K2.6 haiku" fi } # ── ai-kimi: no artemox or config.toml logic ───────────────────────────── test_kimi_no_artemox() { if echo "$KIMI_SECTION" | grep -q 'config.toml' || echo "$KIMI_SECTION" | grep -q 'artemox'; then fail "ai-kimi: still contains Artemox or config.toml logic" else ok "ai-kimi: Artemox and config.toml logic removed" fi } # ── ai-gemini: native launcher generation ───────────────────────────────── test_gemini_native_launcher() { if echo "$GEMINI_SECTION" | grep -q 'antigravity CLI (agy)' \ && echo "$GEMINI_SECTION" | grep -q 'https://antigravity.google/cli/install.sh'; then ok "ai-gemini: native agy launcher is generated" else fail "ai-gemini: missing native agy launcher generation" fi } # ── global rules: Karpathy-style guidelines and native rule files ─────────── test_global_rules_include_quality_guidelines() { karpathy_line=$(grep -n '^## 1\. Think Before Coding$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1) global_line=$(grep -n '^# Global Rules for All AI Agents$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1) if [ -n "$karpathy_line" ] \ && [ -n "$global_line" ] \ && [ "$karpathy_line" -lt "$global_line" ] \ && grep -q 'Always reply in Russian' "$GLOBAL_RULES_SOURCE" \ && grep -q 'Plain git diff visibility' "$GLOBAL_RULES_SOURCE" \ && grep -q 'GLOBAL_RULES_SOURCE=' "$SCRIPT" \ && grep -q 'cp "$GLOBAL_RULES_SOURCE" "$CONFIG_DIR/global_rules.md"' "$SCRIPT"; then ok "global rules: source file includes English Karpathy guidelines before user rules" else fail "global rules: missing source file, English Karpathy guidelines, or user rules" fi } test_native_rule_files_generated() { if grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.codex/AGENTS.md"' "$SCRIPT" \ && grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.kimi-code/AGENTS.md"' "$SCRIPT" \ && grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.claude/CLAUDE.md"' "$SCRIPT" \ && grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.gemini/GEMINI.md"' "$SCRIPT" \ && echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.codex/AGENTS.md"' \ && echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.kimi-code/AGENTS.md"' \ && echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.claude/CLAUDE.md"' \ && echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.gemini/GEMINI.md"' \ && ! echo "$HELPERS_SECTION" | grep -q 'echo "$rendered" >'; then ok "global rules: setup and launchers write native rule files from global_rules.md" else fail "global rules: setup and launchers must write native rule files from global_rules.md" fi } # ── Fix 7: trap quotes $TMP correctly ──────────────────────────────────────── test_fix7_trap_tmp() { if grep -q "trap 'rm -rf \"\$TMP\"' EXIT" "$SCRIPT"; then ok "Fix7: trap uses single quotes with quoted \"\$TMP\"" else fail "Fix7: trap still uses double quotes or \$TMP still unquoted at execution" fi } # ── bash syntax of the whole script ───────────────────────────────────────── test_script_syntax() { if bash -n "$SCRIPT" 2>&1; then ok "syntax: ai-setup.sh passes 'bash -n'" else fail "syntax: ai-setup.sh has syntax errors" fi } # ── run all tests ───────────────────────────────────────────────────────────── test_script_syntax test_gpt_autoinstall test_gpt_no_proxy test_kimi_claude_launcher test_kimi_official_api test_kimi_no_artemox test_gemini_native_launcher test_global_rules_include_quality_guidelines test_native_rule_files_generated test_fix7_trap_tmp echo "" echo "Results: $PASS passed, $FAIL failed" [ "$FAIL" -eq 0 ] && exit 0 || exit 1