# SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2026 Bryan Joshua Pedini # tests/unit/test_helper.bash - common setup for the unit tests (sourced via `load test_helper`). # The applet runs with a hermetic PATH: fake package managers (tests/unit/fakes/) in front # of a directory with symlinks to the few system tools it needs. No root, no network, no real # package manager; everything is written under $BATS_TEST_TMPDIR. # shellcheck shell=bash load '../vendor/bats-support/load' load '../vendor/bats-assert/load' SU_BIN=$(cd "$BATS_TEST_DIRNAME/../.." && pwd)/skeptical-updater FAKES=$BATS_TEST_DIRNAME/fakes export FAKE_DATA=$BATS_TEST_DIRNAME/data SYS_TOOLS=(bash env cat sort sed grep tr cut join awk mktemp mv mkdir chmod rm cp ln date ls head tail wc touch sleep kill flock readlink timeout stat sha256sum) common_setup() { SYSBIN=$BATS_TEST_TMPDIR/sysbin mkdir -p "$SYSBIN" local t p for t in "${SYS_TOOLS[@]}"; do p=$(type -P "$t") || continue ln -sf "$p" "$SYSBIN/$t" done export FAKE_DIR=$BATS_TEST_TMPDIR/fake mkdir -p "$FAKE_DIR" : >"$FAKE_DIR/holds" export FAKE_LOG=$FAKE_DIR/log : >"$FAKE_LOG" export STATE=$BATS_TEST_TMPDIR/state export STATE_FILE=$STATE/trusted.tsv export SKEPTICAL_UPDATER_STATE_DIR=$STATE export SKEPTICAL_UPDATER_EUID=0 export SKEPTICAL_UPDATER_OS_RELEASE=$FAKE_DATA/os-release-debian12 export TMPDIR=$BATS_TEST_TMPDIR export FAKE_PACMAN_DBPATH=$FAKE_DIR/pacman-db mkdir -p "$FAKE_PACMAN_DBPATH/sync" "$FAKE_PACMAN_DBPATH/local" unset NO_COLOR ZYPP_CONF COLUMNS SKEPTICAL_UPDATER_LOCK_WAIT use_fakes apt } # use_fakes DIR...: the applet sees only these fake dirs + the system tools use_fakes() { local d p= for d in "$@"; do p+=$FAKES/$d:; done TEST_PATH=$p$SYSBIN } # skup ARGS...: run the applet (use as `run skup ...`, stdin is passed through) skup() { env PATH="$TEST_PATH" "$SU_BIN" "$@"; } # pty_skup INPUT ARGS...: run the applet on a pseudo-terminal (script(1), util-linux/bsdutils) with # INPUT typed in one go - readline consumes it as it reads, so no timing is involved; end INPUT with # a line that ends the session (q or an empty line). Sets status, output and lines like `run` # (output without the pty's CRs; NO_COLOR, as stdout is a terminal); the raw transcript stays in # $PTY_RAW. Skips without script(1). # shellcheck disable=SC2034 # status/lines are read by bats-assert pty_skup() { local input=$1 cmd shift command -v script >/dev/null 2>&1 || skip "script(1) (util-linux/bsdutils) not available: no pty to drive" PTY_RAW=$BATS_TEST_TMPDIR/pty.raw printf -v cmd '%q ' env PATH="$TEST_PATH" TERM=dumb NO_COLOR=1 "$SU_BIN" "$@" status=0 printf '%s' "$input" | timeout 60 script -qfec "$cmd" /dev/null >"$PTY_RAW" 2>&1 || status=$? output=$(tr -d '\r' <"$PTY_RAW") mapfile -t lines <<<"$output" } # pty_bells: number of BEL bytes (readline's bell) in the raw transcript of the last pty_skup pty_bells() { tr -cd '\a' <"$PTY_RAW" | wc -c; } # count_lines LINE: number of output lines that are exactly LINE count_lines() { grep -cxF -- "$1" <<<"$output" || true; } # shellcheck disable=SC2034 # used by the .bats files HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)' # shellcheck disable=SC2034 DATE_RE='[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z' # shellcheck disable=SC2034 T=$'\t' # write_state LINE...: create the statefile with exactly these lines write_state() { mkdir -p "$STATE" printf '%s\n' "$@" >"$STATE_FILE" } # log_has LINE: the fake log contains exactly this line log_has() { grep -qxF -- "$1" "$FAKE_LOG" || { printf 'expected log line: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2 return 1 } } # log_matches REGEX: some fake log line matches log_matches() { grep -qE -- "$1" "$FAKE_LOG" || { printf 'expected a log line matching: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2 return 1 } } # log_lacks REGEX: no fake log line matches log_lacks() { if grep -qE -- "$1" "$FAKE_LOG"; then printf 'unexpected log line matching: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2 return 1 fi }