#!/bin/bash set -uo pipefail # Tests the minimise/restore state machine against a mock sway IPC, by # asserting the exact commands classroom-window sends. # # tests/test-classroom-window.sh ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SCRIPT="$ROOT/scripts/classroom-window" WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT passed=0 failed=0 check() { local label="$1" expected="$2" actual="$3" if [[ "$actual" == "$expected" ]]; then echo " ok $label" passed=$((passed + 1)) else echo " FAIL $label" echo " expected: ${expected//$'\n'/ | }" echo " got: ${actual//$'\n'/ | }" failed=$((failed + 1)) fi } mkdir -p "$WORK/bin" cat > "$WORK/bin/swaymsg" <<'SHIM' #!/usr/bin/env python3 import json, os, sys args = sys.argv[1:] state = json.load(open(os.environ["MOCK_TREE"])) if args[:1] == ["-t"]: print(json.dumps(state["tree" if args[1] == "get_tree" else "workspaces"])) sys.exit(0) with open(os.environ["MOCK_LOG"], "a") as log: log.write(" ".join(a for a in args if a != "--") + "\n") SHIM chmod +x "$WORK/bin/swaymsg" export PATH="$WORK/bin:$PATH" export MOCK_LOG="$WORK/log" export XDG_RUNTIME_DIR="$WORK/run" tree() { cat > "$WORK/tree.json" export MOCK_TREE="$WORK/tree.json" } run() { : > "$MOCK_LOG"; python3 "$SCRIPT" "$@" >/dev/null 2>&1; cat "$MOCK_LOG"; } # ------------------------------------------------ a focused Chrome window tree <<'JSON' {"tree":{"type":"root","id":1,"nodes":[ {"type":"output","id":2,"name":"HDMI-A-1","nodes":[ {"type":"workspace","id":3,"name":"1","nodes":[ {"type":"con","id":10,"pid":100,"app_id":"google-chrome","focused":true, "fullscreen_mode":0,"nodes":[],"floating_nodes":[]}],"floating_nodes":[]}, {"type":"workspace","id":4,"name":"__ekklesia_hidden","nodes":[ {"type":"con","id":11,"pid":101,"app_id":null, "window_properties":{"class":"vlc","instance":"vlc"},"focused":false, "fullscreen_mode":1,"nodes":[],"floating_nodes":[]}],"floating_nodes":[]} ],"floating_nodes":[]}],"floating_nodes":[]}, "workspaces":[{"name":"1","focused":true,"visible":true}, {"name":"__ekklesia_hidden","focused":false,"visible":false}]} JSON echo "1. the browser button" check "focused window is minimised, fullscreen dropped first" \ "[con_id=10] fullscreen disable [con_id=10] move container to workspace __ekklesia_hidden" \ "$(run toggle --match google-chrome -- google-chrome)" check "a minimised window comes back tiled, not floating" \ "[con_id=11] move container to workspace 1 [con_id=11] floating disable [con_id=11] focus" \ "$(run toggle --match '(?i)vlc' -- vlc)" echo echo "2. keyboard" check "Super+M minimises whatever is focused" \ "[con_id=10] fullscreen disable [con_id=10] move container to workspace __ekklesia_hidden" \ "$(run minimize)" check "Super+Shift+M restores from the hidden workspace" \ "[con_id=11] move container to workspace 1 [con_id=11] floating disable [con_id=11] focus" \ "$(run restore-last)" echo echo "3. a running but unfocused window is focused, not minimised" python3 - "$WORK/tree.json" <<'PY' import json, sys data = json.load(open(sys.argv[1])) data["tree"]["nodes"][0]["nodes"][0]["nodes"][0]["focused"] = False json.dump(data, open(sys.argv[1], "w")) PY check "focus only" "[con_id=10] focus" "$(run toggle --match google-chrome -- x)" echo echo "4. nothing running launches the application" : > "$MOCK_LOG" output="$(python3 "$SCRIPT" toggle --match firefox -- /bin/echo LAUNCHED 2>&1)" sleep 0.3 check "launch instead of a sway command" "LAUNCHED" "$output" check "no sway command sent" "" "$(cat "$MOCK_LOG")" echo echo "5. a window stranded in sway's own scratchpad is rescued" tree <<'JSON' {"tree":{"type":"root","id":1,"nodes":[ {"type":"output","id":90,"name":"__i3","nodes":[ {"type":"workspace","id":91,"name":"__i3_scratch","nodes":[],"floating_nodes":[ {"type":"floating_con","id":12,"pid":102,"app_id":"google-chrome", "focused":false,"fullscreen_mode":0,"nodes":[],"floating_nodes":[]}]}], "floating_nodes":[]}, {"type":"output","id":2,"name":"HDMI-A-1","nodes":[ {"type":"workspace","id":3,"name":"1","nodes":[],"floating_nodes":[]}], "floating_nodes":[]}],"floating_nodes":[]}, "workspaces":[{"name":"1","focused":true,"visible":true}, {"name":"__i3_scratch","focused":false,"visible":false}]} JSON check "pulled back and forced out of floating" \ "[con_id=12] move container to workspace 1 [con_id=12] floating disable [con_id=12] focus" \ "$(run toggle --match google-chrome -- x)" echo echo "6. sway not running is survivable" export PATH="${PATH#"$WORK/bin:"}" for action in list minimize restore-last; do python3 "$SCRIPT" "$action" >/dev/null 2>&1 check "$action exits cleanly with no sway" "0" "$?" done echo echo "passed: $passed failed: $failed" [[ "$failed" -eq 0 ]]