zupt/tests/test_completions_manpage.sh
2026-08-31 14:14:36 -03:00

207 lines
6.7 KiB
Shell
Executable file

#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (c) 2025-2026 Cristian Cezar Moisés
set -Eeuo pipefail
cd "$(dirname "$0")/.."
pass_count=0
fail_count=0
skip_count=0
pass() { pass_count=$((pass_count + 1)); printf ' PASS: %s\n' "$1"; }
fail() { fail_count=$((fail_count + 1)); printf ' FAIL: %s\n' "$1"; }
skip() { skip_count=$((skip_count + 1)); printf ' SKIP: %s\n' "$1"; }
version=$(sed -n 's/^#define ZUPT_VERSION_STRING "\([^"]*\)".*/\1/p' include/zupt.h)
[[ -n $version ]] || { printf 'FAIL: cannot determine version\n' >&2; exit 1; }
printf 'ZUPT %s completion and manual-page checks\n' "$version"
completion_files=(
completions/zupt.bash
completions/_zupt
completions/zupt.fish
)
for file in "${completion_files[@]}"; do
[[ -f $file ]] && pass "$file exists" || fail "$file is missing"
done
if bash -n completions/zupt.bash; then
pass 'bash completion parses'
else
fail 'bash completion has a syntax error'
fi
if command -v zsh >/dev/null 2>&1; then
if zsh -n completions/_zupt; then
pass 'zsh completion parses'
else
fail 'zsh completion has a syntax error'
fi
else
skip 'zsh is unavailable'
fi
if command -v fish >/dev/null 2>&1; then
if fish -n completions/zupt.fish; then
pass 'fish completion parses'
else
fail 'fish completion has a syntax error'
fi
else
skip 'fish is unavailable'
fi
if grep -qxF 'complete -F _zupt zupt' completions/zupt.bash &&
! grep -Eq '^complete[[:space:]].*[[:space:]]vaptvupt([[:space:]]|$)' completions/zupt.bash; then
pass 'bash registers only zupt'
else
fail 'bash completion is not limited to the primary zupt command'
fi
if [[ $(sed -n '1p' completions/_zupt) == '#compdef zupt' ]]; then
pass 'zsh registers only zupt'
else
fail 'zsh #compdef is not limited to zupt'
fi
if grep -q '^complete -c zupt' completions/zupt.fish &&
! grep -q '^complete -c vaptvupt\([[:space:]]\|$\)' completions/zupt.fish; then
pass 'fish registers only zupt'
else
fail 'fish completion is not limited to the primary zupt command'
fi
required_flags=(
password-prompt pass-file pass-fd allow-legacy-no-ait kdf comment comment-file
pq pq-only pq-sdk pq-box dedup solid force verbose threads
level block store fast lzhp vaptvupt compare output key pub
sdk box pqonly help version
)
for file in "${completion_files[@]}"; do
missing=()
for flag in "${required_flags[@]}"; do
if ! grep -qF -- "--$flag" "$file" &&
! grep -qE -- "-l[[:space:]]+$flag([[:space:]]|$)" "$file"; then
missing+=("--$flag")
fi
done
if ((${#missing[@]} == 0)); then
pass "$file covers current critical flags"
else
fail "$file is missing: ${missing[*]}"
fi
done
unsupported_flags=(quiet jobs codec keyfile sync no-mtime strip-components block-size)
for file in "${completion_files[@]}"; do
advertised=()
for flag in "${unsupported_flags[@]}"; do
if grep -qF -- "--$flag" "$file" ||
grep -qE -- "-l[[:space:]]+$flag([[:space:]]|$)" "$file"; then
advertised+=("--$flag")
fi
done
if ((${#advertised[@]} == 0)); then
pass "$file does not advertise unsupported flags"
else
fail "$file advertises unsupported flags: ${advertised[*]}"
fi
done
if [[ ! -e doc/vaptvupt.1 && ! -L doc/vaptvupt.1 ]]; then
pass 'former primary man page is absent from the source tree'
else
fail 'doc/vaptvupt.1 remains despite the zupt-only default installation'
fi
manpage=doc/zupt.1
if [[ ! -f $manpage ]]; then
fail "$manpage is missing"
else
required_sections=(NAME SYNOPSIS DESCRIPTION COMMANDS PASSWORD\ INPUT EXAMPLES EXIT\ STATUS LICENSE)
missing_sections=()
for section in "${required_sections[@]}"; do
grep -qxF ".SH $section" "$manpage" || missing_sections+=("$section")
done
if ((${#missing_sections[@]} == 0)); then
pass 'manpage contains required sections'
else
fail "manpage is missing sections: ${missing_sections[*]}"
fi
if grep -qF "ZUPT $version" "$manpage"; then
pass 'manpage version matches include/zupt.h'
else
fail 'manpage version does not match include/zupt.h'
fi
required_man_flags=(
password-prompt pass-file pass-fd allow-legacy-no-ait kdf comment comment-file
pq pq-only pq-sdk pq-box dedup solid force verbose threads
level block store fast lzhp vaptvupt compare output key pub
sdk box pqonly help version
)
missing=()
for flag in "${required_man_flags[@]}"; do
grep -qF -- "--$flag" "$manpage" || missing+=("--$flag")
done
if ((${#missing[@]} == 0)); then
pass 'manpage documents current critical flags'
else
fail "manpage is missing: ${missing[*]}"
fi
advertised=()
for flag in "${unsupported_flags[@]}"; do
grep -qF -- "--$flag" "$manpage" && advertised+=("--$flag")
done
if ((${#advertised[@]} == 0)); then
pass 'manpage does not document unsupported flags'
else
fail "manpage documents unsupported flags: ${advertised[*]}"
fi
if grep -qF 'Plain archives provide compression checksums' "$manpage" &&
grep -qF 'does not restore ownership' "$manpage" &&
grep -qF 'Automatic codec selection' "$manpage"; then
pass 'manpage states current integrity, metadata, and codec behavior'
else
fail 'manpage is missing current behavioral limits'
fi
if grep -q '^\.B 2$\|^\.B 3$\|^\.B 4$\|^\.B 5$' "$manpage"; then
fail 'manpage advertises exit statuses not emitted by the CLI'
else
pass 'manpage documents only emitted exit statuses'
fi
lint_tmp=$(mktemp -d "${TMPDIR:-/tmp}/zupt-man-lint.XXXXXXXX")
trap 'rm -rf -- "$lint_tmp"' EXIT HUP INT TERM
if command -v mandoc >/dev/null 2>&1; then
if mandoc -Tlint "$manpage" >"$lint_tmp/mandoc.log" 2>&1; then
pass 'mandoc lint passes'
else
fail 'mandoc lint reports diagnostics'
sed -n '1,10p' "$lint_tmp/mandoc.log"
fi
elif command -v groff >/dev/null 2>&1; then
if groff -mandoc -Tutf8 "$manpage" >"$lint_tmp/rendered" 2>"$lint_tmp/groff.log" &&
[[ ! -s $lint_tmp/groff.log ]] &&
(($(wc -l <"$lint_tmp/rendered") > 50)); then
pass 'groff renders the manpage without diagnostics'
else
fail 'groff manpage rendering failed or emitted diagnostics'
sed -n '1,10p' "$lint_tmp/groff.log"
fi
else
skip 'mandoc and groff are unavailable'
fi
rm -rf -- "$lint_tmp"
trap - EXIT HUP INT TERM
fi
printf '\nSummary: PASS=%d FAIL=%d SKIP=%d\n' "$pass_count" "$fail_count" "$skip_count"
((fail_count == 0))