<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ida-tui.git/tests/run.py, branch main</title>
<subtitle>tui for headless ida</subtitle>
<id>https://git.sl0p.foo/ida-tui.git/atom/tests/run.py?h=main</id>
<link rel='self' href='https://git.sl0p.foo/ida-tui.git/atom/tests/run.py?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/'/>
<updated>2026-08-07T10:40:14Z</updated>
<entry>
<title>Rebase MISTER EXO's ida-codemode port onto the current tree</title>
<updated>2026-08-07T10:40:14Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-08-07T10:39:54Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=c9208de05d8583b677117fe43c9d3567e89eb2ce'/>
<id>urn:sha1:c9208de05d8583b677117fe43c9d3567e89eb2ce</id>
<content type='text'>
Mechanical part of the port: the 27-file patch was cut against a base ~148
commits behind us, so it did not apply. Resolved 11 conflicts (all of them
diff drift, not semantic clashes) and the three file deletions:

- app.py: the patch re-inserted _do_rename/_do_name_addr/_seek_split etc. as
  "theirs" because our tree moved them to edit_ctl.py/trace_ctl.py. Kept ours
  and applied the real intent (WorkerClient-&gt;CodeModeClient, .call-&gt;.invoke,
  _open_worker_client-&gt;_open_database_client) at their current homes.
- domain.py: kept Head as a NamedTuple -- the patch reverted it to a frozen
  dataclass, which the perf work measured at 2.9us vs 1.9us per row on a
  quarter-million-row walk. Dropped _fetch_output (no download_url under Code
  Mode) and its now-dead urllib/json imports.
- pane.py: the patch's deletion swallowed our zellij support along with the
  worker-reaping block it meant to remove. Kept zellij, removed the reaping.
- test_scenarios.py: the idb_save-&gt;save_database teardown hunk belongs to
  tests/_fixtures.py in our tree; applied it there and kept our pc_num_format
  scenario that the drift landed on.

Three defects in the patch itself, fixed here:

- It made "import idatui" hard-require ida_codemode, so every offline suite
  died at import -- including the pure ones (graph/index/trace) that are the
  house rule for "tests/run.py --fast". The import is now deferred and gated
  on the binding, which is also what lets the port's own contract tests
  inject a fake DatabaseHandle.
- project.stage() inlined an ida_codemode.registry import and treated "library
  not installed" as "someone owns this database", which broke IDA-free project
  staging. Ownership lookup moved to codemode_client.database_owner().
- tests/test_codemode_client.py had no NEEDS_IDA marker, which tests/run.py
  rejects outright.

Offline suite: 301 passed, 0 failed. Against master's 344 the whole delta is
accounted for: -40 worker_client (module deleted), -18 launch sweep checks
(behaviour deliberately removed) +3 guarding that it stays removed, +2 pool
(GUI-save semantics), +13 new codemode_client contract tests.

NOT yet done, and the port is not functional without it: the adapter is
missing five operations our tree grew since the patch's base (flowchart,
op_format, pc_nums, pc_num_format, survey_binary) and its "heads" predates
back-walking and digest/expect.
</content>
</entry>
<entry>
<title>tests: wait for the thing, don't sleep and hope</title>
<updated>2026-08-06T21:25:23Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-08-06T21:25:23Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=9622e957cdd9602a2f2230ed7d4c90b06688a217'/>
<id>urn:sha1:9622e957cdd9602a2f2230ed7d4c90b06688a217</id>
<content type='text'>
test_trace_ui spent 18.8 of its 35.2 seconds in flat pilot.pause() calls placed
to let an async seek land. Two loops were most of it: 6 iterations at 0.5s and
28 at 0.3s, 11.4s of sleeping to check that a step moves the cursor.

They are condition waits now. The questions are unchanged -- does the listing
cursor reach the pc, does the pseudocode cursor follow -- but they cost what
they cost instead of a fixed budget. The second loop settles on something that
does NOT presuppose the answer (the listing cursor arriving, and the trail map
belonging to the loaded function): waiting on 'is this pc mapped' would have
burned the timeout on every unmapped instruction, about half of them, and come
out slower than the sleep it replaced.

35.2s -&gt; 20.9s, 39 checks, stable over repeated runs.

tests/_fixtures.py collects the staging both this suite and test_scenarios need
-- scratch copy, seeded from a golden .i64 nothing writes back to -- which was
private to test_scenarios. Worth saying plainly: on targets/echo the seeding is
worth 0.19s, not the analysis time I assumed when I went looking. It is shared
for the deduplication and for whatever gets pointed at a bigger binary.
</content>
</entry>
<entry>
<title>tests: one front door</title>
<updated>2026-08-06T20:05:03Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-08-06T20:05:03Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=ebff7caaaf348602422f6943e9de01240a79994e'/>
<id>urn:sha1:ebff7caaaf348602422f6943e9de01240a79994e</id>
<content type='text'>
Fourteen test files, each its own __main__, and no way to run them but from
memory -- so in practice you ran the one you were working on and hoped. Worse,
nothing said which files need a licensed IDA and a real worker (minutes) and
which are pure stdlib (milliseconds), so the cheap ones nobody ran either.

tests/run.py runs the lot and prints one table. --fast selects only the suites
that need nothing, which is 257 checks in half a second under any python3 --
that's the one you run between edits.

The classification lives in the test files, not in a table here that would rot
the first time someone adds a test: each declares NEEDS_IDA at module scope and
run.py reads it with ast (it can't import them -- they run their suite at
import). A file without the marker is a hard error rather than a silent guess.
</content>
</entry>
</feed>
