#!/usr/bin/env bash # Unit tests for lib/output.sh 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/output.sh" TMPDIR_SELF="$(mktemp -d)" trap 'rm -rf "$TMPDIR_SELF"' EXIT # --------------------------------------------------------------------------- suite "output: basic file creation" # --------------------------------------------------------------------------- ENV_VARS=("FOO" "BAR") ENV_DESC_FOO="" ENV_DESC_BAR="" ENV_VALUE_FOO="hello" ENV_VALUE_BAR="world" OUT="$TMPDIR_SELF/basic.env" write_env_file "$OUT" 2>/dev/null assert_file_exists "$OUT" "output file created" assert_file_contains "FOO=hello" "$OUT" "FOO written correctly" assert_file_contains "BAR=world" "$OUT" "BAR written correctly" assert_file_contains "# Generated by generate-env" "$OUT" "header present" # --------------------------------------------------------------------------- suite "output: variable order matches ENV_VARS" # --------------------------------------------------------------------------- ENV_VARS=("ALPHA" "BETA" "GAMMA") ENV_VALUE_ALPHA="1" ENV_VALUE_BETA="2" ENV_VALUE_GAMMA="3" OUT="$TMPDIR_SELF/order.env" write_env_file "$OUT" 2>/dev/null # grep -n returns the line number; verify order alpha_line=$(grep -n "ALPHA=" "$OUT" | cut -d: -f1) beta_line=$(grep -n "BETA=" "$OUT" | cut -d: -f1) gamma_line=$(grep -n "GAMMA=" "$OUT" | cut -d: -f1) if (( alpha_line < beta_line && beta_line < gamma_line )); then pass "variable order preserved" else fail "variable order preserved" "ALPHA < BETA < GAMMA" "lines $alpha_line, $beta_line, $gamma_line" fi # --------------------------------------------------------------------------- suite "output: empty values written as KEY=" # --------------------------------------------------------------------------- ENV_VARS=("WITH_VALUE" "NO_VALUE") ENV_VALUE_WITH_VALUE="set" ENV_VALUE_NO_VALUE="" OUT="$TMPDIR_SELF/empty.env" write_env_file "$OUT" 2>/dev/null assert_file_contains "WITH_VALUE=set" "$OUT" "non-empty value written" assert_file_contains "NO_VALUE=" "$OUT" "empty value written as KEY=" assert_file_not_contains "NO_VALUE=x" "$OUT" "no stray value for empty var" # --------------------------------------------------------------------------- suite "output: values containing special characters" # --------------------------------------------------------------------------- ENV_VARS=("SPECIAL") ENV_VALUE_SPECIAL='postgres://user:p@ss!#$@host:5432/db?ssl=true' OUT="$TMPDIR_SELF/special.env" write_env_file "$OUT" 2>/dev/null assert_file_contains "SPECIAL=postgres://user:p@ss" "$OUT" "special chars in value preserved" # --------------------------------------------------------------------------- suite "output: values containing equals signs" # --------------------------------------------------------------------------- ENV_VARS=("DB_URL") ENV_VALUE_DB_URL="postgres://host/db?sslmode=require&timeout=10" OUT="$TMPDIR_SELF/equals.env" write_env_file "$OUT" 2>/dev/null assert_file_contains "DB_URL=postgres://host/db?sslmode=require&timeout=10" \ "$OUT" "equals signs in value preserved" # --------------------------------------------------------------------------- suite "output: header contains ISO-8601 timestamp" # --------------------------------------------------------------------------- ENV_VARS=("X") ENV_VALUE_X="1" OUT="$TMPDIR_SELF/ts.env" write_env_file "$OUT" 2>/dev/null # Header should contain a UTC timestamp in the form YYYY-MM-DDTHH:MM:SSZ if grep -qE '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z' "$OUT"; then pass "header contains ISO-8601 UTC timestamp" else fail "header contains ISO-8601 UTC timestamp" \ "YYYY-MM-DDTHH:MM:SSZ" "(not found in header)" fi # --------------------------------------------------------------------------- suite "output: single variable" # --------------------------------------------------------------------------- ENV_VARS=("SOLO") ENV_VALUE_SOLO="only" OUT="$TMPDIR_SELF/solo.env" write_env_file "$OUT" 2>/dev/null assert_file_exists "$OUT" "file created for single var" assert_file_contains "SOLO=only" "$OUT" "single var written" # --------------------------------------------------------------------------- suite "output: description written as comment before KEY=VALUE" # --------------------------------------------------------------------------- ENV_VARS=("DESCRIBED" "NODESC") ENV_DESC_DESCRIBED="Explains this variable" ENV_DESC_NODESC="" ENV_VALUE_DESCRIBED="val1" ENV_VALUE_NODESC="val2" OUT="$TMPDIR_SELF/desc.env" write_env_file "$OUT" 2>/dev/null assert_file_contains "# Explains this variable" "$OUT" "description written as comment" assert_file_contains "DESCRIBED=val1" "$OUT" "KEY=VALUE follows comment" # The comment line should immediately precede the variable line desc_line=$(grep -n "# Explains this variable" "$OUT" | cut -d: -f1) var_line=$(grep -n "^DESCRIBED=" "$OUT" | cut -d: -f1) if (( var_line == desc_line + 1 )); then pass "comment is on the line directly before KEY=VALUE" else fail "comment is on the line directly before KEY=VALUE" \ "$((desc_line + 1))" "$var_line" fi # Variable with no description should have no comment line immediately before it nodesc_line=$(grep -n "^NODESC=" "$OUT" | cut -d: -f1) prev_line_content=$(sed -n "$((nodesc_line - 1))p" "$OUT") if [[ -z "$prev_line_content" ]]; then pass "variable with no description has blank line before it (no comment)" else fail "variable with no description has blank line before it (no comment)" \ "" "$prev_line_content" fi # --------------------------------------------------------------------------- suite "output: blank line separates each variable block" # --------------------------------------------------------------------------- ENV_VARS=("A" "B" "C") ENV_DESC_A="First" ENV_DESC_B="" ENV_DESC_C="Third" ENV_VALUE_A="1" ENV_VALUE_B="2" ENV_VALUE_C="3" OUT="$TMPDIR_SELF/spacing.env" write_env_file "$OUT" 2>/dev/null # Each variable block ends with a blank line; verify A and C have their comments assert_file_contains "# First" "$OUT" "first var description present" assert_file_contains "# Third" "$OUT" "third var description present" a_line=$(grep -n "^A=" "$OUT" | cut -d: -f1) b_line=$(grep -n "^B=" "$OUT" | cut -d: -f1) # There must be a blank line between A= and B= between=$(sed -n "$((a_line + 1)),$((b_line - 1))p" "$OUT") if [[ -z "$between" || "$between" =~ ^[[:space:]]*$ ]]; then pass "blank line between variable blocks" else fail "blank line between variable blocks" "(blank)" "$between" fi print_summary