run.sh 5.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/env bash
  2. # Self-test for testing-ops — fully offline, deterministic, Linux-safe.
  3. #
  4. # coverage-check.sh gates a project on a coverage threshold. To exercise its
  5. # threshold logic WITHOUT running a slow real pytest suite, the script exposes
  6. # an offline test seam (CM_COVERAGE_OVERRIDE=PCT) that substitutes a given
  7. # percentage for the live measurement — the same pattern check-ytdlp-version.sh
  8. # uses for its installed/latest versions. Asserts the --help contract, semantic
  9. # exit codes (0 pass / 1 below / 2 usage / 5 missing-dep), and stream separation
  10. # (the verdict on stdout; banners + pytest on stderr). Never invokes real pytest.
  11. #
  12. # Usage: bash tests/run.sh
  13. # Exit: 0 all pass, 1 one or more failures
  14. set -uo pipefail
  15. HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  16. SKILL="$(dirname "$HERE")"
  17. V="$SKILL/scripts/coverage-check.sh"
  18. SB="$(mktemp -d)"; trap 'rm -rf "$SB"' EXIT
  19. PASS=0; FAIL=0
  20. ok() { PASS=$((PASS+1)); printf ' PASS %s\n' "$1"; }
  21. no() { FAIL=$((FAIL+1)); printf ' FAIL %s\n' "$1"; }
  22. expect_exit() { [[ "$2" == "$3" ]] && ok "$1 (exit $3)" || no "$1 (want $2 got $3)"; }
  23. expect_has() { case "$3" in *"$2"*) ok "$1";; *) no "$1 (missing '$2')";; esac; }
  24. echo "=== testing-ops self-test ==="
  25. # ── contract ──────────────────────────────────────────────────────────────────
  26. echo "-- contract --"
  27. bash -n "$V" 2>/dev/null && ok "bash -n coverage-check.sh" || no "bash -n coverage-check.sh"
  28. bash "$V" --help >/dev/null 2>&1; expect_exit "--help exits 0" 0 $?
  29. bash "$V" -h >/dev/null 2>&1; expect_exit "-h exits 0" 0 $?
  30. out="$(bash "$V" --help 2>/dev/null)"
  31. expect_has "--help has Examples" "xamples" "$out"
  32. expect_has "--help documents exit 1 (below)" "below threshold" "$out"
  33. expect_has "--help documents exit 2 (usage)" "usage" "$out"
  34. expect_has "--help documents exit 5 (missing-dep)" "pytest missing" "$out"
  35. expect_has "--help names the test seam" "CM_COVERAGE_OVERRIDE" "$out"
  36. bash "$V" --bogus >/dev/null 2>&1; expect_exit "unknown flag -> 2" 2 $?
  37. bash "$V" --threshold >/dev/null 2>&1; expect_exit "--threshold needs value -> 2" 2 $?
  38. bash "$V" --threshold notnum >/dev/null 2>&1; expect_exit "--threshold non-numeric -> 2" 2 $?
  39. CM_COVERAGE_OVERRIDE=bogus bash "$V" --threshold 80 >/dev/null 2>&1; expect_exit "bad override -> 2" 2 $?
  40. # ── threshold logic (offline seam; no real pytest) ───────────────────────────
  41. echo "-- threshold logic (seamed) --"
  42. CM_COVERAGE_OVERRIDE=90 bash "$V" --threshold 80 >/dev/null 2>&1; expect_exit "90>=80 -> pass 0" 0 $?
  43. CM_COVERAGE_OVERRIDE=80 bash "$V" --threshold 80 >/dev/null 2>&1; expect_exit "80>=80 boundary -> pass 0" 0 $?
  44. CM_COVERAGE_OVERRIDE=79 bash "$V" --threshold 80 >/dev/null 2>&1; expect_exit "79<80 -> below 1" 1 $?
  45. CM_COVERAGE_OVERRIDE=72 bash "$V" --threshold 80 >/dev/null 2>&1; expect_exit "72<80 -> below 1" 1 $?
  46. CM_COVERAGE_OVERRIDE=100 bash "$V" --threshold 99.5 >/dev/null 2>&1; expect_exit "100>=99.5 float -> pass 0" 0 $?
  47. CM_COVERAGE_OVERRIDE=99.4 bash "$V" --threshold 99.5 >/dev/null 2>&1; expect_exit "99.4<99.5 float -> below 1" 1 $?
  48. # default threshold is 80 when --threshold is omitted
  49. CM_COVERAGE_OVERRIDE=79 bash "$V" >/dev/null 2>&1; expect_exit "default threshold 80: 79 -> below 1" 1 $?
  50. CM_COVERAGE_OVERRIDE=81 bash "$V" >/dev/null 2>&1; expect_exit "default threshold 80: 81 -> pass 0" 0 $?
  51. # ── stream separation (verdict on stdout; no banner leaks) ───────────────────
  52. echo "-- stream separation --"
  53. out="$(CM_COVERAGE_OVERRIDE=90 bash "$V" --threshold 80 2>/dev/null)"; rc=$?
  54. expect_exit "seamed pass exit 0" 0 "$rc"
  55. expect_has "stdout verdict is pass" "pass" "$out"
  56. expect_has "stdout verdict carries threshold" "80" "$out"
  57. case "$out" in *$'\n'*) no "stdout has more than one line";; *) ok "stdout is a single verdict line";; esac
  58. case "$out" in *"==="*) no "banner leaked onto stdout";; *) ok "no banner on stdout";; esac
  59. out="$(CM_COVERAGE_OVERRIDE=72 bash "$V" --threshold 80 2>/dev/null)"; rc=$?
  60. expect_exit "seamed fail exit 1" 1 "$rc"
  61. expect_has "stdout verdict is fail" "fail" "$out"
  62. case "$out" in *"==="*) no "banner leaked onto stdout (fail)";; *) ok "no banner on stdout (fail)";; esac
  63. # ── missing-dep path: no seam AND no pytest -> exit 5 with install hint ───────
  64. echo "-- missing-dep --"
  65. # Scrub PATH so a host-installed pytest is not resolvable, keeping the suite
  66. # offline and deterministic regardless of host tooling (bash itself stays
  67. # resolvable under /usr/bin:/bin). If pytest somehow survives the scrub, SKIP
  68. # rather than ever launching a real suite.
  69. if PATH=/usr/bin:/bin command -v pytest >/dev/null 2>&1; then
  70. echo " SKIP missing-dep exit 5 (pytest resolvable even under scrubbed PATH)"
  71. else
  72. out="$(PATH=/usr/bin:/bin bash "$V" 2>&1)"; rc=$?
  73. expect_exit "no pytest, no seam -> 5" 5 "$rc"
  74. expect_has "names pytest install hint" "pytest" "$out"
  75. case "$out" in *"pip install pytest"*) ok "hint suggests install";; *) no "hint missing install suggestion";; esac
  76. fi
  77. echo ""
  78. echo "=== $PASS passed, $FAIL failed ==="
  79. [[ "$FAIL" -eq 0 ]] || exit 1
  80. exit 0