diff options
| -rw-r--r-- | idatui/app.py | 5 | ||||
| -rw-r--r-- | tests/test_project_ui.py | 23 |
2 files changed, 27 insertions, 1 deletions
diff --git a/idatui/app.py b/idatui/app.py index f589cea..c3578da 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -2120,7 +2120,10 @@ class SymbolPalette(ModalScreen): for h in hits: at = h.text.lower().find(q) scored.append((at if at >= 0 else 1 << 30, len(h.text), h.text, h)) - scored.sort() + # Sort on an explicit key: the same symbol name in two binaries ties + # on (position, length, text), and a bare sort() would then fall + # through to comparing Hit objects, which aren't orderable. + scored.sort(key=lambda t: (t[0], t[1], t[2], t[3].binary, t[3].addr)) rows = [(h.binary, h.addr, h.text, tuple(range(at, at + len(q))) if at < (1 << 30) else ()) for at, _, _, h in scored[:self.LIMIT]] diff --git a/tests/test_project_ui.py b/tests/test_project_ui.py index 025107d..8a0fd2b 100644 --- a/tests/test_project_ui.py +++ b/tests/test_project_ui.py @@ -138,6 +138,29 @@ async def run(bins): again and app._cur.ea == where, f"cur={app._cur.ea if app._cur else None} want={where}") + # -- project-wide symbol search ------------------------------- # + # 'main' exists in BOTH binaries: identical name, so the rank tuple + # ties and a bare sort() would fall through to comparing Hit objects + # ('<' not supported between instances of 'Hit'). + from idatui.app import SymbolPalette + await settle(lambda: app._index is not None + and len(app._index.counts()) == 2, 60) + check("both binaries got indexed", + len(app._index.counts()) == 2, f"{app._index.counts()}") + await pilot.press("ctrl+n") + if await settle(lambda: isinstance(app.screen, SymbolPalette), 20): + pal = app.screen + pal.query_one(Input).value = "main" + await pilot.pause(0.3) + await pilot.press("f2") # widen to the whole project + await pilot.pause(0.4) + names = [(b, n) for b, _, n in pal._results] + check("project scope finds a name shared by both binaries", + len({b for b, n in names if n == "main"}) == 2, + f"{names[:6]}") + await pilot.press("escape") + await pilot.pause(0.2) + # -- the promise: nothing was written next to the sources ---------- # left = sorted(os.listdir(src)) check("the source tree stays pristine (no .i64/scratch beside it)", |
