@@ -98,10 +98,158 @@ def test_none_theme_option_3(self, mock_stdout, mock_input):
98
98
choice = interactive_menu (self .config_none )
99
99
self .assertEqual (choice , "3" )
100
100
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 )
105
253
106
254
if __name__ == "__main__" :
107
255
unittest .main ()
0 commit comments