243 lines
8.2 KiB
Bash
Executable File
243 lines
8.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# End-to-end tests for generate-env.sh.
|
|
#
|
|
# Each test pipes a crafted stdin to generate-env.sh and inspects the output
|
|
# .env file. Input lines are counted to match each variable's prompt exactly.
|
|
|
|
TESTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(dirname "$TESTS_DIR")"
|
|
SCRIPT="$ROOT_DIR/generate-env.sh"
|
|
|
|
source "$TESTS_DIR/framework.sh"
|
|
|
|
TMPDIR_SELF="$(mktemp -d)"
|
|
trap 'rm -rf "$TMPDIR_SELF"' EXIT
|
|
|
|
# run_gen <input_string> <input_file> <output_file>
|
|
# Runs generate-env.sh, feeding <input_string> as stdin.
|
|
# Suppresses all terminal output. Removes <output_file> first so the
|
|
# overwrite guard never triggers.
|
|
run_gen() {
|
|
local input="$1"
|
|
local in_file="$2"
|
|
local out_file="$3"
|
|
rm -f "$out_file"
|
|
# -o must come before the positional input-file argument so getopts sees it
|
|
printf "%s" "$input" | bash "$SCRIPT" -o "$out_file" "$in_file" 2>/dev/null
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: accept all defaults"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Fixture: three optional vars with defaults, no required fields
|
|
IN="$TMPDIR_SELF/defaults.env.example"
|
|
OUT="$TMPDIR_SELF/defaults.env"
|
|
cat > "$IN" << 'EOF'
|
|
# App name
|
|
APP_NAME=MyApp
|
|
|
|
# Port
|
|
# @type number
|
|
PORT=3000
|
|
|
|
# Debug mode
|
|
# @type bool
|
|
DEBUG=false
|
|
EOF
|
|
|
|
# Input: three Enter presses (accept all defaults)
|
|
run_gen $'\n\n\n' "$IN" "$OUT"
|
|
|
|
assert_file_exists "$OUT" "output file created"
|
|
assert_file_contains "APP_NAME=MyApp" "$OUT" "string default accepted"
|
|
assert_file_contains "PORT=3000" "$OUT" "number default accepted"
|
|
assert_file_contains "DEBUG=false" "$OUT" "bool default accepted"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: override defaults"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/override.env.example"
|
|
OUT="$TMPDIR_SELF/override.env"
|
|
cat > "$IN" << 'EOF'
|
|
APP_NAME=MyApp
|
|
PORT=3000
|
|
EOF
|
|
|
|
# Override both
|
|
run_gen $'CustomApp\n8080\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "APP_NAME=CustomApp" "$OUT" "string default overridden"
|
|
assert_file_contains "PORT=8080" "$OUT" "number default overridden"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: required fields must be filled"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/required.env.example"
|
|
OUT="$TMPDIR_SELF/required.env"
|
|
cat > "$IN" << 'EOF'
|
|
# @required
|
|
MUST_HAVE=
|
|
EOF
|
|
|
|
# First send empty (should re-prompt), then a value
|
|
run_gen $'\nfilled\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "MUST_HAVE=filled" "$OUT" "required field filled on retry"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: bool values"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/bool.env.example"
|
|
OUT="$TMPDIR_SELF/bool.env"
|
|
cat > "$IN" << 'EOF'
|
|
# @type bool
|
|
FLAG_A=false
|
|
|
|
# @type bool
|
|
FLAG_B=true
|
|
EOF
|
|
|
|
# y for FLAG_A (-> true), Enter for FLAG_B (-> default true)
|
|
run_gen $'y\n\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "FLAG_A=true" "$OUT" "y -> true"
|
|
assert_file_contains "FLAG_B=true" "$OUT" "empty accepts true default"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: enum with numeric choice"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/enum.env.example"
|
|
OUT="$TMPDIR_SELF/enum.env"
|
|
cat > "$IN" << 'EOF'
|
|
# @type enum:development,staging,production
|
|
# @required
|
|
APP_ENV=development
|
|
EOF
|
|
|
|
# Choose option 3 (production)
|
|
run_gen $'3\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "APP_ENV=production" "$OUT" "enum numeric choice 3 -> production"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: enum with string choice"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
OUT="$TMPDIR_SELF/enum_str.env"
|
|
|
|
run_gen $'staging\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "APP_ENV=staging" "$OUT" "enum string choice -> staging"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: enum accepts default"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
OUT="$TMPDIR_SELF/enum_default.env"
|
|
|
|
run_gen $'\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "APP_ENV=development" "$OUT" "enum empty input uses default"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: secret with confirmation"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/secret.env.example"
|
|
OUT="$TMPDIR_SELF/secret.env"
|
|
cat > "$IN" << 'EOF'
|
|
# @type secret
|
|
# @required
|
|
JWT_SECRET=
|
|
EOF
|
|
|
|
# Enter value twice (entry + confirm)
|
|
run_gen $'supersecret\nsupersecret\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "JWT_SECRET=supersecret" "$OUT" "secret stored after confirmation"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: secret uses default on empty input"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/secret_default.env.example"
|
|
OUT="$TMPDIR_SELF/secret_default.env"
|
|
cat > "$IN" << 'EOF'
|
|
# @type secret
|
|
JWT_SECRET=existing_token
|
|
EOF
|
|
|
|
# Empty input -> keep default
|
|
run_gen $'\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "JWT_SECRET=existing_token" "$OUT" "secret empty input keeps default"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: -o flag sets output path"
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/flag.env.example"
|
|
CUSTOM_OUT="$TMPDIR_SELF/custom_output.env"
|
|
cat > "$IN" << 'EOF'
|
|
KEY=val
|
|
EOF
|
|
|
|
rm -f "$CUSTOM_OUT"
|
|
printf "\n" | bash "$SCRIPT" -o "$CUSTOM_OUT" "$IN" 2>/dev/null
|
|
|
|
assert_file_exists "$CUSTOM_OUT" "custom output path created via -o flag"
|
|
assert_file_contains "KEY=val" "$CUSTOM_OUT" "content written to custom path"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: empty optional field written as KEY="
|
|
# ---------------------------------------------------------------------------
|
|
|
|
IN="$TMPDIR_SELF/optional.env.example"
|
|
OUT="$TMPDIR_SELF/optional.env"
|
|
cat > "$IN" << 'EOF'
|
|
# Optional field with no default
|
|
# @type email
|
|
ADMIN_EMAIL=
|
|
EOF
|
|
|
|
# Leave empty
|
|
run_gen $'\n' "$IN" "$OUT"
|
|
|
|
assert_file_contains "ADMIN_EMAIL=" "$OUT" "optional empty field written as KEY="
|
|
assert_file_not_contains "ADMIN_EMAIL=x" "$OUT" "no stray value"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
suite "e2e: full example.env.example"
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# Variable order and input count:
|
|
# 1. APP_NAME (string, required, default "MyApp") → "\n" accept default
|
|
# 2. APP_ENV (enum:…, required, default "development") → "\n" accept default (1)
|
|
# 3. PORT (number, optional, default "3000") → "\n" accept default
|
|
# 4. DEBUG (bool, optional, default "false") → "n\n" explicit n
|
|
# 5. JWT_SECRET(secret, required, no default) → "tok\ntok\n" entry+confirm
|
|
# 6. DATABASE_URL(url, required, has default) → "\n" accept default
|
|
# 7. ADMIN_EMAIL (email, optional, no default) → "\n" leave empty
|
|
|
|
OUT="$TMPDIR_SELF/full.env"
|
|
INPUT=$'\n\n\nn\ntok\ntok\n\n\n'
|
|
|
|
run_gen "$INPUT" "$ROOT_DIR/example.env.example" "$OUT"
|
|
|
|
assert_file_exists "$OUT" "output file created"
|
|
assert_file_contains "APP_NAME=MyApp" "$OUT" "APP_NAME default"
|
|
assert_file_contains "APP_ENV=development" "$OUT" "APP_ENV default"
|
|
assert_file_contains "PORT=3000" "$OUT" "PORT default"
|
|
assert_file_contains "DEBUG=false" "$OUT" "DEBUG=false (n)"
|
|
assert_file_contains "JWT_SECRET=tok" "$OUT" "JWT_SECRET value"
|
|
assert_file_contains "DATABASE_URL=postgres://localhost:5432/myapp" "$OUT" "DATABASE_URL default"
|
|
assert_file_contains "ADMIN_EMAIL=" "$OUT" "ADMIN_EMAIL empty"
|
|
assert_file_contains "# Generated by generate-env" "$OUT" "header present"
|
|
|
|
print_summary
|