191 lines
8.2 KiB
Bash
191 lines
8.2 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# Unit tests for prompt helper functions in lib/prompt.sh.
|
||
|
|
#
|
||
|
|
# All interactive functions write prompts to stderr and read from stdin.
|
||
|
|
# Tests pipe input via stdin and capture stdout, suppressing stderr.
|
||
|
|
|
||
|
|
TESTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
ROOT_DIR="$(dirname "$TESTS_DIR")"
|
||
|
|
|
||
|
|
source "$TESTS_DIR/framework.sh"
|
||
|
|
source "$ROOT_DIR/lib/colors.sh"
|
||
|
|
source "$ROOT_DIR/lib/validate.sh"
|
||
|
|
source "$ROOT_DIR/lib/prompt.sh"
|
||
|
|
|
||
|
|
# Helpers: feed stdin to a function and capture its stdout
|
||
|
|
feed() {
|
||
|
|
# feed <input_string> <function> [args...]
|
||
|
|
local input="$1"; shift
|
||
|
|
printf "%s" "$input" | "$@" 2>/dev/null
|
||
|
|
}
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_enum: numeric selection"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "a" "$(feed "1"$'\n' _prompt_enum "V" "a,b,c" "a")" "choice 1 -> first option"
|
||
|
|
assert_eq "b" "$(feed "2"$'\n' _prompt_enum "V" "a,b,c" "a")" "choice 2 -> second option"
|
||
|
|
assert_eq "c" "$(feed "3"$'\n' _prompt_enum "V" "a,b,c" "a")" "choice 3 -> third option"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_enum: string selection"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "a" "$(feed "a"$'\n' _prompt_enum "V" "a,b,c" "")" "string 'a' selects a"
|
||
|
|
assert_eq "b" "$(feed "b"$'\n' _prompt_enum "V" "a,b,c" "")" "string 'b' selects b"
|
||
|
|
assert_eq "c" "$(feed "c"$'\n' _prompt_enum "V" "a,b,c" "")" "string 'c' selects c"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_enum: empty input uses default"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "a" "$(feed $'\n' _prompt_enum "V" "a,b,c" "a")" "empty -> first default"
|
||
|
|
assert_eq "b" "$(feed $'\n' _prompt_enum "V" "a,b,c" "b")" "empty -> middle default"
|
||
|
|
assert_eq "c" "$(feed $'\n' _prompt_enum "V" "a,b,c" "c")" "empty -> last default"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_enum: invalid choice then valid"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
# Send out-of-range number, then a valid number
|
||
|
|
assert_eq "b" "$(printf "99\n2\n" | _prompt_enum "V" "a,b,c" "a" 2>/dev/null)" \
|
||
|
|
"invalid index followed by valid index"
|
||
|
|
|
||
|
|
# Send unknown string, then valid string
|
||
|
|
assert_eq "c" "$(printf "zzz\nc\n" | _prompt_enum "V" "a,b,c" "a" 2>/dev/null)" \
|
||
|
|
"invalid string followed by valid string"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_enum: real-world APP_ENV"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "development" \
|
||
|
|
"$(feed $'\n' _prompt_enum "APP_ENV" "development,staging,production" "development")" \
|
||
|
|
"empty -> development (default)"
|
||
|
|
|
||
|
|
assert_eq "production" \
|
||
|
|
"$(feed "3"$'\n' _prompt_enum "APP_ENV" "development,staging,production" "development")" \
|
||
|
|
"choice 3 -> production"
|
||
|
|
|
||
|
|
assert_eq "staging" \
|
||
|
|
"$(feed "staging"$'\n' _prompt_enum "APP_ENV" "development,staging,production" "development")" \
|
||
|
|
"string 'staging' -> staging"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_bool: explicit inputs"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "true" "$(feed "y"$'\n' _prompt_bool "")" "y -> true"
|
||
|
|
assert_eq "true" "$(feed "yes"$'\n' _prompt_bool "")" "yes -> true"
|
||
|
|
assert_eq "true" "$(feed "true"$'\n' _prompt_bool "")" "true -> true"
|
||
|
|
assert_eq "true" "$(feed "1"$'\n' _prompt_bool "")" "1 -> true"
|
||
|
|
assert_eq "false" "$(feed "n"$'\n' _prompt_bool "")" "n -> false"
|
||
|
|
assert_eq "false" "$(feed "no"$'\n' _prompt_bool "")" "no -> false"
|
||
|
|
assert_eq "false" "$(feed "false"$'\n' _prompt_bool "")" "false -> false"
|
||
|
|
assert_eq "false" "$(feed "0"$'\n' _prompt_bool "")" "0 -> false"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_bool: empty input uses default"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "true" "$(feed $'\n' _prompt_bool "true")" "empty -> true default"
|
||
|
|
assert_eq "true" "$(feed $'\n' _prompt_bool "yes")" "empty -> yes default normalizes to true"
|
||
|
|
assert_eq "false" "$(feed $'\n' _prompt_bool "false")" "empty -> false default"
|
||
|
|
assert_eq "false" "$(feed $'\n' _prompt_bool "no")" "empty -> no default normalizes to false"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_bool: invalid then valid"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "true" "$(printf "banana\ny\n" | _prompt_bool "" 2>/dev/null)" \
|
||
|
|
"invalid input followed by y"
|
||
|
|
assert_eq "false" "$(printf "maybe\nn\n" | _prompt_bool "" 2>/dev/null)" \
|
||
|
|
"invalid input followed by n"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_secret: matching values accepted"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "mysecret" \
|
||
|
|
"$(printf "mysecret\nmysecret\n" | _prompt_secret "V" "" 2>/dev/null)" \
|
||
|
|
"matching entries return value"
|
||
|
|
|
||
|
|
assert_eq "p@ss!#\$word" \
|
||
|
|
"$(printf 'p@ss!#$word\np@ss!#$word\n' | _prompt_secret "V" "" 2>/dev/null)" \
|
||
|
|
"special characters in secret preserved"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_secret: empty input uses default"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
assert_eq "defaultsecret" \
|
||
|
|
"$(printf "\n" | _prompt_secret "V" "defaultsecret" 2>/dev/null)" \
|
||
|
|
"empty input returns default"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "_prompt_secret: mismatch retries"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
# First pair mismatches, second pair matches
|
||
|
|
assert_eq "correct" \
|
||
|
|
"$(printf "wrong\nmismatch\ncorrect\ncorrect\n" | _prompt_secret "V" "" 2>/dev/null)" \
|
||
|
|
"mismatch retries until match"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "prompt_variable: string type stores value"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Use process substitution (<(...)) so prompt_variable runs in the current
|
||
|
|
# shell and its variable assignments (ENV_VALUE_*) persist.
|
||
|
|
|
||
|
|
ENV_VARS=("MYVAR")
|
||
|
|
ENV_DESC_MYVAR="A test variable"
|
||
|
|
ENV_TYPE_MYVAR="string"
|
||
|
|
ENV_REQUIRED_MYVAR="false"
|
||
|
|
ENV_DEFAULT_MYVAR="default_val"
|
||
|
|
|
||
|
|
# Accept default
|
||
|
|
prompt_variable "MYVAR" < <(printf "\n") 2>/dev/null
|
||
|
|
assert_eq "default_val" "$ENV_VALUE_MYVAR" "empty input stores default"
|
||
|
|
|
||
|
|
# Provide a value
|
||
|
|
prompt_variable "MYVAR" < <(printf "custom\n") 2>/dev/null
|
||
|
|
assert_eq "custom" "$ENV_VALUE_MYVAR" "typed value stored"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "prompt_variable: number type re-prompts on invalid input"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
ENV_TYPE_MYVAR="number"
|
||
|
|
ENV_DEFAULT_MYVAR="42"
|
||
|
|
|
||
|
|
prompt_variable "MYVAR" < <(printf "abc\n99\n") 2>/dev/null
|
||
|
|
assert_eq "99" "$ENV_VALUE_MYVAR" "invalid number re-prompts, then stores valid"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "prompt_variable: bool type"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
ENV_TYPE_MYVAR="bool"
|
||
|
|
ENV_DEFAULT_MYVAR="false"
|
||
|
|
|
||
|
|
prompt_variable "MYVAR" < <(printf "y\n") 2>/dev/null
|
||
|
|
assert_eq "true" "$ENV_VALUE_MYVAR" "bool y stored as true"
|
||
|
|
|
||
|
|
prompt_variable "MYVAR" < <(printf "\n") 2>/dev/null
|
||
|
|
assert_eq "false" "$ENV_VALUE_MYVAR" "bool empty uses false default"
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
suite "prompt_variable: enum type"
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
ENV_TYPE_MYVAR="enum:x,y,z"
|
||
|
|
ENV_DEFAULT_MYVAR="x"
|
||
|
|
|
||
|
|
prompt_variable "MYVAR" < <(printf "2\n") 2>/dev/null
|
||
|
|
assert_eq "y" "$ENV_VALUE_MYVAR" "enum choice 2 stores y"
|
||
|
|
|
||
|
|
prompt_variable "MYVAR" < <(printf "\n") 2>/dev/null
|
||
|
|
assert_eq "x" "$ENV_VALUE_MYVAR" "enum empty uses default x"
|
||
|
|
|
||
|
|
print_summary
|