#!/usr/bin/env bash # lib/tests/gstack-removed.test.sh — GSTACK_REMOVED denylist honored by # every "bring gstack back" path: profile.sh `gstack on` and # toggle-external.sh `enable gstack` both skip a policy-removed name and # leave it parked, restoring only what policy allows; gstack_is_removed() # itself, positive + negative. Covers contract criterion 17. Hermetic: # fixture repo via PROFILE_REPO_OVERRIDE / TOGGLE_EXTERNAL_REPO_OVERRIDE — # same harness as lib/tests/profile-default.test.sh and # lib/tests/toggle-external-repo-resolution.test.sh. set -u ROOT="$(cd "$(dirname "$0")/../.." && pwd)" pass=0; fail=0 check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1)); printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; } check_has() { case "$2" in *"$3"*) pass=$((pass+1));; *) fail=$((fail+1)); printf 'FAIL %s: [%s] does not contain [%s]\n' "$1" "$2" "$3";; esac; } check_not() { case "$2" in *"$3"*) fail=$((fail+1)); printf 'FAIL %s: [%s] unexpectedly contains [%s]\n' "$1" "$2" "$3";; *) pass=$((pass+1));; esac; } # mk_fixture — minimal repo: profile.sh + toggle-external.sh + # gstack-removed.sh under lib/, one removed name (ship) and one kept name # (browse) parked in skills-disabled/. mk_fixture() { local fx="$1" mkdir -p "$fx/skills" "$fx/skills-disabled/gstack__ship" \ "$fx/skills-disabled/gstack__browse" "$fx/lib" cp "$ROOT/lib/profile.sh" "$ROOT/lib/toggle-external.sh" \ "$ROOT/lib/gstack-removed.sh" "$fx/lib/" } # --- T1-T5: profile.sh gstack on restores browse, skips + parks ship --- FX1="$(mktemp -d)"; mk_fixture "$FX1" out="$(PROFILE_REPO_OVERRIDE="$FX1" bash "$FX1/lib/profile.sh" gstack on 2>&1)" check T1-browse-restored "$([ -e "$FX1/skills/browse" ] && echo on || echo off)" on check T2-ship-parked "$([ -e "$FX1/skills-disabled/gstack__ship" ] && echo p || echo n)" p check T3-ship-not-live "$([ -e "$FX1/skills/ship" ] && echo on || echo off)" off check_has T4-skip-names-ship "$out" "ship" check_has T5-real-count "$out" "1 parked gstack skills restored" rm -rf "$FX1" # --- T6-T9: toggle-external.sh enable gstack — same skip + restore --- FX2="$(mktemp -d)"; mk_fixture "$FX2" out="$(TOGGLE_EXTERNAL_REPO_OVERRIDE="$FX2" bash "$FX2/lib/toggle-external.sh" enable gstack 2>&1)" check T6-browse-restored "$([ -e "$FX2/skills/browse" ] && echo on || echo off)" on check T7-ship-parked "$([ -e "$FX2/skills-disabled/gstack__ship" ] && echo p || echo n)" p check T8-ship-not-live "$([ -e "$FX2/skills/ship" ] && echo on || echo off)" off check_has T9-skip-names-ship "$out" "ship" rm -rf "$FX2" # --- T10-T11: toggle-external.sh, only removed names parked — 0 restored, # the policy message fires instead of the "re-run gstack setup" hint --- FX3="$(mktemp -d)" mkdir -p "$FX3/skills" "$FX3/skills-disabled/gstack__ship" "$FX3/lib" cp "$ROOT/lib/toggle-external.sh" "$ROOT/lib/gstack-removed.sh" "$FX3/lib/" out="$(TOGGLE_EXTERNAL_REPO_OVERRIDE="$FX3" bash "$FX3/lib/toggle-external.sh" enable gstack 2>&1)" check_has T10-policy-msg "$out" "policy-removed skills remain parked" check_not T11-no-setup-hint "$out" "re-run gstack setup" rm -rf "$FX3" # --- T12-T13: gstack_is_removed() itself, positive + negative --- # shellcheck source=lib/gstack-removed.sh disable=SC1091 source "$ROOT/lib/gstack-removed.sh" gstack_is_removed ship; check T12-removed-positive "$?" 0 gstack_is_removed browse; check T13-removed-negative "$?" 1 printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]