1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
#!/bin/bash
# Correctness gate: no perf win is allowed to cost functionality.
#
# 1. .auto/check_search.py -- the search fast paths against the plain loop.
# Caches that go stale still return AN answer, so no scenario test can see
# them; this compares fast and slow directly, for every typed prefix.
# 2. .auto/check_rename.py -- a rename keeps the listing's walk and only
# re-renders its text. When that goes wrong the pane simply keeps showing
# the old name, which nothing else notices. Checks a NARROW read (what
# painting does) and a WIDE one (what building the search body does), and
# the whole model against a rebuild.
# 3. .auto/check_edit.py -- the listing after an ITEM edit. bump_items(ea)
# keeps the walk in front of the edit rather than discarding it; keeping
# anything across a structural change is the risky half and it fails
# silently, so the kept model is compared against a rebuild row for row.
# 4. tests/run.py -- the project's own front door: every suite, pure and IDA,
# ~185s. It used to be only the scenario suite here, and that gap cost a
# real regression: a faster worker connect left the loading overlay up a
# moment longer relative to the index finishing, and project mode's first
# keypress landed on the overlay. Only test_project_ui.py covers that, and
# it was not being run.
#
# Only failures reach stdout: the agent sees the last 80 lines on failure, and a
# wall of "ok" would push the actual break out of view. A file that fails is
# re-run ALONE before it counts -- the IDA suites share a loaded box, and a
# worker that got CPU-starved mid-analysis reads as a failure but is not one
# (see the note in tests/run.py).
set -euo pipefail
cd "$(dirname "$0")/.."
PY="${IDATUI_PYTHON:-$HOME/ida-venv/bin/python}"
search=$("$PY" .auto/check_search.py targets/echo 2>&1) || {
echo "--- search fast paths disagree with the plain loop ---"
echo "$search" | tail -20
exit 1
}
echo "$search" | tail -1
rn=$("$PY" .auto/check_rename.py targets/echo 2>&1) || {
echo "--- the listing is wrong after a rename ---"
echo "$rn" | tail -20
exit 1
}
echo "$rn" | tail -1
ed=$("$PY" .auto/check_edit.py targets/echo 2>&1) || {
echo "--- the listing is wrong after an item edit ---"
echo "$ed" | tail -20
exit 1
}
echo "$ed" | tail -1
out=$(python3 tests/run.py 2>&1) || true
echo "$out" | tail -2
# Files run.py marked bad, e.g. " FAIL scenarios 301 passed, 2 failed"
# run.py's summary says "N passed[, M failed]..."; no "failed" clause == green.
if ! echo "$out" | tail -3 | grep -q "failed"; then
exit 0
fi
echo "--- first pass failures ---"
echo "$out" | grep -E "^ FAIL" | head -20
# run.py names them itself: "failing files: formats scenarios" (colourised).
files=$(echo "$out" | sed -e 's/\x1b\[[0-9;]*m//g' \
| sed -n 's/^failing files: *//p' | tr '\n' ' ')
if [ -z "$files" ]; then
echo "--- could not identify the failing file; full tail ---"
echo "$out" | tail -30
exit 1
fi
echo "--- retrying alone: $files ---"
retry=$(python3 tests/run.py $files 2>&1) || true
if echo "$retry" | tail -3 | grep -q "failed"; then
echo "--- REAL regression ---"
echo "$retry" | grep -E "^ FAIL" | head -30
echo "$retry" | tail -3
exit 1
fi
echo "flake: [$files] pass in isolation"
|