Files
ElyOffice/tests/scripts/pdf-recovery.sh
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

78 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# ElyPDF: a locked file keeps sealed points past engine ends.
set -euo pipefail
root=$(cd "$(dirname "$0")/../.." && pwd)
[ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; }
work=$(mktemp -d)
cleanup() {
local status=$?
if [ -n "${pid:-}" ]; then
pkill -9 -P "$pid" 2>/dev/null || true
kill "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
fi
[ "$status" = 0 ] && rm -rf "$work" || echo "kept $work" >&2
exit "$status"
}
trap cleanup EXIT
fail() {
echo "FAIL: $*" >&2
exit 1
}
cargo build -q -p ely-pdf-engine --bins -p ely-pdf --manifest-path "$root/Cargo.toml"
for tool in ax-values ax-press; do swiftc -O -o "$work/$tool" "$root/tests/scripts/$tool.swift"; done
[ "$("$work/ax-values" $$ | head -n 1)" != untrusted ] || { echo "SKIP: needs Accessibility permission"; exit 0; }
home="$work/home"
data="$home/Library/Application Support/ElyOffice/ely-pdf"
mkdir -p "$home"
cp "$root/tests/fixtures/pdf/aes128.pdf" "$work/locked.pdf"
keys() { osascript -e 'tell application "System Events"' -e "$1" -e 'end tell' >/dev/null; }
seen() {
for _ in $(seq 80); do "$work/ax-values" "$pid" | grep -q -- "$1" && return 0; sleep 0.25; done
return 1
}
opened() { { grep -c "ely-pdf: opened" "$data/ely.log" 2>/dev/null || true; } | head -n 1; }
start() {
ELY_SMOKE=hold ELY_LOCALE=en ELY_NO_DIALOG=1 HOME="$home" perl -e 'alarm 300; exec @ARGV' \
"$root/target/debug/ely-pdf" "$@" >"$work/out" 2>&1 &
pid=$!
for _ in $(seq 40); do "$work/ax-values" "$pid" | grep -q AXWindow && break; sleep 0.25; done
osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $pid) to true" >/dev/null
sleep 1
}
# The open-password dialog, answered; then the tab is there.
unlock() {
local before
before=$(opened)
seen "is locked" || fail "no password asked ($1)"
keys 'keystroke "owner"'
keys 'key code 36'
for _ in $(seq 80); do [ "$(opened)" -gt "${before:-0}" ] && break; sleep 0.25; done
[ "$(opened)" -gt "${before:-0}" ] || fail "the locked file did not open ($1)"
}
# A new sealed point, and never a plain one.
sealed() {
touch "$work/mark"
for _ in $(seq 100); do
find "$data/recovery" -name '*.enc' -newer "$work/mark" 2>/dev/null | grep -q . && break
sleep 0.25
done
find "$data/recovery" -name '*.enc' -newer "$work/mark" | grep -q . || fail "no sealed point ($1)"
[ -z "$(find "$data/recovery" -name '*.bin')" ] || fail "a plain point of a locked file ($1)"
}
start "$work/locked.pdf"
unlock "the file"
osascript -e "tell application \"System Events\" to tell (first process whose unix id is $pid) to click menu item \"Rotate Pages Right\" of menu \"Pages\" of menu bar 1" >/dev/null
sealed "while editing"
# The idle engine ends: told; the copy asks again.
pkill -9 -P "$pid" -f ely-pdf-worker || fail "no worker to stop"
seen "The document engine stopped" || fail "an idle engine's end is not told"
"$work/ax-press" "$pid" "Reopen documents" >/dev/null
unlock "the copy after the engine ended"
[ -n "$(find "$data/recovery" -name '*.enc')" ] || fail "the old points went before a new one"
grep -q "the engine is back, 0 tab(s) lost" "$data/ely.log" || fail "a tab is lost"
sealed "for the reopened copy"
echo "ok: pdf recovery"