"""Tests for the bot CLI (app.bot_cli). The CLI mirrors the Telegram bot's manual-trigger surface (Telegram handlers /1, /2, /3) plus the operational ops (credit, transfer, monitor-once). With no args, it drops into a stdlib TUI menu. These tests mock app.bot_cli.CM_BOT_HAL so they never touch the database or cm99.net. The HAL class is imported at module load (which is a pure import — no env reads), so we can patch the symbol bound on app.bot_cli without affecting other tests. """ import argparse import contextlib import io import os import sys import unittest from unittest import mock import app.bot_cli as bot_cli class ParserSanityTests(unittest.TestCase): def test_build_parser_returns_argument_parser(self): parser = bot_cli.build_parser() self.assertIsInstance(parser, argparse.ArgumentParser) def test_main_with_no_args_dispatches_to_interactive(self): # When invoked with no subcommand, main() should drop into the # TUI loop. We verify the dispatch by patching cmd_interactive to # a no-op recorder. with mock.patch.object(bot_cli, "cmd_interactive", return_value=0) as mocked: rc = bot_cli.main([]) mocked.assert_called_once() self.assertEqual(rc, 0) if __name__ == "__main__": unittest.main()