aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 13:54:40 +0200
committerblasty <blasty@local>2026-07-09 13:54:40 +0200
commit8d9644e8c6158af45ce95467c4a0611e8e10fa22 (patch)
treec22c94a1f130308fcc2514a83b01c6f93f6e8f73 /tests
parentfunction-name filter: incremental + highlight + clear (diff)
downloadida-tui-8d9644e8c6158af45ce95467c4a0611e8e10fa22.tar.gz
ida-tui-8d9644e8c6158af45ce95467c4a0611e8e10fa22.tar.xz
ida-tui-8d9644e8c6158af45ce95467c4a0611e8e10fa22.zip
xrefs + follow-under-cursor (disasm & pseudocode)
- Enter follows the reference under the cursor: disasm uses xref_query(from) to find the code target; pseudocode matches a decompiler ref name on the line. Navigates to the containing function at the exact line (address-history push). - x opens an xrefs popup (XrefsScreen modal): xrefs_to the subject under cursor (call target if any, else the current item); Enter jumps to a referencing site, Esc closes. - domain: Program.function_of (mid-addr -> containing func via lookup_funcs), xrefs_from/xrefs_to (xref_query), Xref model, DisasmModel ea->index map for landing on an exact address. - fix: goto to a mid-function address now lands on the right line (was opening it as a bogus function start). - pilot suite 32/32; domain 17/17.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_tui.py42
1 files changed, 40 insertions, 2 deletions
diff --git a/tests/test_tui.py b/tests/test_tui.py
index 2aaf8ff..999d341 100644
--- a/tests/test_tui.py
+++ b/tests/test_tui.py
@@ -12,8 +12,10 @@ import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-from idatui.app import DecompView, DisasmView, FunctionsPanel, IdaTui # noqa: E402
-from textual.widgets import DataTable, Input, Static # noqa: E402
+from idatui.app import ( # noqa: E402
+ DecompView, DisasmView, FunctionsPanel, IdaTui, XrefsScreen,
+)
+from textual.widgets import DataTable, Input, OptionList, Static # noqa: E402
from rich.text import Text # noqa: E402
PASS = FAIL = 0
@@ -227,6 +229,42 @@ async def run(db):
check("Esc on the list clears the filter", table.row_count == full,
f"{table.row_count}/{full}")
+ # Follow (Enter) + back (Esc) + xrefs (x), using a real call site.
+ dis = app.query_one(DisasmView)
+ dis.focus()
+ await pilot.pause(0.1)
+ lines = dis.model.lines(0, 400, prefetch=False)
+ call_idx = next((i for i, ln in enumerate(lines)
+ if ln.text.startswith("call ")), None)
+ if call_idx is None:
+ check("found a call line to exercise follow/xrefs", False, "no call in first 400")
+ else:
+ dis.cursor = call_idx
+ dis.refresh()
+ orig = app._cur.ea
+ depth = len(app._nav)
+ await pilot.press("enter")
+ await wait_until(pilot, lambda: len(app._nav) > depth, timeout=25)
+ check("Enter follows the call into another function",
+ app._cur.ea != orig and len(app._nav) > depth, f"cur={app._cur.ea:#x}")
+ await pilot.press("escape")
+ await pilot.pause(0.2)
+ check("Esc returns from the follow", app._cur.ea == orig, f"cur={app._cur.ea:#x}")
+ dis.cursor = call_idx
+ dis.refresh()
+ await pilot.press("x")
+ opened = await wait_until(
+ pilot, lambda: isinstance(app.screen, XrefsScreen), timeout=25)
+ check("'x' opens the xrefs popup", opened,
+ f"screen={type(app.screen).__name__}")
+ if opened:
+ check("xrefs popup has entries",
+ app.screen.query_one(OptionList).option_count >= 1)
+ await pilot.press("escape")
+ await pilot.pause(0.2)
+ check("Esc closes the xrefs popup",
+ not isinstance(app.screen, XrefsScreen))
+
def main(argv):
db = None