joeylib2/scripts/verify-dvx-fullscreen.sh
2026-10-13 14:01:46 -05:00

230 lines
9 KiB
Bash
Executable file

#!/usr/bin/env bash
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
# See LICENSE.md for license information.
# SPDX-License-Identifier: MIT
#
# verify-dvx-fullscreen.sh - Full-screen gate for DVX: a program on the whole
# screen in DVX's exclusive mode (src/dvx/hal.c), started there by the port's
# own setting as Game > Full Screen leaves it (dvxFullScreen), and read back
# from DOSBox's raw screenshots of the VGA screen. Two runs of a scratch DVX
# in DOSBox Staging under Xvfb:
# 1. UBER on the whole screen, suspended part way (Ctrl+Esc: DVX's Task
# Manager takes the focus, the desktop comes back and UBER presents into
# its window) and resumed (the Task Manager's Switch To): the
# screenshots must be the 320x200 mode, the desktop, then 320x200 again;
# DVX.LOG must show the mode set twice; and UBER's 51 hashes must equal
# the DOS port's (tests/goldens/uber/dos.txt): the stage is DOS's
# wherever it is shown.
# 2. KEYS on the whole screen: the typed string must reach jlInputGetChar
# (its log), and its verification row must read back off the 320x200
# screen at exactly the stage's own (0,198) (scripts/lib/keysRow.py):
# the full-screen present, its palette and its placement. Alt+keypad
# Enter (DOSBox keeps Alt+Enter for its own full screen) takes KEYS back
# to its window, where the row must be found on the desktop; the same
# keys again, and the row must be at (0,198) once more. The setting must
# still say full screen.
#
# Usage: scripts/verify-dvx-fullscreen.sh
# Env: DVX_FULLSCREEN_SHOTS also copy the screenshots into this folder
# Requires: DOSBox Staging, Xvfb, xdotool, python3 + PIL, the dvx component;
# the uber and keys programs (make dvx).
set -uo pipefail
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source "$repo/scripts/lib/joeyEnv.sh"
source "$repo/scripts/lib/dvxGate.sh"
joeyNeed DOSBOX dosbox
joeyNeed DVX_ROOT dvx
target="192.168.1.10:6510"
wall=180 # hard cap on each DOSBox run, whatever happens to this script
readySeconds=60 # DVX boot until its shell reports ready
settleSeconds=3 # then the program taking the screen
stepSeconds=2 # a key, then DVX and the program acting on it
shotSeconds=5 # Ctrl+F5 until DOSBox has written the screenshot
holdSeconds=0.3 # a key held that long: a quick tap can fall between two polls
uberSeconds=120 # UBER's run until its done line
logSeconds=30 # Escape until KEYS's typed line is in its log
fullSize=320x200 # DVX's full-screen mode for the stage: VGA mode 13h here
desktopSize="${DVX_VIDEO_W}x${DVX_VIDEO_H}"
rowAt=0,198 # KEYS's verification row at 1x: its place on the stage
uberDone="press any key to exit"
dvxNeedBuild uber keys
work=$(mktemp -d -t joeylib-dvx-fullscreen.XXXXXX)
guard=""
dosbox=""
xvfb=""
win=""
fails=""
# 2>/dev/null: bash reports the SIGKILLed timeout wrapper as "Killed".
cleanup() {
joeyStop "$dosbox" "$guard" "$xvfb" 2> /dev/null
rm -rf "$work"
}
trap cleanup EXIT
# boot PROGRAM -- DVX staged in $work/PROGRAM with PROGRAM its desktop, on the
# whole screen from the start; sets guard, dosbox and win.
boot() {
local dir="$work/$1"
local waited
dvxStage "$dir/c" "$(dvxAppDir "$1")"
dvxFullScreen "$dir/c" "$1"
dvxDosboxConf "$dir/dosbox.conf" "$dir/c"
printf '\n[capture]\ncapture_dir = %s\ndefault_image_capture_formats = raw\n' "$dir/shots" >> "$dir/dosbox.conf"
mkdir -p "$dir/xdg" "$dir/shots"
XDG_CONFIG_HOME="$dir/xdg" DISPLAY="$display" SDL_AUDIODRIVER=dummy \
timeout -s KILL "$wall" "$DOSBOX" "${JOEY_DOSBOX_ISOLATE[@]}" \
--conf "$dir/dosbox.conf" > "$dir/dosbox.log" 2>&1 &
guard=$!
dosbox=$(joeyChild "$guard")
for ((waited = 0; waited < readySeconds; waited++)); do
if dvxDvxLog "$dir/c" 200 | grep -q "DVX Shell ready"; then
sleep "$settleSeconds"
win=$(joeyFindWindow "$display" "$dosbox")
[ -n "$win" ] || return 1
DISPLAY="$display" xdotool windowactivate --sync "$win" 2> /dev/null || true
return 0
fi
joeyAlive "$guard" || return 1
sleep 1
done
return 1
}
# fail WHAT -- note a failed check; the gate goes on to report the rest.
fail() {
echo "verify-dvx-fullscreen: FAIL - $1"
fails="${fails:+$fails; }$1"
}
# fullScreenSets PROGRAM -- how often DVX.LOG says the full-screen mode was set.
fullScreenSets() {
dvxDvxLog "$work/$1/c" 400 | grep -c "$DVX_FULL_SCREEN_LOG"
}
# hold KEY... -- press the keys in order, each held holdSeconds before the
# next (a chord's modifier goes down first), release them in reverse, then
# give DVX and the program time to act.
hold() {
local k
local i
for k in "$@"; do
DISPLAY="$display" xdotool keydown --window "$win" "$k"
sleep "$holdSeconds"
done
for ((i = $#; i >= 1; i--)); do
DISPLAY="$display" xdotool keyup --window "$win" "${!i}"
done
sleep "$stepSeconds"
}
# shot PROGRAM NAME SIZE -- a DOSBox screenshot (Ctrl+F5: the raw VGA picture)
# as $work/NAME.png, which must be SIZE.
shot() {
local png
local size
local waited
DISPLAY="$display" xdotool key --window "$win" ctrl+F5
for ((waited = 0; waited < shotSeconds; waited++)); do
sleep 1
png=$(ls "$work/$1/shots/"*.png 2> /dev/null | head -1)
if [ -n "$png" ]; then
mv "$png" "$work/$2.png"
size=$(python3 -c 'import sys; from PIL import Image; print("%dx%d" % Image.open(sys.argv[1]).size)' "$work/$2.png")
echo "verify-dvx-fullscreen: $2: $size"
[ "$size" = "$3" ] || fail "$2 is $size, want $3"
return 0
fi
done
fail "no screenshot for $2"
}
# stop -- end the DOSBox run.
stop() {
joeyStop "$dosbox" "$guard" 2> /dev/null
dosbox=""
guard=""
}
display=":$((RANDOM % 400 + 3700))"
Xvfb "$display" -screen 0 1024x768x24 -nolisten tcp > /dev/null 2>&1 &
xvfb=$!
sleep 1
# 1. UBER: the hashes on the whole screen, through a suspend and a resume.
if ! boot uber; then
echo "verify-dvx-fullscreen: FAIL - DVX with UBER did not come up (DVX.LOG follows)" >&2
dvxDvxLog "$work/uber/c" >&2
exit 1
fi
shot uber uberFull "$fullSize"
hold ctrl Escape
shot uber uberSuspended "$desktopSize"
hold alt s
shot uber uberResumed "$fullSize"
log=$(dvxAwaitLog "$work/uber/c" uber "$uberDone" "$uberSeconds" "$guard")
sets=$(fullScreenSets uber)
stop
echo "verify-dvx-fullscreen: UBER: full-screen mode set $sets times"
[ "$sets" -ge 2 ] || fail "UBER: DVX set the full-screen mode $sets times, want 2 (start, resume)"
if [ -z "$log" ]; then
fail "UBER wrote no \"$uberDone\" within ${uberSeconds}s"
else
tr -d '\r' < "$log" > "$work/uber.txt"
if hashes=$("$repo/tools/diff-uber-hashes" "$repo/tests/goldens/uber/dos.txt" "$work/uber.txt"); then
echo "verify-dvx-fullscreen: UBER hashes: $(printf '%s\n' "$hashes" | tail -1)"
else
printf '%s\n' "$hashes"
fail "UBER's hashes on the whole screen differ from the DOS port's"
fi
fi
# 2. KEYS: the typed row read off the screen, full screen, window, full again.
if ! boot keys; then
echo "verify-dvx-fullscreen: FAIL - DVX with KEYS did not come up (DVX.LOG follows)" >&2
dvxDvxLog "$work/keys/c" >&2
exit 1
fi
DISPLAY="$display" xdotool type --window "$win" --delay 150 -- "$target"
sleep "$stepSeconds"
shot keys keysFull "$fullSize"
python3 "$repo/scripts/lib/keysRow.py" "$work/keysFull.png" "$target" --at "$rowAt" || fail "KEYS's row on the whole screen"
hold alt KP_Enter
shot keys keysWindow "$desktopSize"
python3 "$repo/scripts/lib/keysRow.py" "$work/keysWindow.png" "$target" || fail "KEYS's row in its window after leaving the whole screen"
hold alt KP_Enter
shot keys keysFullAgain "$fullSize"
python3 "$repo/scripts/lib/keysRow.py" "$work/keysFullAgain.png" "$target" --at "$rowAt" || fail "KEYS's row on the whole screen again"
hold Escape
log=$(dvxAwaitLog "$work/keys/c" keys '^typed=' "$logSeconds" "$guard")
sets=$(fullScreenSets keys)
stop
echo "verify-dvx-fullscreen: KEYS: full-screen mode set $sets times"
[ "$sets" -ge 2 ] || fail "KEYS: DVX set the full-screen mode $sets times, want 2 (start, Alt+Enter)"
if [ -z "$log" ]; then
fail "KEYS logged no typed line within ${logSeconds}s of Escape"
else
dvxKeysTyped "$log" "$target" || fail "KEYS's typed log"
fi
setting=$(find "$work/keys/c/DVX" -ipath "*/config/apps/$DVX_VENDOR/keys/$DVX_SETTINGS_FILE" -print -quit)
tr -d '\r' < "$setting" 2> /dev/null | grep -qi "^$DVX_SETTINGS_FULL_SCREEN *= *true" || fail "the setting does not say full screen after switching back ($setting)"
if [ -n "${DVX_FULLSCREEN_SHOTS:-}" ]; then
mkdir -p "$DVX_FULLSCREEN_SHOTS"
cp "$work"/*.png "$DVX_FULLSCREEN_SHOTS/"
fi
if [ -n "$fails" ]; then
echo "verify-dvx-fullscreen: FAIL - $fails"
exit 1
fi
echo "verify-dvx-fullscreen: PASS (UBER 51/51 on the whole screen through a suspend and resume; KEYS's typed row read off the 320x200 screen at (0,198), in its window, and full screen again)"