diff options
| author | Duncan Ogilvie <mr.exodia.tpodt@gmail.com> | 2026-08-17 15:22:09 +0200 |
|---|---|---|
| committer | Duncan Ogilvie <mr.exodia.tpodt@gmail.com> | 2026-08-17 15:22:09 +0200 |
| commit | 10142605e0137fc27b542646c884d2587c6dcf12 (patch) | |
| tree | 20fb76771b9687b2bc977a1dac9e6be191790ec4 /tests/test_scenarios.py | |
| parent | Add kitty graphics fallback for Windows support (diff) | |
| download | ida-tui-10142605e0137fc27b542646c884d2587c6dcf12.tar.gz ida-tui-10142605e0137fc27b542646c884d2587c6dcf12.tar.xz ida-tui-10142605e0137fc27b542646c884d2587c6dcf12.zip | |
Add Ctrl+R to refresh all views
Diffstat (limited to 'tests/test_scenarios.py')
| -rw-r--r-- | tests/test_scenarios.py | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py index c08dc96..2acb5ba 100644 --- a/tests/test_scenarios.py +++ b/tests/test_scenarios.py @@ -935,7 +935,8 @@ async def s_help(c: Ctx): c.check("each key group gets its own card", titles == {t for t, _ in _HELP}, f"{titles}") c.check("it documents real bindings", - "set type" in txt and "split view" in txt and "cross-references" in txt) + "set type" in txt and "split view" in txt and "cross-references" in txt + and "refresh the current view" in txt) c.check("the graph keys are documented", "control-flow graph" in txt and "minimap" in txt) body = app.screen.query_one("#help-body") @@ -1048,6 +1049,45 @@ async def s_view_modes_all_handled(c: Ctx): await c.open(fn.addr, "listing") +@scenario("refresh_view") +async def s_refresh_view(c: Ctx): + """Ctrl+R replaces stale backing data without moving the listing.""" + fn = await c.open_biggest("listing") + await c.press("down", "down", "down") + lst = c.lst + old_model = lst.model + old_ea = lst._cursor_ea() + old_top = round(lst.scroll_offset.y) + old_head = old_model.get(old_top) if old_model is not None else None + old_top_ea = getattr(old_head, "ea", None) + + await c.press("ctrl+r") + landed = await c.wait( + lambda: lst.model is not old_model and lst._cursor_ea() == old_ea, 25) + c.check("Ctrl+R rebuilds the listing model", lst.model is not old_model) + c.check("Ctrl+R preserves the cursor address", landed, + f"got={lst._cursor_ea()} want={old_ea}") + new_top = round(lst.scroll_offset.y) + new_head = lst.model.get(new_top) if lst.model is not None else None + c.check("Ctrl+R preserves the viewport by address", + getattr(new_head, "ea", None) == old_top_ea, + f"got={getattr(new_head, 'ea', None)} want={old_top_ea}") + + await c.open(fn.addr, "decomp") + dec = c.dec + dec.cursor = min(3, max(len(dec._texts) - 1, 0)) + old_dec_cursor = dec.cursor + await c.press("ctrl+r") + refreshed = await c.wait( + lambda: c.app.is_decomp and dec.loaded_ea == fn.addr and not dec.loading, + 25) + c.check("Ctrl+R reloads pseudocode without changing views", refreshed, + f"active={c.app._active} loaded={dec.loaded_ea} want={fn.addr:#x}") + c.check("Ctrl+R preserves the pseudocode cursor", + dec.cursor == old_dec_cursor, + f"got={dec.cursor} want={old_dec_cursor}") + + @scenario("split_view") async def s_split_view(c: Ctx): app, lst, dec = c.app, c.lst, c.dec @@ -1792,6 +1832,16 @@ async def s_hex(c: Ctx): c.check("hex shows the actual byte at that address", rb is not None and rb[hx.cursor % 16] == want[0], f"got={rb[hx.cursor % 16] if rb else None} want={want[0]}") + old_va = hx.cursor_va() + block = (old_va - hx.model.start) // hx.model.BLOCK + old_bytes = hx.model._blocks.get(block) + await c.press("ctrl+r") + reloaded = await c.wait( + lambda: hx.model._blocks.get(block) is not None + and hx.model._blocks.get(block) is not old_bytes, 20) + c.check("Ctrl+R refetches the visible hex block", reloaded) + c.check("Ctrl+R preserves the hex cursor", hx.cursor_va() == old_va, + f"got={hx.cursor_va():#x} want={old_va:#x}") await c.press("l") await c.pause(0.1) c.check("hex cursor steps one byte", hx.cursor_va() == code_ea + 1, @@ -3691,6 +3741,15 @@ async def s_graph_open(c: Ctx): for i, a in enumerate(boxes) for b in boxes[i + 1:]) c.check("no two blocks overlap", not overlap) c.check("the status names the graph", "graph" in c.status(), c.status()) + old_fc = gv.fc + old_ea = gv._cursor_ea() + await c.press("ctrl+r") + rebuilt = await c.wait( + lambda: app.is_graph and gv.fc is not None and gv.fc is not old_fc + and gv.lay is not None, 30) + c.check("Ctrl+R rebuilds the graph", rebuilt) + c.check("Ctrl+R preserves the graph cursor", gv._cursor_ea() == old_ea, + f"got={gv._cursor_ea()} want={old_ea}") await c.press("space") await c.wait(lambda: app._active != "graph", 15) c.check("space returns to the listing", app._active == "listing", |
