#!/usr/bin/env bash # Storage: sizes shown; log cleared now, cache at restart. set -euo pipefail root=$(cd "$(dirname "$0")/../.." && pwd) [ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; } work=$(mktemp -d) # Keeps the run's own status; the app's SIGTERM is expected. cleanup() { local status=$? if [ -n "${pid:-}" ]; then kill "$pid" 2>/dev/null || true wait "$pid" 2>/dev/null || true fi rm -rf "$work" exit "$status" } trap cleanup EXIT fail() { echo "FAIL: $*" >&2 exit 1 } cargo build -q -p ely-mark --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-mark" mkdir -p "$home" keys() { osascript -e 'tell application "System Events"' -e "$1" -e 'end tell' >/dev/null; } seen() { for _ in $(seq 60); do "$work/ax-values" "$pid" | grep -q -- "$1" && return 0; sleep 0.25; done return 1 } start() { ELY_SMOKE=hold ELY_LOCALE=en HOME="$home" perl -e 'alarm 400; exec @ARGV' "$root/target/debug/ely-mark" >"$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 KB the page shows for row $1. kb() { "$work/ax-values" "$pid" | grep -m 1 "title=$1" | sed 's/.*help=//; s/ KB.*//'; } # What the page should count under $1, KB rounded up. disk_kb() { find "$1" -type f -exec stat -f %z {} + | awk '{s += $1} END {print int((s + 1023) / 1024)}'; } quit() { keys 'keystroke "q" using command down' for _ in $(seq 40); do kill -0 "$pid" 2>/dev/null || break; sleep 0.25; done wait "$pid" 2>/dev/null || true } mkdir -p "$data/web" # A known 2 MiB in the cache for the row. dd if=/dev/zero of="$data/web/ely-sample" bs=1024 count=2048 2>/dev/null # A log long enough that clearing it shows. head -c 8192 /dev/zero | tr '\0' 'x' >"$data/ely.log" start keys 'keystroke "," using command down' seen "title=Storage" || fail "no settings window" "$work/ax-press" "$pid" Storage >/dev/null seen "title=Web content cache" || fail "the storage page lists no cache" shown=$(kb "Web content cache") [ "${shown:-0}" -ge 2048 ] || fail "the cache shows ${shown:-nothing} KB, not at least 2048" shown=$(kb "This app's log") [ "${shown:-0}" -ge 8 ] || fail "the log shows ${shown:-nothing} KB, not at least 8" # Each clear asks first; nothing goes before the yes. "$work/ax-press" "$pid" Clear AXButton >/dev/null seen "title=Delete" || fail "clearing the log did not ask" [ "$(wc -c <"$data/ely.log")" -gt 4096 ] || fail "the log went before the yes" "$work/ax-press" "$pid" Delete AXButton >/dev/null sleep 1 [ "$(wc -c <"$data/ely.log")" -lt 4096 ] || fail "the log was not cleared" "$work/ax-press" "$pid" "Clear at next start" AXButton >/dev/null seen "title=Delete" || fail "clearing the cache did not ask" [ ! -e "$data/.clear-web" ] || fail "the cache was marked before the yes" "$work/ax-press" "$pid" Delete AXButton >/dev/null seen "Clears at next start" || fail "the cache clear is not shown as pending" [ -e "$data/ely-sample" ] || [ -d "$data/web" ] || fail "the cache went while in use" # Ten points kept per document, once twelve were made. "$work/ax-press" "$pid" 10 >/dev/null for _ in $(seq 20); do grep -q '"keep": 10' "$data/settings.json" 2>/dev/null && break; sleep 0.25; done grep -q '"keep": 10' "$data/settings.json" || fail "the recovery limit is not kept" osascript -e "tell application \"System Events\" to click button 1 of (first window of (first process whose unix id is $pid) whose name is \"Settings\")" >/dev/null sleep 1 # An untitled document: never autosaved, so it keeps recovery points. keys 'keystroke "n" using command down' for _ in $(seq 40); do grep -q "mark: shown" "$data/ely.log" && break; sleep 0.25; done sleep 2 # Twelve points written, one edit each. written() { grep -c "recovery: a point at" "$data/ely.log" || true; } for n in $(seq 12); do before=$(written) keys "keystroke \"edit $n \"" for _ in $(seq 100); do [ "$(written)" -gt "$before" ] && break; sleep 0.25; done [ "$(written)" -gt "$before" ] || fail "edit $n wrote no point" done points=$(find "$data/recovery" -path '*/points/*.bin' | wc -l | tr -d ' ') [ "$points" -eq 10 ] || fail "$points recovery points kept, not 10" # Two picks while the file is locked: both are kept. keys 'keystroke "," using command down' seen "title=Storage" || fail "no settings window after the points" "$work/ax-press" "$pid" Storage >/dev/null seen "title=256" || fail "no space choices" shown=$(kb "Recovery copies") [ "$shown" = "$(disk_kb "$data/recovery")" ] || fail "recovery copies show ${shown:-nothing} KB, not $(disk_kb "$data/recovery")" [ "$shown" -gt 0 ] || fail "recovery copies show nothing" python3 -c 'import fcntl, sys, time; f = open(sys.argv[1], "a"); fcntl.flock(f, fcntl.LOCK_EX); time.sleep(5)' "$data/.settings.lock" & sleep 0.3 "$work/ax-press" "$pid" 20 >/dev/null # Another page and back: the reread keeps the waiting pick. "$work/ax-press" "$pid" General >/dev/null sleep 0.5 "$work/ax-press" "$pid" Storage >/dev/null seen "title=256" || fail "no space choices after coming back" sleep 0.5 "$work/ax-press" "$pid" 256 >/dev/null sleep 6 grep -q '"keep": 20' "$data/settings.json" && grep -q '"megabytes": 256' "$data/settings.json" || fail "one pick undid the other: $(grep -A3 recovery "$data/settings.json")" # Settings closed and opened again between two locked picks. python3 -c 'import fcntl, sys, time; f = open(sys.argv[1], "a"); fcntl.flock(f, fcntl.LOCK_EX); time.sleep(6)' "$data/.settings.lock" & sleep 0.3 "$work/ax-press" "$pid" 50 >/dev/null osascript -e "tell application \"System Events\" to click button 1 of (first window of (first process whose unix id is $pid) whose name is \"Settings\")" >/dev/null sleep 0.5 keys 'keystroke "," using command down' seen "title=Storage" || fail "no settings window the second time" "$work/ax-press" "$pid" Storage >/dev/null seen "title=256" || fail "no space choices the second time" "$work/ax-press" "$pid" 32 >/dev/null sleep 7 grep -q '"keep": 50' "$data/settings.json" && grep -q '"megabytes": 32' "$data/settings.json" || fail "reopening lost a pick: $(grep -A3 recovery "$data/settings.json")" # A failed limit save stays told after a clear succeeds. mv "$data/.settings.lock" "$work/lock" mkdir "$data/.settings.lock" "$work/ax-press" "$pid" 10 >/dev/null seen "Not done" || fail "the failed limit save is not told" rmdir "$data/.settings.lock" mv "$work/lock" "$data/.settings.lock" "$work/ax-press" "$pid" Clear AXButton >/dev/null seen "title=Delete" || fail "clearing the log did not ask the second time" "$work/ax-press" "$pid" Delete AXButton >/dev/null sleep 1 "$work/ax-values" "$pid" | grep -q "Not done" || fail "a clear hid the failed limit save" "$work/ax-press" "$pid" 20 >/dev/null for _ in $(seq 40); do grep -q '"keep": 20' "$data/settings.json" && break; sleep 0.25; done grep -q '"keep": 20' "$data/settings.json" || fail "the retried limit is not kept" sleep 0.5 "$work/ax-values" "$pid" | grep -q "Not done" && fail "the failure stays after a good save" quit touch "$data/web/ely-marker" start [ ! -e "$data/web/ely-marker" ] || fail "the cache was not cleared at the start" quit # A failed clear stops the start; the mark stays. mkdir -p "$data/web/locked" touch "$data/web/locked/kept" "$data/.clear-web" chmod 555 "$data/web/locked" status=0 ELY_SMOKE=hold ELY_LOCALE=en ELY_NO_DIALOG=1 HOME="$home" perl -e 'alarm 60; exec @ARGV' "$root/target/debug/ely-mark" >"$work/out" 2>&1 || status=$? chmod 755 "$data/web/locked" [ "$status" = 1 ] || fail "a failed clear started anyway ($status)" grep -q "could not be deleted" "$work/out" || fail "the failed clear is not told: $(tail -3 "$work/out")" grep -q "web: CEF" "$work/out" && fail "the cache opened after a failed clear" [ -e "$data/.clear-web" ] && [ -e "$data/web/locked/kept" ] || fail "the failed clear lost its mark or data" start [ ! -e "$data/web/locked/kept" ] || fail "the clear was not tried again" quit echo "ok: storage"