#!/usr/bin/env bash # MARK-09, 11, 13, 14 live: look, output, Git, large files. set -euo pipefail root=$(cd "$(dirname "$0")/../.." && pwd) [ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; } [ -d "${ELY_CEF:-$root/engines/cef}/Chromium Embedded Framework.framework" ] || { echo "SKIP: no CEF; run scripts/fetch-cef.sh" exit 0 } command -v npm >/dev/null || { echo "SKIP: no npm"; exit 0; } command -v pdftotext >/dev/null || { echo "SKIP: no pdftotext"; exit 0; } [ -x "$root/engines/git/bin/git" ] || export ELY_GIT=${ELY_GIT:-$(command -v git)} work=$(mktemp -d) app= trap 'if [ -n "$app" ]; then kill "$app" 2>/dev/null || true; wait "$app" 2>/dev/null || true; fi; pkill -f "$work" 2>/dev/null || true; rm -rf "$work"' EXIT fail() { echo "FAIL: $*" >&2 exit 1 } "$root/scripts/build-mark-content.sh" >"$work/build" 2>&1 || fail "build: $(tail -n 5 "$work/build")" cargo build -q -p ely-mark -p ely-tree -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 repo=$work/repo mkdir -p "$repo/assets" python3 -c 'import struct,zlib,sys c=lambda t,d: struct.pack(">I",len(d))+t+d+struct.pack(">I",zlib.crc32(t+d)) open(sys.argv[1],"wb").write(b"\x89PNG\r\n\x1a\n"+c(b"IHDR",struct.pack(">IIBBBBB",1,1,8,2,0,0,0))+c(b"IDAT",zlib.compress(b"\0\xff\0\0"))+c(b"IEND",b""))' "$repo/assets/pic.png" cp "$repo/assets/pic.png" "$repo/assets/high.png" doc=$repo/t.md printf '%s\n' '# Title' '' 'Some $x^2$ math.' '' '![pic](assets/pic.png)' '' "" '' \ "a > b" '' '```mermaid' 'graph TD; A-->B' '```' '' \ '```mermaid' 'graph TD; SECRET_WORDS -->' '```' '' '
RAW TEXT
TWO
' '' \ "" '' "" '' \ "" '' \ '$\privateDocumentToken$' '' '![gone](missing.png)' '' 'END MARK' >"$doc" git -C "$repo" init -q git -C "$repo" -c user.name=t -c user.email=t@e.x add -A git -C "$repo" -c user.name=t -c user.email=t@e.x commit -qm one original=$(cat "$doc") launch() { ELY_LOG=info ELY_LOCALE=en ELY_NO_DIALOG=1 HOME="$work" \ "$root/target/debug/ely-mark" "$@" >"$work/log" 2>&1 & app=$! waits "mark: shown as" osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $app) to true" -e 'delay 2' >/dev/null } waits() { for _ in $(seq 160); do grep -qF "$1" "$work/log" && return 0 kill -0 "$app" 2>/dev/null || fail "ElyMark quit: $(tail -n 5 "$work/log")" sleep 0.25 done fail "never saw '$1': $(grep -E 'mark:|office:' "$work/log" | tail -n 5)" } count() { grep -c "$1" "$work/log" || true; } front() { osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $app) to true" -e 'delay 1' >/dev/null; } key() { osascript -e "tell application \"System Events\" to $1" -e 'delay 0.8' >/dev/null; } # The window's own titles; system menus list recent files too. seen() { "$work/ax-values" "$app" | grep -v '^AXMenu' | grep -qF "title=$1"; } press() { for _ in $(seq 40); do [ "$("$work/ax-press" "$app" "$@")" = pressed ] && { sleep 0.8; return 0; } sleep 0.25 done fail "could not press $*" } quit() { kill "$app" wait "$app" 2>/dev/null || true app= } # Asks a `kind` export beside the document, maybe named `$2`. ask_export() { front key 'keystroke "e" using command down' press "$1" press "Export…" AXButton # The panel opens in the document's folder, the stem chosen. sleep 3 [ -z "${2:-}" ] || key "keystroke \"$2\"" # The panel's own button: Return alone did not always save. press Save AXButton } # Exports `kind`; waits for its log line. export_as() { local before failed before=$(count "mark: exported") failed=$(count "export failed") ask_export "$@" for _ in $(seq 160); do [ "$(count "mark: exported")" -gt "$before" ] && return 0 [ "$(count "export failed")" -gt "$failed" ] && fail "export: $(grep "export failed" "$work/log" | tail -n 1)" sleep 0.25 done fail "no $1 export: $(grep -E "mark:|office:|dialog|panel" "$work/log" | tail -n 4)" } launch "$doc" [ "$("$work/ax-press" $$ none)" != untrusted ] || fail "needs Accessibility permission" # Git sees the file; its item opens ElyTree there. for _ in $(seq 40); do seen "Git: unchanged" && break; sleep 0.25; done seen "Git: unchanged" || fail "no Git state: $(grep 'git says' "$work/log" | tail -n 1)" key 'keystroke "f" using command down' key 'key code 53' key 'key code 125 using command down' key 'keystroke "Z"' for _ in $(seq 60); do seen "Git: changed" && break; sleep 0.25; done seen "Git: changed" || fail "Git missed the change: $(grep -E "git says|autosave|saved" "$work/log" | tail -n 4)" printf '%s\n' "$original" >"$doc" press "Git: changed" for _ in $(seq 40); do pgrep -f "target/debug/ely-tree .*${repo#/private}" >/dev/null && break; sleep 0.25; done pgrep -f "target/debug/ely-tree .*${repo#/private}" >/dev/null || fail "ElyTree did not open the repository" # ElyTree takes the file itself and shows its history (§16). waits "tree: file history of t.md" pkill -f "target/debug/ely-tree .*${repo#/private}" || true sleep 2 front # Focus mode folds the chrome; the look outlives the app. press "Focus Mode" ! seen "t.md" || fail "focus mode kept the tabs" press "Serif Font" quit grep -q '"focus": true' "$work/Library/Application Support/ElyOffice/ely-mark/look.json" || fail "the look was not kept" [ "$(cat "$doc")" = "$original" ] || fail "the look changed the file: $(cat "$doc")" printf '# Other\n' >"$repo/b.md" launch "$repo/b.md" "$doc" ! seen "t.md" || fail "focus mode did not come back" press "Focus Mode" seen "t.md" || fail "focus mode stayed" # Tabs open in any order; t.md's page takes the keys. press t.md key 'keystroke "f" using command down' key 'key code 53' # Each export holds the whole document. export_as HTML html=$repo/t.html grep -q 'class="katex' "$html" && grep -q '/dev/null && break; sleep 0.25; done pgrep -f "target/debug/ely-pdf .*t.pdf" >/dev/null || fail "Open did not show the PDF in ElyPDF" pkill -f "target/debug/ely-pdf .*t.pdf" || true front pdftotext "$repo/t.pdf" - | grep -q "END MARK" || fail "the PDF lacks text" [ "$(grep -c 'without 1 images' "$work/log")" -ge 3 ] || fail "the PDF hid a missing image" export_as "Plain Text" grep -q 'x^2' "$repo/t.txt" && grep -qx 'RAW TEXT' "$repo/t.txt" && grep -qx 'TWO' "$repo/t.txt" && grep -q 'END MARK' "$repo/t.txt" || fail "the text: $(cat "$repo/t.txt")" # Print renders the same page, then the system panel. printed=$(count "web: printed") key 'keystroke "p" using command down' for _ in $(seq 60); do [ "$(count "web: printed")" -gt "$printed" ] && break; sleep 0.25; done [ "$(count "web: printed")" -gt "$printed" ] || fail "print made no PDF" sleep 2 key 'key code 53' # Rich copy carries HTML; it overwrites the clipboard. if [ "${ELY_CLIPBOARD_TEST:-}" = 1 ]; then key 'keystroke "f" using command down' key 'key code 53' key 'keystroke "a" using command down' key 'keystroke "c" using command down' osascript -e 'clipboard info' | grep -q 'HTML' || fail "the copy carried no HTML: $(osascript -e 'clipboard info')" fi quit # A large file: source alone, every byte kept and exported. big=$work/big.md python3 -c 'import sys open(sys.argv[1],"w").write("".join(f"Line {n} of a large file.\n\n" for n in range(120000))+"LAST LINE\n")' "$big" size=$(wc -c <"$big") launch "$big" waits 'mark: shown as "source"' key 'keystroke "1" using command down' waits "a large file stays in source" key 'key code 125 using command down' # A digit: an input method never holds it. key 'keystroke "9"' for _ in $(seq 40); do grep -q 'LAST LINE' "$big" && [ "$(wc -c <"$big")" -gt "$size" ] && break; sleep 0.25; done [ "$(wc -c <"$big")" -gt "$size" ] && grep -q 'LAST LINE' "$big" && grep -q '^Line 0 of' "$big" || fail "the large file lost bytes" export_as "Plain Text" grep -q 'LAST LINE' "$work/big.txt" || fail "a large export was cut" quit echo "ok: mark output"