Files
crkl/scripts/smoke-circle.sh
T
ilia 8509d93ed5
CI / skip-ci-check (pull_request) Successful in 30s
CI / secret-scan (pull_request) Successful in 28s
Icon-only VIP chips and faster draw overlay
Replace labeled chips with icons (Todo = checkbox+check). Drop software
layer and BlurMaskFilter; draw strokes with a Path and spaced points.
2026-08-05 14:40:55 -04:00

168 lines
5.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Device/emulator smoke — catches the bugs that unit tests + "any extract" miss.
# Cases:
# 1) Tight circle on "How to circle" must NOT steal Ship demo block above
# 2) Circle email region → Copy chip works
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
ADB="${ADB:-adb}"
COMP='com.example.crkl/com.example.crkl.accessibility.CrklAccessibilityService'
PKG=com.example.crkl
die() { echo "FAIL: $*" >&2; exit 1; }
pass() { echo "OK: $*"; }
# adb devices -l uses spaces, not tabs, between serial and state
"$ADB" devices | awk '/device( |$)/ && $1 !~ /List/{found=1} END{exit !found}' \
|| die "no adb device"
echo "== smoke Circle on $($ADB get-serialno) =="
"$ADB" shell settings put secure accessibility_enabled 1
"$ADB" shell settings put secure enabled_accessibility_services "$COMP"
"$ADB" shell am force-stop "$PKG" >/dev/null 2>&1 || true
sleep 1
"$ADB" shell settings put secure enabled_accessibility_services "$COMP"
"$ADB" shell settings put secure accessibility_enabled 1
sleep 1.5
"$ADB" shell am start -n "$PKG/.fixtures.TestFixturesActivity" >/dev/null
sleep 1.5
enter_circle() {
"$ADB" logcat -c
"$ADB" shell input tap 964 2200
sleep 0.4
if "$ADB" logcat -d -s OverlayView:D | grep -q 'floating button clicked'; then
return 0
fi
for y in $(seq 2140 20 2280); do
for x in $(seq 900 20 1030); do
"$ADB" shell input tap "$x" "$y"
sleep 0.05
if "$ADB" logcat -d -s OverlayView:D | grep -q 'floating button clicked'; then
return 0
fi
done
done
return 1
}
draw_loop() {
local cx="$1" cy="$2" r="$3"
python3 - "$cx" "$cy" "$r" <<'PY'
import math, subprocess, sys, time
cx, cy, r = map(int, sys.argv[1:4])
adb = lambda *a: subprocess.check_call(["adb", *a])
n = 28
pts = [
(
int(cx + r * math.cos(2 * math.pi * i / n - math.pi / 2)),
int(cy + r * math.sin(2 * math.pi * i / n - math.pi / 2)),
)
for i in range(n + 1)
]
adb("shell", "input", "motionevent", "DOWN", str(pts[0][0]), str(pts[0][1]))
for x, y in pts[1:]:
adb("shell", "input", "motionevent", "MOVE", str(x), str(y))
adb("shell", "input", "motionevent", "UP", str(pts[-1][0]), str(pts[-1][1]))
for _ in range(25):
time.sleep(0.3)
out = subprocess.check_output(["adb", "logcat", "-d"], text=True)
if "extract:" in out or "Selection ready" in out:
break
PY
}
close_panel() {
"$ADB" shell input tap 980 1300 || true
sleep 0.3
"$ADB" shell input keyevent KEYCODE_BACK || true
sleep 0.3
}
# Resolve live UI bounds so layout/scroll changes do not false-fail smoke.
"$ADB" shell uiautomator dump /sdcard/crkl-smoke.xml >/dev/null
"$ADB" pull /sdcard/crkl-smoke.xml /tmp/crkl-smoke.xml >/dev/null
eval "$(python3 <<'PY'
import re, sys
xml = open("/tmp/crkl-smoke.xml").read()
m = re.search(r'text="How to circle"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"', xml)
if not m:
sys.exit("How to circle not on screen — open fixtures / scroll to top")
x1, y1, x2, y2 = map(int, m.groups())
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
r = max(60, min(100, (x2 - x1) // 2 + 30, (y2 - y1) // 2 + 40))
print(f"HEAD_CX={cx}; HEAD_CY={cy}; HEAD_R={r}")
# Email fixture / subject area — prefer Subject line if present
m2 = re.search(r'text="[^"]*Subject: Q2[^"]*"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"', xml)
if not m2:
m2 = re.search(r'text="[^"]*Q2 planning moved[^"]*"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"', xml)
if m2:
a, b, c, d = map(int, m2.groups())
print(f"MAIL_CX={(a+c)//2}; MAIL_CY={(b+d)//2}; MAIL_R=160")
else:
print("MAIL_CX=540; MAIL_CY=1720; MAIL_R=160")
PY
)"
# --- Case 1: heading must not steal Ship demo ---
enter_circle || die "FAB not clickable — is Circle Overlay ON?"
pass "enter circle mode"
draw_loop "$HEAD_CX" "$HEAD_CY" "$HEAD_R"
logs="$("$ADB" logcat -d)"
echo "$logs" | grep -q 'Selection ready' || die "case1: no selection"
echo "$logs" | grep -E 'extract:.*preview=' | grep -qi 'How to circle' \
|| die "case1: extract missing 'How to circle' (got wrong node?)"
if echo "$logs" | grep -E 'extract:.*preview=' | grep -qi 'English sentence'; then
die "case1: Ship demo block leaked into heading circle"
fi
pass "tight heading extract (no Ship demo leak)"
close_panel
# --- Case 2: email region → Copy ---
"$ADB" shell am start -n "$PKG/.fixtures.TestFixturesActivity" >/dev/null
sleep 1
# Re-dump in case scroll changed
"$ADB" shell uiautomator dump /sdcard/crkl-smoke.xml >/dev/null
"$ADB" pull /sdcard/crkl-smoke.xml /tmp/crkl-smoke.xml >/dev/null
eval "$(python3 <<'PY'
import re
xml = open("/tmp/crkl-smoke.xml").read()
m2 = re.search(r'text="[^"]*Subject: Q2[^"]*"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"', xml)
if not m2:
m2 = re.search(r'text="[^"]*Q2 planning moved[^"]*"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"', xml)
if m2:
a, b, c, d = map(int, m2.groups())
print(f"MAIL_CX={(a+c)//2}; MAIL_CY={(b+d)//2}; MAIL_R=160")
else:
print("MAIL_CX=540; MAIL_CY=1720; MAIL_R=160")
PY
)"
enter_circle || die "FAB not clickable (case2)"
draw_loop "$MAIL_CX" "$MAIL_CY" "$MAIL_R"
logs="$("$ADB" logcat -d)"
echo "$logs" | grep -qE 'extract:.*chars=[1-9]' || die "case2: no text extracted"
pass "email region extract"
"$ADB" logcat -c
# Icon-only chips: Translate, Copy, Explain, Share, Todo — ~44dp, y≈2100.
copied=0
for y in 2090 2100 2110; do
for x in 200 240 280 160 320; do
"$ADB" shell input tap "$x" "$y"
sleep 0.3
if "$ADB" logcat -d | grep -q 'action kind=COPY'; then
copied=1
break 2
fi
done
done
[[ "$copied" = 1 ]] || die "Copy chip not triggered"
"$ADB" logcat -d | grep -q 'action result ok=true' || die "Copy failed"
pass "Copy chip"
echo "== smoke PASSED =="
echo "Tip: full dogfood is docs/dogfood.md"