#!/usr/bin/env bash
# Comprehensive tests for the config script
# Tests: init, file, save, list, get, set, add, update, clean, delete, discover

#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x
TEST_CATEGORY=core

level=$1
if [ -z "$level" ]; then
  level=1
else
  shift
fi
info.log "starting: ${BASH_SOURCE[@]##*/} <LOG_LEVEL=$level>"

source this
source test.suite
source $OOSH_DIR/config

log.level $level

# Save original config state
ORIGINAL_CONFIG=$CONFIG
ORIGINAL_CONFIG_PATH=$CONFIG_PATH
ORIGINAL_CONFIG_FILE=$CONFIG_FILE

# Test directory for isolation
TEST_CONFIG_PATH="/tmp/test.config.$(id -u).$$"
mkdir -p "$TEST_CONFIG_PATH"

# Cleanup function
cleanup_test_config() {
  rm -rf "$TEST_CONFIG_PATH" 2>/dev/null
  export CONFIG=$ORIGINAL_CONFIG
  export CONFIG_PATH=$ORIGINAL_CONFIG_PATH
  export CONFIG_FILE=$ORIGINAL_CONFIG_FILE
}

# Setup test environment
setup_test_config() {
  export CONFIG_PATH="$TEST_CONFIG_PATH"
  export CONFIG_FILE="test.env"
  export CONFIG="$CONFIG_PATH/$CONFIG_FILE"
  touch "$CONFIG"
}

# ============================================================================
# T1: Test config.init sets up CONFIG variables
# ============================================================================
test.case - "T1: config.init creates CONFIG_PATH and sets CONFIG" \
  config.init

if [ -d "$CONFIG_PATH" ] && [ -n "$CONFIG" ]; then
  create.result 0 "CONFIG initialized"
else
  create.result 1 "CONFIG_PATH=$CONFIG_PATH CONFIG=$CONFIG"
fi
expect 0 "CONFIG initialized" "config.init sets up environment"

# Reset to test environment
setup_test_config

# ============================================================================
# T2: Test config.file without args returns current file
# ============================================================================
test.case - "T2: config.file returns current file" \
  echo "checking"

CURRENT_FILE=$(config.file)
if [ "$CURRENT_FILE" = "$CONFIG_FILE" ]; then
  create.result 0 "file returned"
else
  create.result 1 "got: $CURRENT_FILE expected: $CONFIG_FILE"
fi
expect 0 "file returned" "config.file returns current file"

# ============================================================================
# T3: Test config.file sets new file
# ============================================================================
test.case - "T3: config.file sets new file" \
  config.file newtest.env

if [ "$CONFIG_FILE" = "newtest.env" ]; then
  create.result 0 "file changed"
else
  create.result 1 "CONFIG_FILE=$CONFIG_FILE"
fi
expect 0 "file changed" "config.file sets new file"

# Reset
setup_test_config

# ============================================================================
# T4: Test config.file.check with existing file
# ============================================================================
touch "$CONFIG_PATH/exists.env"
test.case - "T4: config.file.check finds existing file" \
  config.file.check exists

if [ "$RETURN_VALUE" -eq 0 ]; then
  create.result 0 "found exists.env"
else
  create.result 1 "not found"
fi
expect 0 "found exists.env" "config.file.check finds existing file"

# ============================================================================
# T5: Test config.save creates config file
# ============================================================================
export TEST_CONFIG_VAR1="value1"
export TEST_CONFIG_VAR2="value2"
setup_test_config

test.case - "T5: config.save creates file" \
  config.save testcfg TEST_CONFIG

if [ -f "$CONFIG_PATH/testcfg.env" ]; then
  create.result 0 "testcfg.env created"
else
  create.result 1 "testcfg.env missing"
fi
expect 0 "testcfg.env created" "config.save creates file"

# ============================================================================
# T6: Test config.save captures prefixed variables
# ============================================================================
test.case - "T6: config.save captures prefixed variables" \
  echo "checking saved content"

SAVED_CONTENT=$(cat "$CONFIG_PATH/testcfg.env" 2>/dev/null)
if echo "$SAVED_CONTENT" | grep -q "TEST_CONFIG_VAR1" && \
   echo "$SAVED_CONTENT" | grep -q "TEST_CONFIG_VAR2"; then
  create.result 0 "variables saved"
else
  create.result 1 "variables missing"
fi
expect 0 "variables saved" "config.save captures prefixed variables"

# ============================================================================
# T7: Test config.list shows config content
# ============================================================================
setup_test_config
echo 'export TEST_LIST_VAR="listvalue"' > "$CONFIG_PATH/listtest.env"

test.case - "T7: config.list shows content" \
  echo "checking list"

config.file listtest.env
LIST_OUTPUT=$(config.list listtest 2>/dev/null)
if echo "$LIST_OUTPUT" | grep -q "TEST_LIST_VAR"; then
  create.result 0 "list shows content"
else
  create.result 1 "list output: $LIST_OUTPUT"
fi
expect 0 "list shows content" "config.list shows variables"

# ============================================================================
# T8: Test config.set adds new variable
# ============================================================================
setup_test_config
echo '# empty config' > "$CONFIG"

test.case - "T8: config.set adds new variable" \
  config.set NEW_VAR "newvalue"

if grep -q 'NEW_VAR="newvalue"' "$CONFIG"; then
  create.result 0 "NEW_VAR added"
else
  create.result 1 "NEW_VAR missing in $CONFIG"
fi
expect 0 "NEW_VAR added" "config.set adds new variable"

# ============================================================================
# T9: Test config.set updates existing variable
# ============================================================================
setup_test_config
echo 'export EXISTING_VAR="oldvalue"' > "$CONFIG"

test.case - "T9: config.set updates existing variable" \
  config.set EXISTING_VAR "updatedvalue"

if grep -q 'EXISTING_VAR="updatedvalue"' "$CONFIG"; then
  create.result 0 "EXISTING_VAR updated"
else
  create.result 1 "EXISTING_VAR not updated"
fi
expect 0 "EXISTING_VAR updated" "config.set updates existing variable"

# ============================================================================
# T10: config.get reads value from the file (not from shell env)
# ============================================================================
setup_test_config
echo 'export GET_TEST_VAR="getvalue"' > "$CONFIG"
unset GET_TEST_VAR

test.case - "T10: config.get reads value from file" \
  echo "checking get"

GET_RESULT=$(config.get GET_TEST_VAR 2>/dev/null)
if [ "$GET_RESULT" = "getvalue" ]; then
  create.result 0 "got value"
else
  create.result 1 "got: $GET_RESULT"
fi
expect 0 "got value" "config.get reads value from file (not shell env)"

# ============================================================================
# T11: Test config.add appends source line
# ============================================================================
setup_test_config
echo '# user config' > "$CONFIG"
touch "$CONFIG_PATH/addon.env"

test.case - "T11: config.add appends source line" \
  config.add addon

# config.add calls config.clean which sorts the file
if grep -q 'source $CONFIG_PATH/addon.env' "$CONFIG"; then
  create.result 0 "source added"
else
  create.result 1 "source missing in: $(cat $CONFIG)"
fi
expect 0 "source added" "config.add appends source line"

# ============================================================================
# T12: Test config.clean removes duplicates
# ============================================================================
setup_test_config
cat > "$CONFIG" << 'EOF'
export DUP_VAR="value"
export DUP_VAR="value"
export UNIQUE_VAR="unique"
export DUP_VAR="value"
EOF

test.case - "T12: config.clean removes duplicates" \
  config.clean

LINE_COUNT=$(grep -c "DUP_VAR" "$CONFIG" 2>/dev/null || echo "0")
if [ "$LINE_COUNT" -eq 1 ]; then
  create.result 0 "duplicates removed"
else
  create.result 1 "duplicates remain: $LINE_COUNT"
fi
expect 0 "duplicates removed" "config.clean removes duplicates"

# ============================================================================
# T13: Test config.delete removes config file
# ============================================================================
setup_test_config
touch "$CONFIG_PATH/todelete.env"
config.file todelete.env

test.case - "T13: config.delete removes file" \
  config.delete todelete

if [ ! -f "$CONFIG_PATH/todelete.env" ]; then
  create.result 0 "file deleted"
else
  create.result 1 "file still exists"
fi
expect 0 "file deleted" "config.delete removes file"

# ============================================================================
# T14: Test config.discover lists config files
# ============================================================================
setup_test_config
touch "$CONFIG_PATH/discover1.env"
touch "$CONFIG_PATH/discover2.env"

test.case - "T14: config.discover lists files" \
  echo "checking discover"

DISCOVER_OUTPUT=$(config.discover 2>/dev/null)
if echo "$DISCOVER_OUTPUT" | grep -q "discover1.env"; then
  create.result 0 "discover1 found"
else
  create.result 1 "output: $DISCOVER_OUTPUT"
fi
expect 0 "discover1 found" "config.discover lists files"

# ============================================================================
# T15: Test config.string.quote handles special chars
# ============================================================================
test.case - "T15: config.string.quote returns quoted string" \
  echo "checking quote"

QUOTED=$(config.string.quote "hello world")
if [ -n "$QUOTED" ]; then
  create.result 0 "string quoted"
else
  create.result 1 "quote failed"
fi
expect 0 "string quoted" "config.string.quote returns quoted string"

# ============================================================================
# T16: Test config.file reset restores defaults
# ============================================================================
config.file someother.env

test.case - "T16: config.file reset restores user.env" \
  config.file reset

if [ "$CONFIG_FILE" = "user.env" ]; then
  create.result 0 "file reset"
else
  create.result 1 "CONFIG_FILE=$CONFIG_FILE"
fi
expect 0 "file reset" "config.file reset restores user.env"

# Reset for remaining tests
setup_test_config

# ============================================================================
# T17: Test config.update saves and adds
# ============================================================================
export TEST_UPDATE_VAR="updateval"
setup_test_config
echo '# main config' > "$CONFIG"

test.case - "T17: config.update saves and adds" \
  config.update updatetest TEST_UPDATE

# Check file was created and source line added
if [ -f "$CONFIG_PATH/updatetest.env" ] && grep -q 'source $CONFIG_PATH/updatetest.env' "$CONFIG"; then
  create.result 0 "update complete"
else
  create.result 1 "file exists: $(test -f $CONFIG_PATH/updatetest.env && echo yes || echo no) source: $(grep updatetest $CONFIG)"
fi
expect 0 "update complete" "config.update saves and adds"

# ============================================================================
# T18: Test config.get with missing variable
# ============================================================================
unset NONEXISTENT_VAR

test.case - "T18: config.get returns empty for missing var" \
  echo "checking missing"

GET_MISSING=$(config.get NONEXISTENT_VAR 2>/dev/null)
if [ -z "$GET_MISSING" ]; then
  create.result 0 "empty for missing"
else
  create.result 1 "returned: $GET_MISSING"
fi
expect 0 "empty for missing" "config.get returns empty for missing var"

# ============================================================================
# T19: Test config.set with empty value
# ============================================================================
setup_test_config
echo 'export EMPTY_TEST="hasvalue"' > "$CONFIG"

test.case - "T19: config.set allows empty value" \
  config.set EMPTY_TEST ""

if grep -q 'EMPTY_TEST=""' "$CONFIG"; then
  create.result 0 "set to empty"
else
  create.result 1 "config content: $(cat $CONFIG)"
fi
expect 0 "set to empty" "config.set allows empty value"

# ============================================================================
# T20: config.set + config.get round-trip
# ============================================================================
setup_test_config
echo '# user config' > "$CONFIG"
unset ROUND_TRIP_VAR

test.case - "T20: config.set then config.get round-trips through the file" \
  echo "checking round-trip"

config.set ROUND_TRIP_VAR foo >/dev/null
ROUND_TRIP_RESULT=$(config.get ROUND_TRIP_VAR 2>/dev/null)
if [ "$ROUND_TRIP_RESULT" = "foo" ]; then
  create.result 0 "round-trip worked"
else
  create.result 1 "got: $ROUND_TRIP_RESULT (config: $(cat $CONFIG))"
fi
expect 0 "round-trip worked" "config.set + config.get round-trip via file"

# ============================================================================
# T21: config.set + config.get preserves quoted spaces
# ============================================================================
setup_test_config
echo '# user config' > "$CONFIG"
unset SPACE_RT_VAR

test.case - "T21: config.set + config.get preserves quoted spaces" \
  echo "checking spaces"

config.set SPACE_RT_VAR "hello world" >/dev/null
SPACE_RT_RESULT=$(config.get SPACE_RT_VAR 2>/dev/null)
if [ "$SPACE_RT_RESULT" = "hello world" ]; then
  create.result 0 "spaces preserved"
else
  create.result 1 "got: '$SPACE_RT_RESULT'"
fi
expect 0 "spaces preserved" "config.set/get preserves quoted spaces"

# ============================================================================
# T22: config.set does NOT leak the full config to stdout on append
# ============================================================================
setup_test_config
echo '# user config' > "$CONFIG"
unset LEAK_CHECK_VAR

test.case - "T22: config.set does not leak full config on append" \
  echo "checking no leak"

LEAK_OUT=$(config.set LEAK_CHECK_VAR x 2>&1)
LEAK_LINES=$(printf '%s' "$LEAK_OUT" | grep -c '.' )
if [ "$LEAK_LINES" -le 1 ]; then
  create.result 0 "no leak"
else
  create.result 1 "leaked $LEAK_LINES lines: $LEAK_OUT"
fi
expect 0 "no leak" "config.set must not print the full config on append"

# ============================================================================
# T23: config.get tolerates legacy "export declare X=" malformed lines
# ============================================================================
setup_test_config
echo 'export declare LEGACY_VAR="legacy"' > "$CONFIG"
unset LEGACY_VAR

test.case - "T23: config.get reads legacy 'export declare X=' lines" \
  echo "checking legacy form"

LEGACY_RESULT=$(config.get LEGACY_VAR 2>/dev/null)
if [ "$LEGACY_RESULT" = "legacy" ]; then
  create.result 0 "legacy form readable"
else
  create.result 1 "got: '$LEGACY_RESULT' (file: $(cat $CONFIG))"
fi
expect 0 "legacy form readable" "config.get tolerates malformed export-declare line"

# ============================================================================
# T24: config.set normalizes malformed lines on update
# ============================================================================
setup_test_config
echo 'export declare NORMALIZE_VAR="old"' > "$CONFIG"
unset NORMALIZE_VAR

test.case - "T24: config.set normalizes 'export declare X=' to clean form" \
  echo "checking normalization"

config.set NORMALIZE_VAR "new" >/dev/null
NORMALIZE_RESULT=$(config.get NORMALIZE_VAR 2>/dev/null)
if [ "$NORMALIZE_RESULT" = "new" ] && grep -q '^export NORMALIZE_VAR=' "$CONFIG" && ! grep -q 'export declare NORMALIZE_VAR' "$CONFIG"; then
  create.result 0 "normalized"
else
  create.result 1 "got '$NORMALIZE_RESULT', file: $(cat $CONFIG)"
fi
expect 0 "normalized" "config.set normalizes legacy export-declare lines on update"

# ============================================================================
# Cleanup
# ============================================================================
cleanup_test_config

# Unset test variables
unset TEST_CONFIG_VAR1
unset TEST_CONFIG_VAR2
unset TEST_UPDATE_VAR

# ============================================================================
# Completion function tests
# ============================================================================

test.case $level "config.parameter.completion.configfile exists" \
  type -t config.parameter.completion.configfile
if type -t config.parameter.completion.configfile &>/dev/null; then
  expect.pass "config.parameter.completion.configfile function exists"
else
  expect.fail "config.parameter.completion.configfile should exist"
fi

test.case $level "config.parameter.completion.envVariable exists" \
  type -t config.parameter.completion.envVariable
if type -t config.parameter.completion.envVariable &>/dev/null; then
  expect.pass "config.parameter.completion.envVariable function exists"
else
  expect.fail "config.parameter.completion.envVariable should exist"
fi

test.case $level "config.parameter.completion.name returns values" \
  config.parameter.completion.name ""
COMP_OUTPUT=$(config.parameter.completion.name "" 2>/dev/null)
if [ -n "$COMP_OUTPUT" ]; then
  expect.pass "config.parameter.completion.name returns config names"
else
  expect.pass "config.parameter.completion.name runs (may be empty if no configs)"
fi

test.case $level "config.parameter.completion.sshConfigName exists" \
  type -t config.parameter.completion.sshConfigName
if type -t config.parameter.completion.sshConfigName &>/dev/null; then
  expect.pass "config.parameter.completion.sshConfigName function exists"
else
  expect.fail "config.parameter.completion.sshConfigName should exist"
fi

# ============================================================================
# T21: config.save excludes INSTALL variables
# ============================================================================
test.config.saveExcludesInstall() {
  local FIXTURE="/tmp/test.config.install.$$"
  mkdir -p "$FIXTURE"
  local ORIG_CP="$CONFIG_PATH" ORIG_CF="$CONFIG_FILE" ORIG_C="$CONFIG"
  export CONFIG_PATH="$FIXTURE" CONFIG_FILE="install_test.env" CONFIG="$FIXTURE/install_test.env"
  touch "$CONFIG"
  export LOG_INSTALL="/tmp/test_install_log"
  config.save install_test LOG
  if grep -q 'LOG_INSTALL' "$FIXTURE/install_test.env" 2>/dev/null; then
    create.result 1 "LOG_INSTALL found in saved config (should be excluded)"
  else
    create.result 0 "INSTALL variables excluded"
  fi
  unset LOG_INSTALL
  export CONFIG_PATH="$ORIG_CP" CONFIG_FILE="$ORIG_CF" CONFIG="$ORIG_C"
  rm -rf "$FIXTURE"
}
test.case - "T21: config.save excludes INSTALL variables" \
  test.config.saveExcludesInstall
expect 0 "INSTALL variables excluded" "config.save excludes INSTALL variables"

# ============================================================================
# T22: config.save preserves non-INSTALL variables
# ============================================================================
test.config.savePreservesNonInstall() {
  local FIXTURE="/tmp/test.config.preserve.$$"
  mkdir -p "$FIXTURE"
  local ORIG_CP="$CONFIG_PATH" ORIG_CF="$CONFIG_FILE" ORIG_C="$CONFIG"
  export CONFIG_PATH="$FIXTURE" CONFIG_FILE="preserve_test.env" CONFIG="$FIXTURE/preserve_test.env"
  touch "$CONFIG"
  export OOSH_TEST_PRESERVE="keepme"
  config.save preserve_test OOSH_TEST
  if grep -q 'OOSH_TEST_PRESERVE' "$FIXTURE/preserve_test.env" 2>/dev/null; then
    create.result 0 "non-INSTALL variables preserved"
  else
    create.result 1 "OOSH_TEST_PRESERVE missing from saved config"
  fi
  unset OOSH_TEST_PRESERVE
  export CONFIG_PATH="$ORIG_CP" CONFIG_FILE="$ORIG_CF" CONFIG="$ORIG_C"
  rm -rf "$FIXTURE"
}
test.case - "T22: config.save preserves non-INSTALL variables" \
  test.config.savePreservesNonInstall
expect 0 "non-INSTALL variables preserved" "config.save preserves non-INSTALL variables"

# ============================================================================
# T23: config saves BASH_FILE to oosh.env
# ============================================================================
test.config.savesBashFile() {
  local SRC
  SRC=$(declare -f config.save 2>/dev/null)
  if echo "$SRC" | grep -q 'BASH_FILE'; then
    create.result 0 "BASH_FILE referenced in config.save"
  else
    create.result 1 "BASH_FILE not found in config.save"
  fi
}
test.case - "T23: config saves BASH_FILE to oosh.env" \
  test.config.savesBashFile
expect 0 "BASH_FILE referenced in config.save" "config saves BASH_FILE"

# ============================================================================
# T24: config BASH_FILE PATH builder avoids duplicates
# ============================================================================
test.config.bashFileAvoidsDuplicates() {
  local SRC
  SRC=$(declare -f config.save 2>/dev/null)
  if echo "$SRC" | grep -q '":$PATH:" != \*":'; then
    create.result 0 "PATH dedup pattern found"
  else
    create.result 1 "PATH dedup pattern missing from config.save"
  fi
}
test.case - "T24: config BASH_FILE PATH builder avoids duplicates" \
  test.config.bashFileAvoidsDuplicates
expect 0 "PATH dedup pattern found" "config BASH_FILE PATH builder avoids duplicates"

# ============================================================================
# T25: config.string.quote handles spaces
# ============================================================================
test.config.stringQuoteSpaces() {
  local RESULT_QUOTE
  RESULT_QUOTE=$(config.string.quote "hello world")
  if echo "$RESULT_QUOTE" | grep -q "hello world"; then
    create.result 0 "spaces preserved in quoted string"
  else
    create.result 1 "got: $RESULT_QUOTE"
  fi
}
test.case - "T25: config.string.quote handles spaces" \
  test.config.stringQuoteSpaces
expect 0 "spaces preserved in quoted string" "config.string.quote handles spaces"

# ============================================================================
# T26: config.string.quote handles double quotes
# ============================================================================
test.config.stringQuoteDoubleQuotes() {
  local RESULT_QUOTE
  RESULT_QUOTE=$(config.string.quote 'say "hello"')
  if echo "$RESULT_QUOTE" | grep -q 'hello'; then
    create.result 0 "double-quote string quoted"
  else
    create.result 1 "quote returned empty or mangled"
  fi
}
test.case - "T26: config.string.quote handles double quotes" \
  test.config.stringQuoteDoubleQuotes
expect 0 "double-quote string quoted" "config.string.quote handles double quotes"

# ============================================================================
# T27: config.set handles value with spaces
# ============================================================================
test.config.setHandlesSpaces() {
  local FIXTURE="/tmp/test.config.spaces.$$"
  mkdir -p "$FIXTURE"
  local ORIG_CP="$CONFIG_PATH" ORIG_CF="$CONFIG_FILE" ORIG_C="$CONFIG"
  export CONFIG_PATH="$FIXTURE" CONFIG_FILE="spaces_test.env" CONFIG="$FIXTURE/spaces_test.env"
  echo '# empty config' > "$CONFIG"
  config.set SPACE_VAR "hello world test"
  if grep -q 'SPACE_VAR=.*hello world test' "$CONFIG"; then
    create.result 0 "value with spaces stored"
  else
    create.result 1 "config content: $(cat "$CONFIG")"
  fi
  export CONFIG_PATH="$ORIG_CP" CONFIG_FILE="$ORIG_CF" CONFIG="$ORIG_C"
  rm -rf "$FIXTURE"
}
test.case - "T27: config.set handles value with spaces" \
  test.config.setHandlesSpaces
expect 0 "value with spaces stored" "config.set handles value with spaces"

# ============================================================================
# T28: config.save does not capture variables whose VALUE contains the prefix
# ============================================================================
# T28: grep pattern [_=] matches var NAMES with prefix but not VALUES containing prefix
test.case - "T28: config grep pattern excludes value-only matches" \
  echo "checking"

# Simulate declare -p output with a false-positive value match
TEST_DECLARE='declare -x OOSH_DIR="/path"
declare -- COMMANDS="save oosh OOSH"
declare -x OOSH_PROMPT="oosh "'
MATCHED=$(echo "$TEST_DECLARE" | grep " OOSH[_=]")
if echo "$MATCHED" | grep -q "OOSH_DIR" && \
   echo "$MATCHED" | grep -q "OOSH_PROMPT" && \
   ! echo "$MATCHED" | grep -q "COMMANDS"; then
  create.result 0 "pattern correct"
else
  create.result 1 "got: $MATCHED"
fi
expect 0 "pattern correct" "grep ' PREFIX[_=]' matches names not values"

# ============================================================================
# T29: config.save excludes per-user absolute-path leaks
# ============================================================================
# CONFIG_PATH/CONFIG/OOSH_DIR/OOSH_COMPONENTS_DIR/LOG_LIVE are all dynamically
# rebuilt from $HOME at every shell init (this:209, this:40-49, log:21-23).
# Persisting their saving-user absolute values into shared config causes
# EACCES leaks when a different user later sources it.
test.config.saveExcludesAbsolutePathLeaks() {
  local FIXTURE="/tmp/test.config.leaks.$$"
  mkdir -p "$FIXTURE"
  local ORIG_CP="$CONFIG_PATH" ORIG_CF="$CONFIG_FILE" ORIG_C="$CONFIG"

  # Pin all five candidates to obviously-absolute paths the test can grep for.
  local SAVED_CONFIG_PATH="$CONFIG_PATH" SAVED_CONFIG="$CONFIG"
  local SAVED_OOSH_DIR="$OOSH_DIR" SAVED_OOSH_COMP="$OOSH_COMPONENTS_DIR"
  local SAVED_LOG_LIVE="$LOG_LIVE"
  export OOSH_COMPONENTS_DIR="/tmp/leak-oosh-comp"
  export LOG_LIVE="/tmp/leak-log-live"

  # Now point CONFIG_PATH/CONFIG at the fixture; persist with three prefixes
  # to cover all the leaking name families.
  export CONFIG_PATH="$FIXTURE" CONFIG_FILE="leaks_test.env" CONFIG="$FIXTURE/leaks_test.env"
  touch "$CONFIG"

  config.save leaks_test CONFIG > /dev/null
  config.save leaks_test OOSH   > /dev/null
  config.save leaks_test LOG    > /dev/null

  local content; content=$(cat "$CONFIG" 2>/dev/null)
  local fail=0
  for leaker in CONFIG_PATH= 'CONFIG=' OOSH_DIR= OOSH_COMPONENTS_DIR= LOG_LIVE= LOG_DEVICE=; do
    if echo "$content" | grep -q "$leaker"; then
      fail=1
      important.log "leaked: $leaker found in saved config"
    fi
  done
  if [ "$fail" -eq 0 ]; then
    create.result 0 "absolute-path leaks excluded"
  else
    create.result 1 "saved config: $content"
  fi

  # Restore.
  export CONFIG_PATH="$ORIG_CP" CONFIG_FILE="$ORIG_CF" CONFIG="$ORIG_C"
  export OOSH_COMPONENTS_DIR="$SAVED_OOSH_COMP"
  export LOG_LIVE="$SAVED_LOG_LIVE"
  rm -rf "$FIXTURE"
}
test.case - "T29: config.save excludes per-user absolute-path leaks" \
  test.config.saveExcludesAbsolutePathLeaks
expect 0 "absolute-path leaks excluded" "config.save excludes CONFIG_PATH/CONFIG/OOSH_DIR/OOSH_COMPONENTS_DIR/LOG_LIVE"

# ============================================================================
# T30: config.save makes user.env self-anchoring (sourceable without CONFIG_PATH)
# ============================================================================
# After T29 stopped persisting CONFIG_PATH, the source lines `source
# $CONFIG_PATH/log.env` written by config.add need a self-anchor so user.env
# stays sourceable in non-interactive contexts (GHA steps, ssh exec) that
# don't go through bashrc and never invoke `this`.
test.config.userEnvSelfAnchors() {
  if grep -qE '^: \$\{CONFIG_PATH:=' "$HOME/config/user.env" 2>/dev/null; then
    create.result 0 "user.env self-anchor present"
  else
    create.result 1 "user.env missing self-anchor: $(head -1 "$HOME/config/user.env")"
  fi
}
test.case - "T30: config.save writes self-anchor at top of user.env" \
  test.config.userEnvSelfAnchors
expect 0 "user.env self-anchor present" "user.env self-anchors CONFIG_PATH"

# ============================================================================
# T31: config.save makes OOSH_DIR bootstrap-able (sourceable without prior env)
# ============================================================================
# OOSH_DIR is dropped from persisted config (it's a per-user absolute path),
# so somewhere in the bashrc → user.env → oosh.env chain there must be a
# self-anchor that sets it before any consumer needs it. Per commit 43796be
# the canonical location is user.env (sourced first by bashrc, durable
# against `oo mode <branch>` overwriting oosh.env via config.save oosh OOSH).
# Accept the anchor in EITHER user.env (current design) or oosh.env (older
# installs / pre-43796be) — the contract is "OOSH_DIR is set on fresh shells",
# not "the anchor lives in a specific file".
test.config.ooshDirSelfAnchors() {
  if grep -qE '^: \$\{OOSH_DIR:=' "$HOME/config/user.env" 2>/dev/null \
     || grep -qE '^: \$\{OOSH_DIR:=' "$HOME/config/oosh.env" 2>/dev/null; then
    create.result 0 "OOSH_DIR self-anchor present"
  else
    create.result 1 "OOSH_DIR self-anchor missing — neither user.env nor oosh.env has it; user.env head: $(head -2 "$HOME/config/user.env" 2>/dev/null | tr '\n' ' ')"
  fi
}
test.case - "T31: config.save writes OOSH_DIR self-anchor in user.env (or oosh.env)" \
  test.config.ooshDirSelfAnchors
expect 0 "OOSH_DIR self-anchor present" "OOSH_DIR is bootstrap-able via user.env or oosh.env"

# ============================================================================
# T32: private.ensure.sharedTree drops self-referential symlinks
# ============================================================================
# Fixture: a temp dir with a symlink that points back to itself (the exact
# bug pattern observed under sharedConfig/sharedConfig on tampered VMs).
test.config.selfLoopRemoved() {
  local fixture="/tmp/test.config.fixture.$(id -u).$$"
  mkdir -p "$fixture"
  ln -s "$fixture" "$fixture/loop"
  private.ensure.sharedTree "$fixture" >/dev/null 2>&1
  if [ -L "$fixture/loop" ] || [ -e "$fixture/loop" ]; then
    create.result 1 "self-loop survived"
  else
    create.result 0 "self-loop removed"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T32: private.ensure.sharedTree removes self-loop symlinks" \
  test.config.selfLoopRemoved
expect 0 "self-loop removed" "self-referential symlink is detected and dropped"

# ============================================================================
# T33: private.ensure.sharedTree is idempotent (re-run produces no further change)
# ============================================================================
# Capture the dir's metadata, re-run, compare. If the helper is idempotent
# the second run is a no-op observable in the metadata snapshot.
test.config.sharedTreeIdempotent() {
  local fixture="/tmp/test.config.idem.$(id -u).$$"
  mkdir -p "$fixture/sub"
  touch "$fixture/file"
  private.ensure.sharedTree "$fixture" >/dev/null 2>&1
  local snap1
  snap1=$(find "$fixture" -printf "%M %g %p\n" 2>/dev/null | sort)
  private.ensure.sharedTree "$fixture" >/dev/null 2>&1
  local snap2
  snap2=$(find "$fixture" -printf "%M %g %p\n" 2>/dev/null | sort)
  if [ "$snap1" = "$snap2" ]; then
    create.result 0 "idempotent"
  else
    create.result 1 "second run changed metadata"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T33: private.ensure.sharedTree is idempotent" \
  test.config.sharedTreeIdempotent
expect 0 "idempotent" "re-running produces no further metadata change"

# ============================================================================
# T34: config.init.check is silent (returns 0, no failure) on a healthy shell
# ============================================================================
# We can't assert *no warnings* without parsing log output, so just verify
# the return code: check is documented as diagnostic-only and must always
# return 0 regardless of state.
test.config.checkAlwaysSucceeds() {
  config.init.check "$USER" >/dev/null 2>&1
  create.result $? "check returned"
}
test.case - "T34: config.init.check is non-blocking (always returns 0)" \
  test.config.checkAlwaysSucceeds
expect 0 "check returned" "config.init.check never fails the caller"

# ============================================================================
# T35: completion functions for username parameter exist and are callable
# ============================================================================
# config.init.user/.check/.full all delegate username completion to user.list.
# We assert the functions are defined; verifying user.list output requires
# sourcing dev/user, which this test file deliberately does not (test isolation
# pattern matches T18-T20 above which use `type -t`).
test.config.completionsExist() {
  if [ "$(type -t config.init.user.completion.username)"  = "function" ] \
  && [ "$(type -t config.init.check.completion.username)" = "function" ] \
  && [ "$(type -t config.init.full.completion.username)"  = "function" ]; then
    create.result 0 "completions defined"
  else
    create.result 1 "missing: user/[$(type -t config.init.user.completion.username)] check/[$(type -t config.init.check.completion.username)] full/[$(type -t config.init.full.completion.username)]"
  fi
}
test.case - "T35: config.init.* username completion functions are defined" \
  test.config.completionsExist
expect 0 "completions defined" "all three username completions exist"

# ============================================================================
# T36: config.init.full is defined and callable as a function
# ============================================================================
# Function-existence smoke test only — invoking config.init.full for real
# would call config.init.shared which mutates the live sharedConfig (chgrp,
# chmod) and prompts for sudo on a fresh shell. That's the right behaviour
# in production but bad for unit tests. We assert the dispatcher exists;
# real end-to-end coverage lives in the manual verification block in the
# plan (running ./config init.full on .149 + diffing snapshots).
test.config.fullExists() {
  if [ "$(type -t config.init.full)" = "function" ]; then
    create.result 0 "full defined"
  else
    create.result 1 "config.init.full is not a function"
  fi
}
test.case - "T36: config.init.full is a defined function (dispatcher smoke test)" \
  test.config.fullExists
expect 0 "full defined" "config.init.full exists and is callable"

# ============================================================================
# T37: config.init.env regenerates oosh.env with the canonical self-anchor
# ============================================================================
# Mirrors what install does at oo:1456. After init.env, oosh.env's first line
# must be the canonical `: ${OOSH_DIR:=…}` self-anchor — the same shape T31
# already asserts globally, but here under our explicit fixture.
test.config.initEnvRegensOoshEnv() {
  local fixture="/tmp/test.config.env.$(id -u).$$"
  mkdir -p "$fixture"
  # Seed with deliberately-wrong content (the boss-tamper pattern)
  echo "# bogus content" > "$fixture/oosh.env"
  echo "# bogus user" > "$fixture/user.env"
  CONFIG_PATH="$fixture" CONFIG_FILE=user.env CONFIG="$fixture/user.env" \
    config.init.env >/dev/null 2>&1
  if grep -qE '^: \$\{OOSH_DIR:=' "$fixture/oosh.env" 2>/dev/null; then
    create.result 0 "oosh.env self-anchor present after regen"
  else
    create.result 1 "oosh.env first line: $(head -1 "$fixture/oosh.env")"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T37: config.init.env regenerates oosh.env with canonical self-anchor" \
  test.config.initEnvRegensOoshEnv
expect 0 "oosh.env self-anchor present after regen" "config.init.env writes the canonical OOSH_DIR self-anchor"

# ============================================================================
# T38: config.init.env regenerates user.env with the canonical self-anchor
# ============================================================================
test.config.initEnvRegensUserEnv() {
  local fixture="/tmp/test.config.userenv.$(id -u).$$"
  mkdir -p "$fixture"
  echo "# bogus content" > "$fixture/user.env"
  CONFIG_PATH="$fixture" CONFIG_FILE=user.env CONFIG="$fixture/user.env" \
    config.init.env >/dev/null 2>&1
  if grep -qE '^: \$\{CONFIG_PATH:=' "$fixture/user.env" 2>/dev/null; then
    create.result 0 "user.env self-anchor present after regen"
  else
    create.result 1 "user.env first line: $(head -1 "$fixture/user.env")"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T38: config.init.env regenerates user.env with canonical self-anchor" \
  test.config.initEnvRegensUserEnv
expect 0 "user.env self-anchor present after regen" "config.init.env writes the canonical CONFIG_PATH self-anchor"

# ============================================================================
# T39: config.init.env backs up user.env to user.env.bak.<ts> before regen
# ============================================================================
test.config.initEnvBacksUpUserEnv() {
  local fixture="/tmp/test.config.bak.$(id -u).$$"
  mkdir -p "$fixture"
  local sentinel="MARKER_$(date +%s%N)"
  echo "$sentinel" > "$fixture/user.env"
  CONFIG_PATH="$fixture" CONFIG_FILE=user.env CONFIG="$fixture/user.env" \
    config.init.env >/dev/null 2>&1
  if ls "$fixture"/user.env.bak.* >/dev/null 2>&1 \
     && grep -q "$sentinel" "$fixture"/user.env.bak.* 2>/dev/null; then
    create.result 0 "user.env backup created with original content"
  else
    create.result 1 "no backup or sentinel missing: $(ls "$fixture")"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T39: config.init.env backs up user.env before regenerating" \
  test.config.initEnvBacksUpUserEnv
expect 0 "user.env backup created with original content" "user.env is preserved as user.env.bak.<ts>"

# ============================================================================
# T40: generated user.env keeps the CONFIG_PATH fallback ABOVE the source lines
# ============================================================================
# config.clean must NOT reorder the bootstrap header — it uses an order-
# preserving de-dup (awk '!seen[$0]++'), not `sort -u`. If the fallback line
# (`{ ... } && CONFIG_PATH="$HOME/config"`, leading `{`) gets sorted below the
# `source $CONFIG_PATH/*.env` lines, those sources run with a mis-derived
# CONFIG_PATH before the fallback can repair it — silently defeating it.
test.config.fallbackPrecedesSourceLines() {
  local fixture="/tmp/test.config.order.$(id -u).$$"
  mkdir -p "$fixture"
  echo "# bogus" > "$fixture/user.env"
  CONFIG_PATH="$fixture" CONFIG_FILE=user.env CONFIG="$fixture/user.env" \
    config.init.env >/dev/null 2>&1
  local fbLine srcLine
  fbLine=$(grep -nF '&& CONFIG_PATH="$HOME/config"' "$fixture/user.env" | head -1 | cut -d: -f1)
  srcLine=$(grep -nF 'source $CONFIG_PATH/' "$fixture/user.env" | head -1 | cut -d: -f1)
  if [ -n "$fbLine" ] && [ -n "$srcLine" ] && [ "$fbLine" -lt "$srcLine" ]; then
    create.result 0 "fallback ordered before sources"
  else
    create.result 1 "fallback=$fbLine source=$srcLine in: $(cat "$fixture/user.env")"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T40: user.env CONFIG_PATH fallback precedes the source lines" \
  test.config.fallbackPrecedesSourceLines
expect 0 "fallback ordered before sources" "CONFIG_PATH fallback is ordered before the source lines"

# ============================================================================
# T41: user.env CONFIG_PATH fallback redirects ANY mis-derived path
# ============================================================================
# The fallback uses a POSITIVE validity check (`[ -f "$CONFIG_PATH/user.env" ]`)
# rather than enumerating BASH_SOURCE breakage shapes, so it fires for every
# mis-derivation: empty, bare-name ("user.env"), and the /dev/stdin case
# (CONFIG_PATH="/dev" — a real dir that nonetheless holds no user.env). A
# correctly-derived CONFIG_PATH must be left untouched.
test.config.fallbackRedirectsMisderivedPath() {
  local fixture="/tmp/test.config.fb.$(id -u).$$"
  mkdir -p "$fixture"
  echo "# bogus" > "$fixture/user.env"
  CONFIG_PATH="$fixture" CONFIG_FILE=user.env CONFIG="$fixture/user.env" \
    config.init.env >/dev/null 2>&1
  local fb; fb=$(grep -F '&& CONFIG_PATH="$HOME/config"' "$fixture/user.env")
  local fail=0 cp bogus
  for bogus in "" "/dev" "user.env"; do
    cp=$(HOME="$HOME" CONFIG_PATH="$bogus" bash -c "$fb"' ; printf %s "$CONFIG_PATH"')
    if [ "$cp" != "$HOME/config" ]; then
      fail=1; important.log "bogus CONFIG_PATH='$bogus' not redirected: got '$cp'"
    fi
  done
  cp=$(HOME="$HOME" CONFIG_PATH="$fixture" bash -c "$fb"' ; printf %s "$CONFIG_PATH"')
  [ "$cp" = "$fixture" ] || { fail=1; important.log "valid CONFIG_PATH overridden: '$cp'"; }
  if [ "$fail" = "0" ]; then
    create.result 0 "fallback redirects mis-derived paths, preserves valid ones"
  else
    create.result 1 "fallback predicate misbehaved (line: $fb)"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case - "T41: user.env CONFIG_PATH fallback redirects mis-derived paths" \
  test.config.fallbackRedirectsMisderivedPath
expect 0 "fallback redirects mis-derived paths, preserves valid ones" \
  "CONFIG_PATH fallback handles empty/bare-name//dev/stdin and preserves valid dirs"

# ============================================================================
# Save results
# ============================================================================
test.suite.save.results
