From efe3d7bc8df058310ccfd831db35e3291aad048d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 19 Mar 2026 00:44:44 +0000 Subject: [PATCH] test: add Java project test coverage for suggest-optimize hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 7 bats tests covering the Java path in the stop hook: - configured + installed → run codeflash - configured + not installed → install prompt - not configured + installed → setup prompt (codeflash init) - not configured + not installed → install prompt - auto-allow instructions when settings.json missing - omits auto-allow when already configured - codeflash.toml takes precedence over pyproject.toml Also adds helpers: add_java_commit, create_codeflash_toml, setup_mock_codeflash. Co-Authored-By: Claude Opus 4.6 --- tests/helpers/setup.bash | 50 ++++++++++++++ tests/test_suggest_optimize.bats | 114 +++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/tests/helpers/setup.bash b/tests/helpers/setup.bash index 4302c5c..5bff730 100644 --- a/tests/helpers/setup.bash +++ b/tests/helpers/setup.bash @@ -83,6 +83,17 @@ add_ts_commit() { git -C "$REPO" commit -m "add $file" >/dev/null 2>&1 } +add_java_commit() { + local file="${1:-App.java}" + mkdir -p "$REPO/$(dirname "$file")" + echo "public class App { public static void main(String[] args) {} }" > "$REPO/$file" + git -C "$REPO" add -A >/dev/null 2>&1 + local ts + ts=$(future_timestamp) + GIT_COMMITTER_DATE="@$ts" GIT_AUTHOR_DATE="@$ts" \ + git -C "$REPO" commit -m "add $file" >/dev/null 2>&1 +} + add_irrelevant_commit() { local file="${1:-data.txt}" echo "some data" > "$REPO/$file" @@ -173,6 +184,45 @@ EOF git -C "$REPO" commit -m "add package.json" --allow-empty >/dev/null 2>&1 } +# Create codeflash.toml (Java). configured=true adds [tool.codeflash]. +create_codeflash_toml() { + local configured="${1:-true}" + if [ "$configured" = "true" ]; then + cat > "$REPO/codeflash.toml" << 'EOF' +[tool.codeflash] +module-root = "src/main/java" +tests-root = "src/test/java" +EOF + else + cat > "$REPO/codeflash.toml" << 'EOF' +# empty config +EOF + fi + git -C "$REPO" add -A >/dev/null 2>&1 + git -C "$REPO" commit -m "add codeflash.toml" --allow-empty >/dev/null 2>&1 +} + +# Create a mock codeflash binary in MOCK_BIN (for Java tests without venv). +# Usage: setup_mock_codeflash [installed=true] +setup_mock_codeflash() { + local installed="${1:-true}" + mkdir -p "$MOCK_BIN" + + if [ "$installed" = "true" ]; then + cat > "$MOCK_BIN/codeflash" << 'MOCK' +#!/bin/bash +echo "codeflash 0.1.0" +exit 0 +MOCK + else + cat > "$MOCK_BIN/codeflash" << 'MOCK' +#!/bin/bash +exit 127 +MOCK + fi + chmod +x "$MOCK_BIN/codeflash" +} + # Create .claude/settings.json with Bash(*codeflash*) auto-allowed create_auto_allow() { mkdir -p "$REPO/.claude" diff --git a/tests/test_suggest_optimize.bats b/tests/test_suggest_optimize.bats index 2e74e80..0499372 100755 --- a/tests/test_suggest_optimize.bats +++ b/tests/test_suggest_optimize.bats @@ -462,4 +462,118 @@ setup() { run run_hook false "PATH=$MOCK_BIN:$PATH" assert_block assert_reason_contains "npx codeflash --subagent" +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# Java projects +# ═══════════════════════════════════════════════════════════════════════════════ + +# Setup: codeflash.toml with [tool.codeflash]. Mock codeflash binary in PATH. +# One .java file committed after session start. +# Validates: The Java "happy path" — codeflash.toml is configured, codeflash +# binary is available in PATH. The hook instructs Claude to run +# `codeflash --subagent` in the background. +# Expected: Block with reason containing "codeflash --subagent" and +# "run_in_background". +@test "java: configured + codeflash installed → run codeflash" { + add_java_commit + create_codeflash_toml true + setup_mock_codeflash true + + run run_hook false "PATH=$MOCK_BIN:$PATH" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "codeflash --subagent" + assert_reason_contains "run_in_background" +} + +# Setup: codeflash.toml with [tool.codeflash]. No codeflash binary in PATH. +# One .java commit. +# Validates: When codeflash is configured but the binary is not installed, +# the hook should prompt to install it with pip. +# Expected: Block with reason containing "pip install codeflash". +@test "java: configured + NOT installed → install prompt" { + add_java_commit + create_codeflash_toml true + + # Use PATH without codeflash: MOCK_BIN (empty) + system dirs, but not dirs containing codeflash + run run_hook false "PATH=$MOCK_BIN:/usr/bin:/bin" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "pip install codeflash" +} + +# Setup: codeflash.toml exists but has NO [tool.codeflash] section. +# Mock codeflash binary is available. One .java commit. +# Validates: When codeflash is installed but not configured, the hook should +# prompt to run `codeflash init --yes` for auto-configuration. +# Expected: Block with reason containing "codeflash init --yes". +@test "java: NOT configured + installed → setup prompt" { + add_java_commit + create_codeflash_toml false + setup_mock_codeflash true + + run run_hook false "PATH=$MOCK_BIN:$PATH" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "init --yes" +} + +# Setup: codeflash.toml exists but has NO [tool.codeflash] section. +# No codeflash binary in PATH. One .java commit. +# Validates: When neither configured nor installed, the hook should prompt +# to install first then configure. +# Expected: Block with reason containing "pip install codeflash". +@test "java: NOT configured + NOT installed → install prompt" { + add_java_commit + create_codeflash_toml false + + # Use PATH without codeflash: MOCK_BIN (empty) + system dirs, but not dirs containing codeflash + run run_hook false "PATH=$MOCK_BIN:/usr/bin:/bin" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "pip install codeflash" +} + +# Setup: codeflash.toml with [tool.codeflash]. Mock codeflash in PATH. +# No .claude/settings.json exists. One .java commit. +# Validates: Java path also appends auto-allow instructions when settings.json +# is missing. +# Expected: Block with reason containing "permissions.allow". +@test "java: includes auto-allow instructions when settings.json missing" { + add_java_commit + create_codeflash_toml true + setup_mock_codeflash true + + run run_hook false "PATH=$MOCK_BIN:$PATH" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "permissions.allow" +} + +# Setup: codeflash.toml configured. Mock codeflash in PATH. +# .claude/settings.json already has Bash(*codeflash*). One .java commit. +# Validates: Java path omits auto-allow when already configured. +# Expected: Block with reason NOT containing "permissions.allow". +@test "java: omits auto-allow when already configured" { + add_java_commit + create_codeflash_toml true + setup_mock_codeflash true + create_auto_allow + + run run_hook false "PATH=$MOCK_BIN:$PATH" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_not_contains "permissions.allow" +} + +# Setup: codeflash.toml with [tool.codeflash] exists alongside pyproject.toml. +# One .java commit. Mock codeflash in PATH. +# Validates: codeflash.toml takes precedence over pyproject.toml in project +# detection, ensuring Java projects are correctly identified. +# Expected: Block with "Java files" in reason (not "Python files"). +@test "java: codeflash.toml takes precedence over pyproject.toml" { + add_java_commit + create_codeflash_toml true + create_pyproject true + setup_mock_codeflash true + + run run_hook false "PATH=$MOCK_BIN:$PATH" "CODEFLASH_API_KEY=cf-test-key" + assert_block + assert_reason_contains "Java files" + assert_reason_not_contains "Python files" } \ No newline at end of file