m16-widgets.sh raw

#!/usr/bin/env bash
# M16 widgets test under quibble, driving components/Settings.gdc:
#   1. Enter activates the focused button (the focus invariant focuses the
#      first button at mount) — "all on",
#   2. Tab moves focus to the next button; Enter activates it — "all off",
#   3. a pointer click toggles a checkbox (and focuses it),
#   4. Space toggles the now-focused checkbox back,
#   5. idle renders zero frames (buttons and checkboxes request no timers).
set -euo pipefail
cd "$(dirname "$0")/.."

cargo build -p guiduck --example m16_demo

workdir=$(mktemp -d)
sock="$workdir/quibble.sock"
cleanup() {
    quibblectl --socket "$sock" quit >/dev/null 2>&1 || true
    rm -rf "$workdir"
}
trap cleanup EXIT

GUIDUCK_BACKEND=software GUIDUCK_TRACE_FRAMES=1 \
    quibble --socket "$sock" --width 240 --height 150 \
    target/debug/examples/m16_demo \
    >"$workdir/out.log" 2>"$workdir/err.log" &
for _ in $(seq 1 50); do
    quibblectl --socket "$sock" ping >/dev/null 2>&1 && break
    sleep 0.2
done
quibblectl --socket "$sock" wait-window --timeout-ms 30000 >/dev/null
sleep 1

frames() { grep -c '^guiduck-frame' "$workdir/err.log" || true; }
qc() { quibblectl --socket "$sock" "$@" >/dev/null; }
shot() { quibblectl --socket "$sock" screenshot -o "$workdir/$1" >/dev/null; }
last() { grep '^options: ' "$workdir/out.log" | tail -1; }
fail=0

KEY_TAB=15; KEY_ENTER=28; KEY_SPACE=57
key() {
    quibblectl --socket "$sock" key "$1" press >/dev/null
    quibblectl --socket "$sock" key "$1" release >/dev/null
}

# Widget centers (from tests/m16_widgets.rs::print_settings_layout at 240x150).
ALLON_X=42;  ALLON_Y=24
WIFI_X=78;   WIFI_Y=54

shot s0.png

# 1: Enter activates the focused button. The focus invariant focused the
#    first focusable (the "all on" button) at mount.
key $KEY_ENTER
sleep 0.3
shot s1.png
v=$(last)
if [ "$v" = "options: wifi=on bluetooth=on airplane=on" ] && ! cmp -s "$workdir/s0.png" "$workdir/s1.png"; then
    echo "Enter activated the focused button: $v"
else
    echo "FAIL: Enter activate; got '$v'" >&2; fail=1
fi

# 2: Tab moves focus to the next button; Enter activates "all off".
key $KEY_TAB
key $KEY_ENTER
sleep 0.3
shot s2.png
v=$(last)
if [ "$v" = "options: wifi=off bluetooth=off airplane=off" ] && ! cmp -s "$workdir/s1.png" "$workdir/s2.png"; then
    echo "Tab+Enter activated the second button: $v"
else
    echo "FAIL: Tab+Enter; got '$v'" >&2; fail=1
fi

# 3: a pointer click toggles a checkbox (and focuses it).
qc pointer-move $WIFI_X $WIFI_Y
qc click
sleep 0.3
shot s3.png
v=$(last)
if [ "$v" = "options: wifi=on bluetooth=off airplane=off" ] && ! cmp -s "$workdir/s2.png" "$workdir/s3.png"; then
    echo "click toggled the checkbox: $v"
else
    echo "FAIL: checkbox click; got '$v'" >&2; fail=1
fi

# 4: Space toggles the now-focused checkbox back off.
key $KEY_SPACE
sleep 0.3
v=$(last)
if [ "$v" = "options: wifi=off bluetooth=off airplane=off" ]; then
    echo "Space toggled the focused checkbox: $v"
else
    echo "FAIL: Space toggle; got '$v'" >&2; fail=1
fi

# 5: idle renders zero frames (no timers; buttons/checkboxes never blink).
q0=$(frames); sleep 3; q1=$(frames)
echo "idle frames: $q0 -> $q1"
[ "$q0" = "$q1" ] || { echo "FAIL: rendering while idle" >&2; fail=1; }

cp "$workdir/s3.png" target/m16-widgets.png 2>/dev/null || true
[ "$fail" -eq 0 ] && echo "M16 widgets test PASSED"
exit $fail