@@ -98,10 +98,158 @@ def test_none_theme_option_3(self, mock_stdout, mock_input):
9898 choice = interactive_menu (self .config_none )
9999 self .assertEqual (choice , "3" )
100100 output = mock_stdout .getvalue ()
101- self .assertNotIn ("\033 [31m" , output ) # No RED
102- self .assertNotIn ("\033 [33m" , output ) # No YELLOW
103- self .assertNotIn ("\033 [36m" , output ) # No CYAN
104- self .assertIn ("\033 [1m" , output ) # BOLD allowed
101+ self .assertNotIn ("\033 [31m" , output )
102+ self .assertNotIn ("\033 [33m" , output )
103+ self .assertNotIn ("\033 [36m" , output )
104+ self .assertIn ("\033 [1m" , output )
105+
106+ @patch ("builtins.input" , return_value = "22" )
107+ @patch ("sys.stdout" , new_callable = StringIO )
108+ def test_default_theme_option_22 (self , mock_stdout , mock_input ):
109+ """
110+ Test the interactive_menu with default theme and user selects option '22'.
111+ """
112+ choice = interactive_menu (self .config_default )
113+ self .assertEqual (choice , "22" )
114+ output = strip_ansi_codes (mock_stdout .getvalue ())
115+ self .assertIn ("Suggest:" , output )
116+ self .assertIn ("22) Code reviewers (based on git history)" , output )
117+
118+ @patch ("builtins.input" , return_value = "" )
119+ @patch ("sys.stdout" , new_callable = StringIO )
120+ def test_default_theme_exit (self , mock_stdout , mock_input ):
121+ """
122+ Test the interactive_menu with default theme and user presses Enter to exit.
123+ """
124+ choice = interactive_menu (self .config_default )
125+ self .assertEqual (choice , "" )
126+ output = strip_ansi_codes (mock_stdout .getvalue ())
127+ self .assertIn ("press Enter to exit" , output )
128+
129+ @patch ("builtins.input" , return_value = "invalid" )
130+ @patch ("sys.stdout" , new_callable = StringIO )
131+ def test_default_theme_invalid_input (self , mock_stdout , mock_input ):
132+ """
133+ Test the interactive_menu with default theme and user enters an invalid option.
134+ """
135+ choice = interactive_menu (self .config_default )
136+ self .assertEqual (choice , "invalid" )
137+ # Since interactive_menu doesn't print 'Invalid selection', we don't assert that here.
138+ output = strip_ansi_codes (mock_stdout .getvalue ())
139+ self .assertIn ("Generate:" , output )
140+
141+ @patch ("builtins.input" , return_value = "1" )
142+ @patch ("sys.stdout" , new_callable = StringIO )
143+ def test_legacy_theme_option_1 (self , mock_stdout , mock_input ):
144+ """
145+ Test the interactive_menu with legacy theme and user selects option '1'.
146+ """
147+ choice = interactive_menu (self .config_legacy )
148+ self .assertEqual (choice , "1" )
149+ output = strip_ansi_codes (mock_stdout .getvalue ())
150+ self .assertIn ("Generate:" , output )
151+ self .assertIn ("1) Contribution stats (by author)" , output )
152+
153+ @patch ("builtins.input" , return_value = "2" )
154+ @patch ("sys.stdout" , new_callable = StringIO )
155+ def test_legacy_theme_option_2 (self , mock_stdout , mock_input ):
156+ """
157+ Test the interactive_menu with legacy theme and user selects option '2'.
158+ """
159+ choice = interactive_menu (self .config_legacy )
160+ self .assertEqual (choice , "2" )
161+ output = strip_ansi_codes (mock_stdout .getvalue ())
162+ self .assertIn ("2) Contribution stats (by author) on a specific branch" , output )
163+
164+ @patch ("builtins.input" , return_value = "" )
165+ @patch ("sys.stdout" , new_callable = StringIO )
166+ def test_legacy_theme_exit (self , mock_stdout , mock_input ):
167+ """
168+ Test the interactive_menu with legacy theme and user presses Enter to exit.
169+ """
170+ choice = interactive_menu (self .config_legacy )
171+ self .assertEqual (choice , "" )
172+ output = strip_ansi_codes (mock_stdout .getvalue ())
173+ self .assertIn ("press Enter to exit" , output )
174+
175+ @patch ("builtins.input" , return_value = "invalid" )
176+ @patch ("sys.stdout" , new_callable = StringIO )
177+ def test_legacy_theme_invalid_input (self , mock_stdout , mock_input ):
178+ """
179+ Test the interactive_menu with legacy theme and user enters an invalid option.
180+ """
181+ choice = interactive_menu (self .config_legacy )
182+ self .assertEqual (choice , "invalid" )
183+ output = strip_ansi_codes (mock_stdout .getvalue ())
184+ self .assertIn ("Generate:" , output )
185+
186+ @patch ("builtins.input" , side_effect = ["1" , "" ])
187+ @patch ("sys.stdout" , new_callable = StringIO )
188+ def test_multiple_inputs (self , mock_stdout , mock_input ):
189+ """
190+ Test the interactive_menu with multiple inputs in sequence.
191+ """
192+ choice1 = interactive_menu (self .config_default )
193+ choice2 = interactive_menu (self .config_default )
194+ self .assertEqual (choice1 , "1" )
195+ self .assertEqual (choice2 , "" )
196+ output = strip_ansi_codes (mock_stdout .getvalue ())
197+ self .assertIn ("Generate:" , output )
198+
199+ @patch ("builtins.input" , return_value = " 5 " )
200+ @patch ("sys.stdout" , new_callable = StringIO )
201+ def test_input_with_whitespace (self , mock_stdout , mock_input ):
202+ """
203+ Test the interactive_menu with input that includes leading/trailing whitespace.
204+ """
205+ choice = interactive_menu (self .config_default )
206+ self .assertEqual (choice , "5" )
207+ output = strip_ansi_codes (mock_stdout .getvalue ())
208+ self .assertIn ("5) My daily status" , output )
209+
210+ @patch ("builtins.input" , return_value = "QUIT" )
211+ @patch ("sys.stdout" , new_callable = StringIO )
212+ def test_input_quit (self , mock_stdout , mock_input ):
213+ """
214+ Test the interactive_menu with input 'QUIT' to simulate exit.
215+ """
216+ choice = interactive_menu (self .config_default )
217+ self .assertEqual (choice , "QUIT" )
218+ output = strip_ansi_codes (mock_stdout .getvalue ())
219+ self .assertIn ("Generate:" , output )
220+
221+ @patch ("builtins.input" , return_value = "EXIT" )
222+ @patch ("sys.stdout" , new_callable = StringIO )
223+ def test_input_exit (self , mock_stdout , mock_input ):
224+ """
225+ Test the interactive_menu with input 'EXIT' to simulate exit.
226+ """
227+ choice = interactive_menu (self .config_default )
228+ self .assertEqual (choice , "EXIT" )
229+ output = strip_ansi_codes (mock_stdout .getvalue ())
230+ self .assertIn ("Generate:" , output )
231+
232+ @patch ("builtins.input" , return_value = " " )
233+ @patch ("sys.stdout" , new_callable = StringIO )
234+ def test_input_only_whitespace (self , mock_stdout , mock_input ):
235+ """
236+ Test the interactive_menu with input that is only whitespace.
237+ """
238+ choice = interactive_menu (self .config_default )
239+ self .assertEqual (choice , "" )
240+ output = strip_ansi_codes (mock_stdout .getvalue ())
241+ self .assertIn ("press Enter to exit" , output )
242+
243+ @patch ("builtins.input" , side_effect = KeyboardInterrupt )
244+ @patch ("sys.stdout" , new_callable = StringIO )
245+ def test_keyboard_interrupt (self , mock_stdout , mock_input ):
246+ """
247+ Test the interactive_menu handles KeyboardInterrupt (Ctrl+C).
248+ """
249+ with self .assertRaises (KeyboardInterrupt ):
250+ interactive_menu (self .config_default )
251+ output = strip_ansi_codes (mock_stdout .getvalue ())
252+ self .assertIn ("Generate:" , output )
105253
106254if __name__ == "__main__" :
107255 unittest .main ()
0 commit comments