#!/usr/bin/env bash # test-test-quality-gate.sh — Integration-style tests for validate-test-quality.sh. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" PASS_COUNT=0 FAIL_COUNT=0 declare -a TMP_REPOS=() log() { echo "[test-quality-test] $*" } pass() { PASS_COUNT=$((PASS_COUNT + 1)) log "PASS: $*" } fail() { FAIL_COUNT=$((FAIL_COUNT + 1)) log "FAIL: $*" } require_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "Missing required command: $1" exit 1 fi } run_expect_success() { local label="$1" shift if "$@" >/tmp/test-quality-gate.out 2>&1; then pass "$label" else fail "$label" cat /tmp/test-quality-gate.out fi } run_expect_failure() { local label="$1" shift if "$@" >/tmp/test-quality-gate.out 2>&1; then fail "$label (expected failure but command succeeded)" cat /tmp/test-quality-gate.out else pass "$label" fi } create_fixture_repo() { local repo repo="$(mktemp -d)" mkdir -p "$repo/scripts" \ "$repo/audit" \ "$repo/androidApp/src/androidTest/kotlin/example" \ "$repo/iosApp/iosAppUITests" cp "$PROJECT_ROOT/scripts/validate-test-quality.sh" "$repo/scripts/" chmod +x "$repo/scripts/validate-test-quality.sh" cat > "$repo/androidApp/src/androidTest/kotlin/example/ExampleUiTest.kt" <<'EOF' package example import org.junit.Test class ExampleUiTest { @Test fun usesAntiPatternsForFixture() { Thread.sleep(5) try { // fixture-only } catch (e: AssertionError) { // fixture-only } } } EOF cat > "$repo/iosApp/iosAppUITests/ExampleUiTests.swift" <<'EOF' import XCTest final class ExampleUiTests: XCTestCase { func testFixtureUsesAntiPatterns() { sleep(1) if XCUIApplication().buttons["Example"].exists { XCTAssertTrue(true) } } } EOF cat > "$repo/audit/test-quality-baseline.json" <<'EOF' { "version": 1, "generated_at": "2026-02-20T16:00:00Z", "metrics": [ { "id": "android_thread_sleep_calls", "description": "Android Thread.sleep", "mode": "rg", "root": "androidApp/src/androidTest", "glob": "*.kt", "pattern": "Thread\\.sleep\\(", "baseline": 1, "allowed_growth": 0 }, { "id": "android_assertionerror_catches", "description": "Android AssertionError catches", "mode": "rg", "root": "androidApp/src/androidTest", "glob": "*.kt", "pattern": "catch \\([^\\)]*AssertionError", "baseline": 1, "allowed_growth": 0 }, { "id": "ios_sleep_calls", "description": "iOS sleep calls", "mode": "rg", "root": "iosApp/iosAppUITests", "glob": "*.swift", "pattern": "\\bsleep\\(", "baseline": 1, "allowed_growth": 0 }, { "id": "ios_conditional_exists_guards_in_test_bodies", "description": "iOS conditional exists checks in test bodies", "mode": "swift_test_body_pattern", "root": "iosApp/iosAppUITests", "glob": "*.swift", "pattern": "if[[:space:]]+[^\\n]*\\.exists", "baseline": 1, "allowed_growth": 0 }, { "id": "ios_noop_assert_true", "description": "iOS no-op assertTrue(true) in test bodies", "mode": "swift_test_body_pattern", "root": "iosApp/iosAppUITests", "glob": "*.swift", "pattern": "XCTAssertTrue\\(true\\)", "baseline": 1, "allowed_growth": 0 }, { "id": "ios_empty_test_bodies", "description": "iOS empty or comment-only test bodies", "mode": "rg_multiline", "root": "iosApp/iosAppUITests", "glob": "*.swift", "pattern": "(?s)func\\s+test[[:alnum:]_]+\\s*\\([^)]*\\)\\s*(?:throws\\s*)?\\{\\s*(?:(?://[^\\n]*\\n)\\s*)*\\}", "baseline": 0, "allowed_growth": 0 }, { "id": "ios_placeholder_test_markers", "description": "iOS placeholder markers in test bodies", "mode": "swift_test_body_pattern", "root": "iosApp/iosAppUITests", "glob": "*.swift", "pattern": "(TODO|FIXME|placeholder|no-op)", "baseline": 0, "allowed_growth": 0 } ] } EOF TMP_REPOS+=("$repo") echo "$repo" } test_baseline_pass() { local repo repo="$(create_fixture_repo)" run_expect_success "validate-test-quality passes when metrics match baseline" \ bash -lc "cd '$repo' && scripts/validate-test-quality.sh" } test_growth_fails() { local repo repo="$(create_fixture_repo)" echo "Thread.sleep(10)" >> "$repo/androidApp/src/androidTest/kotlin/example/ExampleUiTest.kt" run_expect_failure "validate-test-quality fails when metric grows past threshold" \ bash -lc "cd '$repo' && scripts/validate-test-quality.sh" } test_allowed_growth_passes() { local repo repo="$(create_fixture_repo)" local tmp tmp="$(mktemp)" jq '(.metrics[] | select(.id == "ios_sleep_calls") | .allowed_growth) = 1' \ "$repo/audit/test-quality-baseline.json" > "$tmp" mv "$tmp" "$repo/audit/test-quality-baseline.json" echo "sleep(1)" >> "$repo/iosApp/iosAppUITests/ExampleUiTests.swift" run_expect_success "validate-test-quality honors allowed_growth threshold" \ bash -lc "cd '$repo' && scripts/validate-test-quality.sh" } main() { require_cmd jq require_cmd rg require_cmd awk test_baseline_pass test_growth_fails test_allowed_growth_passes log "Summary: pass=$PASS_COUNT fail=$FAIL_COUNT" if [[ "$FAIL_COUNT" -gt 0 ]]; then exit 1 fi return 0 } cleanup() { local repo for repo in "${TMP_REPOS[@]:-}"; do [[ -d "$repo" ]] && rm -rf "$repo" done rm -f /tmp/test-quality-gate.out return 0 } trap cleanup EXIT main "$@"