"""Unit tests for the wizard menus — scripted input, no raw terminal involved.""" from __future__ import annotations import io import sys import unittest from unittest import mock from weekly_activity.wizard import _menu, _option_line class NumberedMenuFallbackTest(unittest.TestCase): """When stdin/stdout are not a TTY the numbered prompt stays as it was.""" def run_numbered(self, answers: list[str], options: list[str], *, cancellable: bool = False): """Run _menu with forced non-TTY stdio and scripted interactive answers.""" fake_stdin, fake_stdout = io.StringIO(), io.StringIO() with ( mock.patch.object(sys, "stdin", fake_stdin), mock.patch.object(sys, "stdout", fake_stdout), mock.patch("builtins.input", side_effect=iter(answers)), ): picked = _menu("Pick one", options, cancellable=cancellable) return picked, fake_stdout.getvalue() def test_returns_zero_based_index_of_chosen_option(self) -> None: picked, output = self.run_numbered(["2"], ["Alpha", "Beta", "Gamma"]) self.assertEqual(picked, 1) self.assertIn("Pick one", output) self.assertIn(" 2) Beta", output) def test_empty_answer_backs_out_of_cancellable_menu(self) -> None: picked, _ = self.run_numbered([""], ["Alpha", "Beta"], cancellable=True) self.assertIsNone(picked) def test_back_number_returns_none(self) -> None: picked, _ = self.run_numbered(["3"], ["Alpha", "Beta"], cancellable=True) self.assertIsNone(picked) def test_invalid_answers_loop_until_valid_one(self) -> None: picked, output = self.run_numbered(["9", "nope", "3"], ["Alpha", "Beta", "Gamma"]) self.assertEqual(picked, 2) self.assertEqual(output.count("Please enter a number between 1 and 3."), 2) class OptionLineRenderingTest(unittest.TestCase): """Selected rows carry the '>' marker and bold codes; others stay plain.""" def test_selected_line_is_bold_and_marked(self) -> None: self.assertEqual(_option_line("Exit", True), "\x1b[1m> Exit\x1b[0m") def test_unselected_line_is_indented_and_plain(self) -> None: self.assertEqual(_option_line("Remove a source", False), " Remove a source") if __name__ == "__main__": unittest.main()