Some research
This commit is contained in:
+133
-1
@@ -1618,7 +1618,10 @@ class InstallOpsTests(unittest.TestCase):
|
||||
def test_status_reports_all_targets(self):
|
||||
with mock.patch.object(tai, "container_engine", return_value=None):
|
||||
report = tai.install_report("status", list(tai.INSTALL_TARGETS), self.config.home, self.store)
|
||||
for label in ("binary:", "bash-hook:", "venv:", "scheduler-service:", "telegram-service:", "container:", "vault:"):
|
||||
for label in (
|
||||
"binary:", "bash-hook:", "zsh-hook:", "fish-hook:", "plexer-hook:", "zsh-plexer-hook:",
|
||||
"fish-plexer-hook:", "venv:", "scheduler-service:", "telegram-service:", "container:", "vault:",
|
||||
):
|
||||
self.assertIn(label, report)
|
||||
self.assertIn("not installed", report)
|
||||
self.assertIn("never touch data", report)
|
||||
@@ -1647,6 +1650,91 @@ class InstallOpsTests(unittest.TestCase):
|
||||
self.assertTrue(os.path.isfile(path + ".bak-tai"))
|
||||
self.assertIn("not present", tai.op_hook("uninstall", self.config.home))
|
||||
|
||||
def test_zsh_hook_install_remove_idempotent(self):
|
||||
path = os.path.join(self.home, ".zshrc")
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
self.assertIn("source ~/.zshrc", tai.op_zsh_hook("install", self.config.home))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn(tai.BASHRC_MARK_BEGIN, content)
|
||||
self.assertIn("command_not_found_handler", content)
|
||||
self.assertNotIn("command_not_found_handle()", content)
|
||||
self.assertIn("already present", tai.op_zsh_hook("install", self.config.home))
|
||||
self.assertIn("removed", tai.op_zsh_hook("uninstall", self.config.home))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
self.assertNotIn(tai.BASHRC_MARK_BEGIN, handle.read())
|
||||
self.assertTrue(os.path.isfile(path + ".bak-tai"))
|
||||
self.assertIn("not present", tai.op_zsh_hook("uninstall", self.config.home))
|
||||
|
||||
def test_fish_hook_install_remove_idempotent(self):
|
||||
path = os.path.join(self.home, ".config", "fish", "config.fish")
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
result = tai.op_fish_hook("install", self.config.home)
|
||||
self.assertIn("installed", result)
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn(tai.BASHRC_MARK_BEGIN, content)
|
||||
self.assertIn("function fish_command_not_found", content)
|
||||
self.assertIn("already present", tai.op_fish_hook("install", self.config.home))
|
||||
self.assertIn("removed", tai.op_fish_hook("uninstall", self.config.home))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
self.assertNotIn(tai.BASHRC_MARK_BEGIN, handle.read())
|
||||
self.assertTrue(os.path.isfile(path + ".bak-tai"))
|
||||
|
||||
def test_shell_hook_skips_loudly_when_shell_missing(self):
|
||||
with mock.patch.object(tai, "shell_present", return_value=False):
|
||||
self.assertEqual(tai.op_zsh_hook("install", self.config.home), "zsh-hook: zsh not found, skipped")
|
||||
self.assertEqual(tai.op_fish_hook("upgrade", self.config.home), "fish-hook: fish not found, skipped")
|
||||
self.assertEqual(
|
||||
tai.op_zsh_plexer_hook("install", self.config.home), "zsh-plexer-hook: zsh not found, skipped",
|
||||
)
|
||||
self.assertEqual(
|
||||
tai.op_fish_plexer_hook("install", self.config.home), "fish-plexer-hook: fish not found, skipped",
|
||||
)
|
||||
self.assertFalse(os.path.exists(os.path.join(self.home, ".zshrc")))
|
||||
self.assertFalse(os.path.exists(os.path.join(self.home, ".config", "fish", "config.fish")))
|
||||
|
||||
def test_shell_hook_uninstall_cleans_up_even_if_shell_missing_now(self):
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
tai.op_zsh_hook("install", self.config.home)
|
||||
with mock.patch.object(tai, "shell_present", return_value=False):
|
||||
self.assertIn("removed", tai.op_zsh_hook("uninstall", self.config.home))
|
||||
|
||||
def test_zsh_plexer_hook_reuses_bash_syntax_different_file(self):
|
||||
bash_path = os.path.join(self.home, ".bashrc")
|
||||
zsh_path = os.path.join(self.home, ".zshrc")
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
tai.op_plexer_hook("install", self.config.home)
|
||||
tai.op_zsh_plexer_hook("install", self.config.home)
|
||||
with open(bash_path, encoding="utf-8") as handle:
|
||||
bash_content = handle.read()
|
||||
with open(zsh_path, encoding="utf-8") as handle:
|
||||
zsh_content = handle.read()
|
||||
self.assertEqual(bash_content, zsh_content)
|
||||
self.assertIn('case "$-" in', zsh_content)
|
||||
|
||||
def test_fish_plexer_hook_uses_fish_syntax(self):
|
||||
path = os.path.join(self.home, ".config", "fish", "config.fish")
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
self.assertIn("installed", tai.op_fish_plexer_hook("install", self.config.home))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn("status is-interactive", content)
|
||||
self.assertIn("isatty stdin", content)
|
||||
self.assertIn("isatty stdout", content)
|
||||
self.assertIn("exec \"$HOME/.local/bin/tai.py\" --plexer-wrap", content)
|
||||
self.assertNotIn("case \"$-\"", content)
|
||||
self.assertNotIn("[ -z \"$TAI_PLEXER_ACTIVE\" ]", content)
|
||||
|
||||
def test_install_self_detects_current_shell(self):
|
||||
with mock.patch.object(tai, "shell_present", return_value=True):
|
||||
with mock.patch.dict(os.environ, {"SHELL": "/usr/bin/zsh"}):
|
||||
with mock.patch("builtins.print") as shown:
|
||||
tai.install_self()
|
||||
printed = "\n".join(str(call.args[0]) for call in shown.call_args_list)
|
||||
self.assertIn("zsh-hook:", printed)
|
||||
self.assertIn("source ~/.zshrc", printed)
|
||||
|
||||
def test_venv_kept_and_removed(self):
|
||||
folder = tai.venv_dir(self.config.home)
|
||||
python = os.path.join(folder, "bin", "python")
|
||||
@@ -2885,6 +2973,50 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertIn("alias x=y", content)
|
||||
self.assertEqual(content.count(tai.BASHRC_MARK_BEGIN), 1)
|
||||
|
||||
def test_shell_rc_path_bash_zsh(self):
|
||||
with mock.patch.dict(os.environ, {"HOME": "/home/x"}, clear=False):
|
||||
self.assertEqual(tai.shell_rc_path("bash"), "/home/x/.bashrc")
|
||||
self.assertEqual(tai.shell_rc_path("zsh"), "/home/x/.zshrc")
|
||||
|
||||
def test_shell_rc_path_fish_respects_xdg_config_home(self):
|
||||
with mock.patch.dict(os.environ, {"HOME": "/home/x"}, clear=False):
|
||||
os.environ.pop("XDG_CONFIG_HOME", None)
|
||||
self.assertEqual(tai.shell_rc_path("fish"), "/home/x/.config/fish/config.fish")
|
||||
with mock.patch.dict(os.environ, {"XDG_CONFIG_HOME": "/custom/cfg"}):
|
||||
self.assertEqual(tai.shell_rc_path("fish"), "/custom/cfg/fish/config.fish")
|
||||
|
||||
def test_fish_hook_creates_missing_config_directory(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = os.path.join(tmp, "fish", "config.fish")
|
||||
self.assertFalse(os.path.isdir(os.path.dirname(path)))
|
||||
self.assertTrue(tai.upsert_fish_hook_block(path))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn("function fish_command_not_found", content)
|
||||
self.assertFalse(tai.upsert_fish_hook_block(path))
|
||||
|
||||
def test_zsh_fish_hook_roundtrip_preserves_other_content(self):
|
||||
for shell, upsert, remove, present, needle in (
|
||||
("zsh", tai.upsert_zsh_hook_block, tai.remove_zsh_hook_block, tai.zsh_hook_present, "command_not_found_handler"),
|
||||
("fish", tai.upsert_fish_hook_block, tai.remove_fish_hook_block, tai.fish_hook_present, "fish_command_not_found"),
|
||||
):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = os.path.join(tmp, "rc")
|
||||
with open(path, "w", encoding="utf-8") as handle:
|
||||
handle.write("# pre-existing user content\nexport FOO=bar\n")
|
||||
self.assertTrue(upsert(path))
|
||||
self.assertTrue(present(path))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn("export FOO=bar", content)
|
||||
self.assertIn(needle, content)
|
||||
self.assertTrue(remove(path))
|
||||
self.assertFalse(present(path))
|
||||
with open(path, encoding="utf-8") as handle:
|
||||
content = handle.read()
|
||||
self.assertIn("export FOO=bar", content)
|
||||
self.assertNotIn(needle, content, "shell=%s" % shell)
|
||||
|
||||
def test_parser_prompt(self):
|
||||
args = tai.build_parser().parse_args(["what", "is", "(2+3)?"])
|
||||
self.assertEqual(args.prompt, ["what", "is", "(2+3)?"])
|
||||
|
||||
Reference in New Issue
Block a user