"""CLI tests for CoinHunter V2.""" from __future__ import annotations import io import unittest from unittest.mock import patch from coinhunter import cli class CLITestCase(unittest.TestCase): def test_help_includes_v2_commands(self): parser = cli.build_parser() help_text = parser.format_help() self.assertIn("init", help_text) self.assertIn("account", help_text) self.assertIn("opportunity", help_text) def test_init_dispatches(self): captured = {} with patch.object(cli, "ensure_init_files", return_value={"force": True, "root": "/tmp/ch"}), patch.object( cli, "print_output", side_effect=lambda payload, **kwargs: captured.setdefault("payload", payload) ): result = cli.main(["init", "--force"]) self.assertEqual(result, 0) self.assertTrue(captured["payload"]["force"]) def test_old_command_is_rejected(self): with self.assertRaises(SystemExit): cli.main(["exec", "bal"]) def test_runtime_error_is_rendered_cleanly(self): stderr = io.StringIO() with patch.object(cli, "load_config", side_effect=RuntimeError("boom")), patch("sys.stderr", stderr): result = cli.main(["market", "tickers", "BTCUSDT"]) self.assertEqual(result, 1) self.assertIn("error: boom", stderr.getvalue()) def test_update_dispatches(self): captured = {} with patch.object(cli, "self_update", return_value={"command": "pipx upgrade coinhunter", "returncode": 0}), patch.object( cli, "print_output", side_effect=lambda payload, **kwargs: captured.setdefault("payload", payload) ): result = cli.main(["update"]) self.assertEqual(result, 0) self.assertEqual(captured["payload"]["returncode"], 0)