Ctrl K
ComunidadGuías…

hack/bats-strict-setup.bats

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bats
# Every discovered unit file must load the nounset helper once. A file-local
# setup() replaces the helper's setup, so its first command must restore it.
#
# This lexical audit accepts one spelling at column zero, not arbitrary shell:
# conditional loads are rejected, while a literal inside a heredoc could be
# mistaken for a load. Fixtures use printf to avoid that ambiguity. Nested Bats
# canaries separately verify the helper's effect in the actual test process.

load test_helper

# The directory to audit. Under the bats binary that is this file's own
# location; under cozytest.sh, which does not set BATS_TEST_FILENAME, `$0` is
# the runner itself -- and the answer comes out the same only because the runner
# lives in the directory it runs files from. The first test below refuses to
# pass on an empty enumeration, so a wrong answer here fails rather than audits
# nothing.
BSS_DIR="$(cd "$(dirname "${BATS_TEST_FILENAME:-$0}")" && pwd)"
BSS_REPO_ROOT="$(cd "$BSS_DIR/.." && pwd)"

# Non-recursive, and the exclusion is on the basename, because that is what
# `$(filter-out hack/e2e-%.bats,$(wildcard hack/*.bats))` in the Makefile means.
# A shell glob keeps this portable to the macOS hook instead of relying on
# GNU find's non-POSIX `-maxdepth` flag.
# Nested files are outside this unit enumeration. Runner reachability is
# checked separately by hack/bats-runner-coverage.bats.
bss_units() {
  for _f in "$1"/*.bats; do
    [ -e "$_f" ] || continue
    case ${_f##*/} in
      e2e-*) continue ;;
    esac
    printf '%s\n' "$_f"
  done | sort
  return 0
}

# Report every unit file whose strict-mode setup is missing or overridden, one
# line each, and print nothing when they all comply.
#
# Through stdout rather than an exit status: cozytest.sh rewrites a function's
# closing brace into `return 0`, so a status set in here would be discarded
# before the caller could read it, and the check would pass unconditionally.
bss_audit() {
  bss_units "$1" | while IFS= read -r _f; do
    [ -e "$_f" ] || continue
    _b=$(basename "$_f")
    _load_count=$(grep -c '^load test_helper$' "$_f" || :)
    if [ "$_load_count" -eq 0 ]; then
      echo "$_b: does not load the strict-mode helper; add a column-zero \`load test_helper\` line under the file's leading comment block"
      continue
    fi
    if [ "$_load_count" -ne 1 ]; then
      echo "$_b: loads the strict-mode helper $_load_count times; keep exactly one column-zero \`load test_helper\` line"
      continue
    fi
    # A file-local setup replaces the helper's without a word from either
    # runner. Recognize the common Bash forms, including indentation,
    # `function setup {`, and a brace on the following line, then require the
    # suite's one canonical spelling. That makes an ambiguous nested declaration
    # fail closed instead of guessing whether Bats will see it at source time.
    _setup_count=$(grep -cE '^[[:space:]]*(setup[[:space:]]*\(|function[[:space:]]+setup([[:space:]]|\(|[{]|$))' "$_f" || :)
    _canonical_count=$(grep -c '^setup() {$' "$_f" || :)
    if [ "$_setup_count" -gt 0 ] \
      && { [ "$_setup_count" -ne 1 ] || [ "$_canonical_count" -ne 1 ]; }; then
      echo "$_b: uses a noncanonical or repeated setup declaration; use exactly one column-zero \`setup() {\` block"
      continue
    fi
    if [ "$_canonical_count" -eq 1 ]; then
      _first_effective=$(awk '
        /^setup\(\) \{$/ { in_setup=1; next }
        in_setup && /^}$/ { exit }
        in_setup && /^[[:space:]]*$/ { next }
        in_setup && /^[[:space:]]*#/ { next }
        in_setup { print; exit }
      ' "$_f")
      if ! printf '%s\n' "$_first_effective" \
        | grep -qE '^[[:space:]]*strict_setup[[:space:]]*$'; then
        echo "$_b: setup() must call strict_setup directly as its first effective command; blank and comment lines may precede it"
      fi
    fi
  done
  return 0
}

# The load line is assembled from a printf argument rather than
# written as a literal, because this file is audited by the guard it defines and
# a column-zero literal here would be read as a second declaration of its own.
bss_new_fixture() {
  printf '%s\n' '#!/usr/bin/env bats' > "$1/subject.bats"
  return 0
}

bss_add_load() {
  printf '%s\n' 'load test_helper' >> "$1/subject.bats"
  return 0
}

bss_add_indented_load() {
  printf '  %s\n' 'load test_helper' >> "$1/subject.bats"
  return 0
}

bss_add_commented_load() {
  printf '# %s\n' 'load test_helper' >> "$1/subject.bats"
  return 0
}

bss_add_own_setup() {
  printf '%s\n' 'setup() {' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_strict_own_setup() {
  printf '%s\n' 'setup() {' '' '  # Restore the unit-suite contract first.' '  strict_setup' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_subshell_strict_own_setup() {
  printf '%s\n' 'setup() {' '  (' '    strict_setup' '  )' '}' >> "$1/subject.bats"
  return 0
}

bss_add_conditional_strict_own_setup() {
  printf '%s\n' 'setup() {' '  if false; then' '    strict_setup' '  fi' '}' >> "$1/subject.bats"
  return 0
}

bss_add_function_own_setup() {
  printf '%s\n' 'function setup {' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_indented_own_setup() {
  printf '%s\n' '  setup() {' '    export FIXTURE=1' '  }' >> "$1/subject.bats"
  return 0
}

bss_add_next_line_brace_setup() {
  printf '%s\n' 'setup()' '{' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_spaced_parens_setup() {
  printf '%s\n' 'setup ( ) {' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_commented_strict_own_setup() {
  printf '%s\n' 'setup() {' '  # strict_setup' '  export FIXTURE=1' '}' >> "$1/subject.bats"
  return 0
}

bss_add_unrelated_strict_call() {
  printf '%s\n' 'unrelated() {' '  strict_setup' '}' >> "$1/subject.bats"
  return 0
}

bss_rename() {
  mv "$1/subject.bats" "$1/$2"
  return 0
}

bss_add_nounset_canary() {
  printf '%s\n' \
    '@test "nounset canary" {' \
    '  printf "%s\n" "$BSS_NOUNSET_CANARY_UNSET"' \
    '}' >> "$1/subject.bats"
  ln -s "$BSS_DIR/test_helper.bash" "$1/test_helper.bash"
  return 0
}

@test "the unit enumeration is not empty" {
  count=$(bss_units "$BSS_DIR" | wc -l)
  if [ "$count" -lt 2 ]; then
    echo "FAIL: enumerated $count unit file(s) under $BSS_DIR; the audit below would be vacuous"
    false
  fi
}

@test "the unit enumeration is non-recursive without GNU find extensions" {
  tmp=$(mktemp -d)
  mkdir -p "$tmp/bin" "$tmp/nested"
  : > "$tmp/root.bats"
  : > "$tmp/e2e-live.bats"
  : > "$tmp/nested/child.bats"
  printf '%s\n' '#!/bin/sh' 'exit 97' > "$tmp/bin/find"
  chmod +x "$tmp/bin/find"

  units=$(PATH="$tmp/bin:$PATH" bss_units "$tmp")
  [ "$units" = "$tmp/root.bats" ]
  rm -rf "$tmp"
}

@test "the audited set is exactly the set the Makefile hands the runner" {
  # Ask make for its own answer instead of trusting this file's copy of the
  # rule. The whole point of the audit is that its input tracks the runner's,
  # so a divergence between the two is the failure it exists to prevent --
  # narrow the Makefile's filter without narrowing this one and the audit goes
  # on reporting clean about files nobody runs, or vice versa.
  tmp=$(mktemp -d)
  bss_units "$BSS_DIR" | sed "s|^$BSS_REPO_ROOT/||" | sort > "$tmp/mine"
  # MAKEFLAGS cleared: this runs from inside `make bats-unit-tests`, and a
  # sub-make that inherits the parent's `-j` without its jobserver descriptors
  # warns about it. The warning goes to stderr and would not corrupt the
  # comparison, but it would land in the middle of a green suite's output.
  (cd "$BSS_REPO_ROOT" && MAKEFLAGS= MAKELEVEL= make --no-print-directory -s print-bats-unit-files) | sort > "$tmp/theirs"
  # File comparison keeps this audit compatible with cozytest's POSIX shell;
  # process substitution would require Bash.
  if ! diff -u "$tmp/theirs" "$tmp/mine" > "$tmp/delta"; then
    echo "FAIL: the audited set and \$(BATS_UNIT_FILES) disagree (-Makefile +audit):"
    cat "$tmp/delta"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "default and direct canonical setup enable nounset in real nested Bats tests" {
  tmp=$(mktemp -d)
  unset BSS_NOUNSET_CANARY_UNSET

  for form in default direct; do
    mkdir "$tmp/$form"
    bss_new_fixture "$tmp/$form"
    bss_add_load "$tmp/$form"
    if [ "$form" = direct ]; then
      bss_add_strict_own_setup "$tmp/$form"
    fi
    bss_add_nounset_canary "$tmp/$form"
    report=$(bss_audit "$tmp/$form")
    if [ -n "$report" ]; then
      echo "FAIL: the supported $form setup was rejected: $report"
      rm -rf "$tmp"
      false
    fi

    child_status=0
    output=$(bats --formatter tap "$tmp/$form/subject.bats" 2>&1) || child_status=$?
    if [ "$child_status" -eq 0 ]; then
      echo "FAIL: nested Bats accepted an unset test-body read with $form setup"
      echo "$output"
      rm -rf "$tmp"
      false
    fi
    printf '%s\n' "$output" | grep -Fq 'not ok 1 nounset canary'
    printf '%s\n' "$output" | grep -Fq 'BSS_NOUNSET_CANARY_UNSET: unbound variable'
  done
  rm -rf "$tmp"
}

@test "the helper leaves subprocess shell options unchanged" {
  tmp=$(mktemp -d)
  unset BSS_NOUNSET_CANARY_UNSET
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  ln -s "$BSS_DIR/test_helper.bash" "$tmp/test_helper.bash"
  printf '%s\n' '#!/bin/bash' 'printf "child:%s\n" "$BSS_NOUNSET_CANARY_UNSET"' > "$tmp/child.sh"
  printf '@test "subprocess canary" {\n  bash "%s/child.sh"\n}\n' "$tmp" >> "$tmp/subject.bats"
  child_status=0
  output=$(bats --formatter tap "$tmp/subject.bats" 2>&1) || child_status=$?
  [ "$child_status" -eq 0 ]
  printf '%s\n' "$output" | grep -Fq 'ok 1 subprocess canary'
  rm -rf "$tmp"
}

@test "every hack/*.bats unit file restores set -u through the shared helper" {
  report=$(bss_audit "$BSS_DIR")
  if [ -n "$report" ]; then
    echo "FAIL: strict-mode setup missing or overridden:"
    echo "$report"
    false
  fi
}

@test "a unit file with no load line is reported" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'does not load the strict-mode helper'; then
    echo "FAIL: an uncovered file was not reported; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a unit file with the load line is clean" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  report=$(bss_audit "$tmp")
  if [ -n "$report" ]; then
    echo "FAIL: a covered file was reported: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "duplicate load lines are reported" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_load "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'keep exactly one column-zero'; then
    echo "FAIL: duplicate load lines were accepted; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "an indented or commented-out load line does not count" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_indented_load "$tmp"
  bss_add_commented_load "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'does not load the strict-mode helper'; then
    echo "FAIL: a load line that never runs was credited; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a file-local setup that skips strict_setup is reported" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'first effective command'; then
    echo "FAIL: a setup() override was not reported; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a file-local setup that calls strict_setup is clean" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_strict_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if [ -n "$report" ]; then
    echo "FAIL: a compliant setup() override was reported: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "subshell and conditional strict_setup placements are rejected and leave nounset off" {
  tmp=$(mktemp -d)
  unset BSS_NOUNSET_CANARY_UNSET

  for form in subshell conditional; do
    mkdir "$tmp/$form"
    bss_new_fixture "$tmp/$form"
    bss_add_load "$tmp/$form"
    if [ "$form" = subshell ]; then
      bss_add_subshell_strict_own_setup "$tmp/$form"
    else
      bss_add_conditional_strict_own_setup "$tmp/$form"
    fi
    bss_add_nounset_canary "$tmp/$form"

    report=$(bss_audit "$tmp/$form")
    if ! printf '%s\n' "$report" | grep -q 'first effective command'; then
      echo "FAIL: the unsafe $form setup was accepted: $report"
      rm -rf "$tmp"
      false
    fi

    child_status=0
    output=$(bats --formatter tap "$tmp/$form/subject.bats" 2>&1) || child_status=$?
    if [ "$child_status" -ne 0 ]; then
      echo "FAIL: the $form fixture unexpectedly enabled nounset:"
      echo "$output"
      rm -rf "$tmp"
      false
    fi
    printf '%s\n' "$output" | grep -Fq 'ok 1 nounset canary'
  done
  rm -rf "$tmp"
}

@test "function-style or indented setup declarations are rejected" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_function_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'noncanonical or repeated setup declaration'; then
    echo "FAIL: function-style setup was not rejected; got: $report"
    rm -rf "$tmp"
    false
  fi
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_indented_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'noncanonical or repeated setup declaration'; then
    echo "FAIL: indented setup was not rejected; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a setup declaration with its brace on the next line is rejected" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_next_line_brace_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'noncanonical or repeated setup declaration'; then
    echo "FAIL: a brace-on-next-line setup was not rejected; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a setup declaration with spaced parentheses is rejected" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_spaced_parens_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'noncanonical or repeated setup declaration'; then
    echo "FAIL: a spaced-parentheses setup was not rejected; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a comment-only strict_setup mention does not satisfy setup" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_commented_strict_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'first effective command'; then
    echo "FAIL: a comment-only strict_setup mention was credited; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "a strict_setup call outside setup does not satisfy setup" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_add_load "$tmp"
  bss_add_unrelated_strict_call "$tmp"
  bss_add_own_setup "$tmp"
  report=$(bss_audit "$tmp")
  if ! echo "$report" | grep -q 'first effective command'; then
    echo "FAIL: a strict_setup call outside setup was credited; got: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}

@test "an e2e- file is outside the audit" {
  tmp=$(mktemp -d)
  bss_new_fixture "$tmp"
  bss_rename "$tmp" "e2e-subject.bats"
  report=$(bss_audit "$tmp")
  if [ -n "$report" ]; then
    echo "FAIL: a live-cluster suite was audited as a unit file: $report"
    rm -rf "$tmp"
    false
  fi
  rm -rf "$tmp"
}