-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_menu.py
More file actions
249 lines (222 loc) · 10 KB
/
test_menu.py
File metadata and controls
249 lines (222 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
import unittest
from unittest.mock import patch
from io import StringIO
import re
from git_py_stats.menu import interactive_menu
def strip_ansi_codes(text):
"""
Remove ANSI escape codes from text. Necessary because, without this,
capturing sys.stdout would capture the string with the raw ANSI
along with it, causing our assertions to fail.
"""
ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
return ansi_escape.sub("", text)
class TestInteractiveMenu(unittest.TestCase):
"""
Unit test class for testing the interactive_menu function in menu.py.
"""
def setUp(self):
# Mock configurations for testing
self.config_default = {} # Default theme
self.config_legacy = {"menu_theme": "legacy"} # Legacy theme
self.config_none = {"menu_theme": "none"} # Alternate colorless theme alias
# Test cases for default theme
@patch("builtins.input", return_value="1")
@patch("sys.stdout", new_callable=StringIO)
def test_default_theme_option_1(self, mock_stdout, mock_input):
"""
Test the interactive_menu with default theme and user selects option '1'.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "1")
output = strip_ansi_codes(mock_stdout.getvalue())
# Check that the menu contains specific text
self.assertIn("Generate:", output)
self.assertIn("1) Contribution stats (by author)", output)
self.assertIn("press Enter to exit", output)
@patch("builtins.input", return_value="22")
@patch("sys.stdout", new_callable=StringIO)
def test_default_theme_option_22(self, mock_stdout, mock_input):
"""
Test the interactive_menu with default theme and user selects option '22'.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "22")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Suggest:", output)
self.assertIn("22) Code reviewers (based on git history)", output)
@patch("builtins.input", return_value="")
@patch("sys.stdout", new_callable=StringIO)
def test_default_theme_exit(self, mock_stdout, mock_input):
"""
Test the interactive_menu with default theme and user presses Enter to exit.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("press Enter to exit", output)
@patch("builtins.input", return_value="invalid")
@patch("sys.stdout", new_callable=StringIO)
def test_default_theme_invalid_input(self, mock_stdout, mock_input):
"""
Test the interactive_menu with default theme and user enters an invalid option.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "invalid")
# Since interactive_menu doesn't print 'Invalid selection', we don't assert that here.
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
@patch("builtins.input", return_value="3")
@patch("sys.stdout", new_callable=StringIO)
def test_none_theme_option_3(self, mock_stdout, mock_input):
"""
Test the interactive_menu with 'none' theme and user selects option '3'.
"""
choice = interactive_menu(self.config_none)
self.assertEqual(choice, "3")
output = mock_stdout.getvalue()
self.assertNotIn("\033[31m", output)
self.assertNotIn("\033[33m", output)
self.assertNotIn("\033[36m", output)
self.assertIn("\033[1m", output)
@patch("builtins.input", return_value="1")
@patch("sys.stdout", new_callable=StringIO)
def test_none_theme_option_1(self, mock_stdout, mock_input):
"""
Test the interactive_menu with 'none' theme and user selects option '1'.
"""
choice = interactive_menu(self.config_none)
self.assertEqual(choice, "1")
output = mock_stdout.getvalue()
self.assertNotIn("\033[31m", output)
self.assertNotIn("\033[33m", output)
self.assertNotIn("\033[36m", output)
self.assertIn("\033[1m", output)
@patch("builtins.input", return_value="")
@patch("sys.stdout", new_callable=StringIO)
def test_none_theme_exit(self, mock_stdout, mock_input):
"""
Test the interactive_menu with none theme and user presses Enter to exit.
"""
choice = interactive_menu(self.config_none)
self.assertEqual(choice, "")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("press Enter to exit", output)
@patch("builtins.input", return_value="invalid")
@patch("sys.stdout", new_callable=StringIO)
def test_none_theme_invalid_input(self, mock_stdout, mock_input):
"""
Test the interactive_menu with none theme and user enters an invalid option.
"""
choice = interactive_menu(self.config_none)
self.assertEqual(choice, "invalid")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
# Test cases for legacy theme
@patch("builtins.input", return_value="1")
@patch("sys.stdout", new_callable=StringIO)
def test_legacy_theme_option_1(self, mock_stdout, mock_input):
"""
Test the interactive_menu with legacy theme and user selects option '1'.
"""
choice = interactive_menu(self.config_legacy)
self.assertEqual(choice, "1")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
self.assertIn("1) Contribution stats (by author)", output)
@patch("builtins.input", return_value="2")
@patch("sys.stdout", new_callable=StringIO)
def test_legacy_theme_option_2(self, mock_stdout, mock_input):
"""
Test the interactive_menu with legacy theme and user selects option '2'.
"""
choice = interactive_menu(self.config_legacy)
self.assertEqual(choice, "2")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("2) Contribution stats (by author) on a specific branch", output)
@patch("builtins.input", return_value="")
@patch("sys.stdout", new_callable=StringIO)
def test_legacy_theme_exit(self, mock_stdout, mock_input):
"""
Test the interactive_menu with legacy theme and user presses Enter to exit.
"""
choice = interactive_menu(self.config_legacy)
self.assertEqual(choice, "")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("press Enter to exit", output)
@patch("builtins.input", return_value="invalid")
@patch("sys.stdout", new_callable=StringIO)
def test_legacy_theme_invalid_input(self, mock_stdout, mock_input):
"""
Test the interactive_menu with legacy theme and user enters an invalid option.
"""
choice = interactive_menu(self.config_legacy)
self.assertEqual(choice, "invalid")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
# Test cases for handling multiple inputs and edge cases
@patch("builtins.input", side_effect=["1", ""])
@patch("sys.stdout", new_callable=StringIO)
def test_multiple_inputs(self, mock_stdout, mock_input):
"""
Test the interactive_menu with multiple inputs in sequence.
"""
choice1 = interactive_menu(self.config_default)
choice2 = interactive_menu(self.config_default)
self.assertEqual(choice1, "1")
self.assertEqual(choice2, "")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
@patch("builtins.input", return_value=" 5 ")
@patch("sys.stdout", new_callable=StringIO)
def test_input_with_whitespace(self, mock_stdout, mock_input):
"""
Test the interactive_menu with input that includes leading/trailing whitespace.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "5")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("5) My daily status", output)
# Test cases for handling exit commands
@patch("builtins.input", return_value="QUIT")
@patch("sys.stdout", new_callable=StringIO)
def test_input_quit(self, mock_stdout, mock_input):
"""
Test the interactive_menu with input 'QUIT' to simulate exit.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "QUIT")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
@patch("builtins.input", return_value="EXIT")
@patch("sys.stdout", new_callable=StringIO)
def test_input_exit(self, mock_stdout, mock_input):
"""
Test the interactive_menu with input 'EXIT' to simulate exit.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "EXIT")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
@patch("builtins.input", return_value=" ")
@patch("sys.stdout", new_callable=StringIO)
def test_input_only_whitespace(self, mock_stdout, mock_input):
"""
Test the interactive_menu with input that is only whitespace.
"""
choice = interactive_menu(self.config_default)
self.assertEqual(choice, "")
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("press Enter to exit", output)
@patch("builtins.input", side_effect=KeyboardInterrupt)
@patch("sys.stdout", new_callable=StringIO)
def test_keyboard_interrupt(self, mock_stdout, mock_input):
"""
Test the interactive_menu handles KeyboardInterrupt (Ctrl+C).
"""
with self.assertRaises(KeyboardInterrupt):
interactive_menu(self.config_default)
output = strip_ansi_codes(mock_stdout.getvalue())
self.assertIn("Generate:", output)
if __name__ == "__main__":
unittest.main()