#!/usr/bin/env bash
# ElyDoc print: the document's paper and scale, cancel changes nothing.
set -euo pipefail
root=$(cd "$(dirname "$0")/../.." && pwd)
[ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; }
command -v pdftotext >/dev/null && command -v pdfinfo >/dev/null || { echo "SKIP: needs poppler"; 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-lok --bins -p ely-doc --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-doc"
mkdir -p "$home"
# A5 landscape, and A5 then A3; written without LibreOffice.
python3 - "$work" <<'PY'
import sys, zipfile
w = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"'
margins = ''
a5 = f'{margins}'
a3 = f'{margins}'
thin = ''
wide = f'{thin}'
square = f'{thin}'
bodies = {
"a5.docx": f'Print me{a5}',
"mixed.docx": f'{a5}Small'
f'Edge{a3}',
"crossed.docx": f'Begin'
f'{wide}Right'
f'Square{square}',
}
for name, body in bodies.items():
parts = {
"[Content_Types].xml": ''
''
''
'',
"_rels/.rels": ''
'',
"word/document.xml": f'{body}',
}
with zipfile.ZipFile(f"{sys.argv[1]}/{name}", "w") as archive:
for part, text in parts.items():
archive.writestr(part, text)
PY
cp "$work/a5.docx" "$work/a5.orig"
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
}
# How often $1 has opened so far.
opened() { local n; n=$(grep -c "opened $1" "$data/ely.log" 2>/dev/null || true); echo "${n:-0}"; }
# Opens $1; extra environment in the rest.
start() {
local file=$1 before
shift
before=$(opened "$file")
env "$@" ELY_SMOKE=hold ELY_LOCALE=en ELY_NO_DIALOG=1 HOME="$home" perl -e 'alarm 200; exec @ARGV' \
"$root/target/debug/ely-doc" "$work/$file" >"$work/out" 2>&1 &
pid=$!
for _ in $(seq 150); do [ "$(opened "$file")" -gt "$before" ] && break; sleep 0.2; done
[ "$(opened "$file")" -gt "$before" ] || fail "$file did not open"
osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $pid) to true" >/dev/null
sleep 1
}
stop() {
pkill -9 -P "$pid" 2>/dev/null || true
kill "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
pid=
}
print() {
keys 'keystroke "p" using command down'
seen "title=Print…" || fail "no print dialog"
"$work/ax-press" "$pid" "Print…" AXButton >/dev/null
}
# The panel, cancelled: nothing changes.
start a5.docx
print
for _ in $(seq 80); do grep -q "print: paper" "$data/ely.log" && break; sleep 0.25; done
grep -q "print: paper" "$data/ely.log" || fail "the print panel did not open"
sleep 1
"$work/ax-press" "$pid" Cancel AXButton >/dev/null
for _ in $(seq 40); do grep -q "print done, printed false" "$data/ely.log" && break; sleep 0.25; done
grep -q "print done, printed false" "$data/ely.log" || fail "the cancel was not seen"
[ -z "$(find "$data/work" -name print.pdf)" ] || fail "the print copy stays"
cmp -s "$work/a5.docx" "$work/a5.orig" || fail "printing changed the file"
keys 'keystroke "w" using command down'
for _ in $(seq 40); do grep -q "office: closed a5.docx" "$data/ely.log" && break; sleep 0.25; done
grep -q "office: closed a5.docx" "$data/ely.log" || fail "the printed document asks or stays"
stop
# The real job, saved: its pages and text positions.
printed() {
rm -f "$work/printed.pdf"
# A shared half scale the print must undo.
start "$1" ELY_PRINT_TO="$work/printed.pdf" ELY_PRINT_SHARED_SCALE=0.5
print
for _ in $(seq 80); do [ -s "$work/printed.pdf" ] && break; sleep 0.25; done
[ -s "$work/printed.pdf" ] || fail "$1: no printed output"
stop
}
sizes() { pdfinfo -f 1 -l 9 "$work/printed.pdf" | awk '/^Page +[0-9]+ size:/ { printf "%.0fx%.0f ", $4, $6 }'; }
# The printed pages are $1 (sizes), each within a point.
pages_are() {
python3 -c 'import sys; got, want = sys.argv[1].split(), sys.argv[2].split()
ok = len(got) == len(want) and all(abs(float(a) - float(b)) <= 1 for g, w in zip(got, want) for a, b in zip(g.split("x"), w.split("x")))
sys.exit(0 if ok else 1)' "$(sizes)" "$1"
}
word() { pdftotext -bbox "$work/printed.pdf" - | grep -m 1 ">$1<"; }
printed a5.docx
pages_are "595x420" || fail "a5: printed on $(sizes), not 595x420"
# One inch in: no scale and no shift.
x=$(word Print | sed -E 's/.*xMin="([0-9.]+)".*/\1/')
python3 -c 'import sys; sys.exit(0 if abs(float(sys.argv[1]) - 72) < 2 else 1)' "$x" || fail "a5: the text starts at $x, not 72"
printed mixed.docx
pages_are "1191x842 1191x842" || fail "mixed: printed on $(sizes), not the A3 paper twice"
word Small >/dev/null || fail "mixed: the A5 page lost its text"
edge=$(word Edge | sed -E 's/.*xMax="([0-9.]+)".*/\1/')
python3 -c 'import sys; sys.exit(0 if 1000 < float(sys.argv[1]) <= 1191 else 1)' "$edge" || fail "mixed: the A3 edge text is at $edge"
printed crossed.docx
pages_are "1000x600 1000x600" || fail "crossed: printed on $(sizes), not 1000x600 twice"
word Begin >/dev/null && word Square >/dev/null || fail "crossed: a page lost its text"
right=$(word Right | sed -E 's/.*xMax="([0-9.]+)".*/\1/')
python3 -c 'import sys; sys.exit(0 if 900 < float(sys.argv[1]) <= 1000 else 1)' "$right" || fail "crossed: the right end is at $right"
echo "ok: print"