aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_kittygfx.py
diff options
context:
space:
mode:
authorDuncan Ogilvie <mr.exodia.tpodt@gmail.com>2026-08-17 15:21:59 +0200
committerDuncan Ogilvie <mr.exodia.tpodt@gmail.com>2026-08-17 15:21:59 +0200
commit61b93538fe6e03f175b907c19c2d196ecd860782 (patch)
tree822b667f5b1a6ea5b8358e2bc473d0069b0d1402 /tests/test_kittygfx.py
parentdocs: be honest that the triskel fork is unpublished (diff)
downloadida-tui-61b93538fe6e03f175b907c19c2d196ecd860782.tar.gz
ida-tui-61b93538fe6e03f175b907c19c2d196ecd860782.tar.xz
ida-tui-61b93538fe6e03f175b907c19c2d196ecd860782.zip
Add kitty graphics fallback for Windows support
Diffstat (limited to 'tests/test_kittygfx.py')
-rw-r--r--tests/test_kittygfx.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/tests/test_kittygfx.py b/tests/test_kittygfx.py
new file mode 100644
index 0000000..74b6bb7
--- /dev/null
+++ b/tests/test_kittygfx.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+"""Cross-platform checks for the optional kitty-graphics startup splash.
+
+Pure: stdlib only, no terminal, Textual, Code Mode, or IDA.
+"""
+from __future__ import annotations
+
+import builtins
+import os
+import sys
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+NEEDS_IDA = False
+
+from idatui import kittygfx # noqa: E402
+
+PASS = FAIL = 0
+
+
+def check(name, ok, detail=""):
+ global PASS, FAIL
+ if ok:
+ PASS += 1
+ print(f" ok {name}")
+ else:
+ FAIL += 1
+ print(f" FAIL {name} {detail}")
+
+
+def t_no_termios_falls_back():
+ """Native Windows has no termios; the splash must simply use ANSI art."""
+ original_import = builtins.__import__
+
+ def without_termios(name, *args, **kwargs):
+ if name == "termios":
+ raise ModuleNotFoundError("No module named 'termios'")
+ return original_import(name, *args, **kwargs)
+
+ builtins.__import__ = without_termios
+ try:
+ check("missing termios disables graphics", kittygfx._query_tty(0) is False)
+ except Exception as exc: # the original Windows startup crash
+ check("missing termios does not escape", False,
+ f"{type(exc).__name__}: {exc}")
+ finally:
+ builtins.__import__ = original_import
+
+
+def t_probe_failure_is_never_fatal():
+ """Even an unexpected platform/probe error cannot prevent TUI startup."""
+ original_query = kittygfx._query_tty
+ original_stdout = sys.__stdout__
+ original_supported = kittygfx._supported
+ old_env = os.environ.pop("IDATUI_KITTY", None)
+
+ class Tty:
+ def isatty(self):
+ return True
+
+ def broken_query():
+ raise RuntimeError("terminal API failed")
+
+ try:
+ sys.__stdout__ = Tty()
+ kittygfx._query_tty = broken_query
+ kittygfx._supported = None
+ check("probe exception disables graphics", kittygfx.supported() is False)
+ check("failed result is cached", kittygfx.supported() is False)
+ except Exception as exc:
+ check("probe exception does not escape", False,
+ f"{type(exc).__name__}: {exc}")
+ finally:
+ kittygfx._query_tty = original_query
+ kittygfx._supported = original_supported
+ sys.__stdout__ = original_stdout
+ if old_env is not None:
+ os.environ["IDATUI_KITTY"] = old_env
+
+
+def main() -> int:
+ for fn in (t_no_termios_falls_back, t_probe_failure_is_never_fatal):
+ print(f"\n{fn.__name__}")
+ fn()
+ print(f"\n{PASS} passed, {FAIL} failed")
+ return 1 if FAIL else 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())