Total Complexity | 66 |
Total Lines | 499 |
Duplicated Lines | 0 % |
Complex classes like coalib.tests.output.ConsoleInteractionTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | import os |
||
103 | class ConsoleInteractionTest(unittest.TestCase): |
||
104 | |||
105 | def setUp(self): |
||
106 | self.log_printer = LogPrinter(ConsolePrinter(print_colored=False)) |
||
107 | self.console_printer = ConsolePrinter(print_colored=False) |
||
108 | self.file_diff_dict = {} |
||
109 | self.local_bears = OrderedDict([("default", [SomelocalBear]), |
||
110 | ("test", [SomelocalBear])]) |
||
111 | self.global_bears = OrderedDict([("default", [SomeglobalBear]), |
||
112 | ("test", [SomeglobalBear])]) |
||
113 | |||
114 | self.old_open_editor_applicable = OpenEditorAction.is_applicable |
||
115 | OpenEditorAction.is_applicable = staticmethod(lambda *args: False) |
||
116 | |||
117 | self.old_apply_patch_applicable = ApplyPatchAction.is_applicable |
||
118 | ApplyPatchAction.is_applicable = staticmethod(lambda *args: False) |
||
119 | |||
120 | def tearDown(self): |
||
121 | OpenEditorAction.is_applicable = self.old_open_editor_applicable |
||
122 | ApplyPatchAction.is_applicable = self.old_apply_patch_applicable |
||
123 | |||
124 | def test_require_settings(self): |
||
125 | self.assertRaises(TypeError, acquire_settings, self.log_printer, 0) |
||
126 | self.assertEqual(acquire_settings(self.log_printer, {0: 0}), {}) |
||
127 | |||
128 | with simulate_console_inputs(0, 1, 2) as generator: |
||
129 | self.assertEqual(acquire_settings(self.log_printer, |
||
130 | {"setting": ["help text", |
||
131 | "SomeBear"]}), |
||
132 | {"setting": 0}) |
||
133 | |||
134 | self.assertEqual(acquire_settings(self.log_printer, |
||
135 | {"setting": ["help text", |
||
136 | "SomeBear", |
||
137 | "AnotherBear"]}), |
||
138 | {"setting": 1}) |
||
139 | |||
140 | self.assertEqual(acquire_settings(self.log_printer, |
||
141 | {"setting": ["help text", |
||
142 | "SomeBear", |
||
143 | "AnotherBear", |
||
144 | "YetAnotherBear"]}), |
||
145 | {"setting": 2}) |
||
146 | |||
147 | self.assertEqual(generator.last_input, 2) |
||
148 | |||
149 | def test_print_result(self): |
||
150 | print_result(self.console_printer, |
||
151 | self.log_printer, |
||
152 | None, |
||
153 | self.file_diff_dict, |
||
154 | "illegal value", |
||
155 | {}) |
||
156 | |||
157 | with simulate_console_inputs(0): |
||
158 | print_result(self.console_printer, |
||
159 | self.log_printer, |
||
160 | None, |
||
161 | self.file_diff_dict, |
||
162 | Result("origin", "msg", diffs={}), |
||
163 | {}) |
||
164 | |||
165 | with make_temp() as testfile_path: |
||
166 | file_dict = { |
||
167 | testfile_path: ["1\n", "2\n", "3\n"], |
||
168 | "f_b": ["1", "2", "3"] |
||
169 | } |
||
170 | diff = Diff(file_dict[testfile_path]) |
||
171 | diff.delete_line(2) |
||
172 | diff.change_line(3, "3\n", "3_changed\n") |
||
173 | |||
174 | with simulate_console_inputs(1), self.assertRaises(ValueError): |
||
175 | ApplyPatchAction.is_applicable = staticmethod( |
||
176 | lambda *args: True) |
||
177 | print_result(self.console_printer, |
||
178 | self.log_printer, |
||
179 | None, |
||
180 | self.file_diff_dict, |
||
181 | Result("origin", "msg", diffs={ |
||
182 | testfile_path: diff}), |
||
183 | file_dict) |
||
184 | |||
185 | # Interaction must be closed by the user with `0` if it's not a |
||
186 | # param |
||
187 | with simulate_console_inputs("INVALID", |
||
188 | -1, |
||
189 | 1, |
||
190 | 0, |
||
191 | 3) as input_generator: |
||
192 | curr_section = Section("") |
||
193 | print_section_beginning(self.console_printer, curr_section) |
||
194 | print_result(self.console_printer, |
||
195 | self.log_printer, |
||
196 | curr_section, |
||
197 | self.file_diff_dict, |
||
198 | Result("origin", "msg", diffs={ |
||
199 | testfile_path: diff}), |
||
200 | file_dict) |
||
201 | self.assertEqual(input_generator.last_input, 3) |
||
202 | |||
203 | self.file_diff_dict.clear() |
||
204 | |||
205 | with open(testfile_path) as f: |
||
206 | self.assertEqual(f.readlines(), ["1\n", "3_changed\n"]) |
||
207 | |||
208 | os.remove(testfile_path + ".orig") |
||
209 | |||
210 | name, section = get_action_info(curr_section, |
||
211 | TestAction().get_metadata()) |
||
212 | self.assertEqual(input_generator.last_input, 4) |
||
213 | self.assertEqual(str(section), " {param : '3'}") |
||
214 | self.assertEqual(name, "TestAction") |
||
215 | |||
216 | # Check if the user is asked for the parameter only the first time. |
||
217 | # Use OpenEditorAction that needs this parameter (editor command). |
||
218 | with simulate_console_inputs(1, "test_editor", 0, 1, 0) as generator: |
||
219 | OpenEditorAction.is_applicable = staticmethod(lambda *args: True) |
||
220 | |||
221 | patch_result = Result("origin", "msg", diffs={testfile_path: diff}) |
||
222 | patch_result.file = "f_b" |
||
223 | |||
224 | print_result(self.console_printer, |
||
225 | self.log_printer, |
||
226 | curr_section, |
||
227 | self.file_diff_dict, |
||
228 | patch_result, |
||
229 | file_dict) |
||
230 | # choose action, choose editor, choose no action (-1 -> 2) |
||
231 | self.assertEqual(generator.last_input, 2) |
||
232 | |||
233 | # It shoudn't ask for parameter again |
||
234 | print_result(self.console_printer, |
||
235 | self.log_printer, |
||
236 | curr_section, |
||
237 | self.file_diff_dict, |
||
238 | patch_result, |
||
239 | file_dict) |
||
240 | self.assertEqual(generator.last_input, 4) |
||
241 | |||
242 | def test_print_affected_files(self): |
||
243 | with retrieve_stdout() as stdout, \ |
||
244 | make_temp() as some_file: |
||
245 | file_dict = {some_file: ["1\n", "2\n", "3\n"]} |
||
246 | affected_code = (SourceRange.from_values(some_file),) |
||
247 | print_affected_files(self.console_printer, |
||
248 | self.log_printer, |
||
249 | Section(""), |
||
250 | Result("origin", |
||
251 | "message", |
||
252 | affected_code=affected_code), |
||
253 | file_dict, |
||
254 | color=True) |
||
255 | self.assertEqual(stdout.getvalue(), |
||
256 | "\n"+relpath(some_file)+"\n") |
||
257 | |||
258 | def test_acquire_actions_and_apply(self): |
||
259 | with make_temp() as testfile_path: |
||
260 | file_dict = {testfile_path: ["1\n", "2\n", "3\n"]} |
||
261 | diff = Diff(file_dict[testfile_path]) |
||
262 | diff.delete_line(2) |
||
263 | diff.change_line(3, "3\n", "3_changed\n") |
||
264 | with simulate_console_inputs(1, 0) as generator, \ |
||
265 | retrieve_stdout() as sio: |
||
266 | ApplyPatchAction.is_applicable = staticmethod( |
||
267 | lambda *args: True) |
||
268 | acquire_actions_and_apply(self.console_printer, |
||
269 | self.log_printer, |
||
270 | Section(""), |
||
271 | self.file_diff_dict, |
||
272 | Result("origin", "message", diffs={ |
||
273 | testfile_path: diff}), |
||
274 | file_dict) |
||
275 | self.assertEqual(generator.last_input, 1) |
||
276 | self.assertIn(ApplyPatchAction.success_message, sio.getvalue()) |
||
277 | |||
278 | class InvalidateTestAction(ResultAction): |
||
279 | |||
280 | is_applicable = staticmethod(lambda *args: True) |
||
281 | |||
282 | def apply(*args, **kwargs): |
||
283 | ApplyPatchAction.is_applicable = staticmethod( |
||
284 | lambda *args: False) |
||
285 | |||
286 | old_applypatch_is_applicable = ApplyPatchAction.is_applicable |
||
287 | ApplyPatchAction.is_applicable = staticmethod(lambda *args: True) |
||
288 | cli_actions = [ApplyPatchAction(), InvalidateTestAction()] |
||
289 | |||
290 | with simulate_console_inputs(2, 1, 0) as generator, \ |
||
291 | retrieve_stdout() as sio: |
||
292 | acquire_actions_and_apply(self.console_printer, |
||
293 | self.log_printer, |
||
294 | Section(""), |
||
295 | self.file_diff_dict, |
||
296 | Result("origin", "message", |
||
297 | diffs={testfile_path: diff}), |
||
298 | file_dict, |
||
299 | cli_actions=cli_actions) |
||
300 | self.assertEqual(generator.last_input, 2) |
||
301 | |||
302 | action_fail = "Failed to execute the action" |
||
303 | self.assertNotIn(action_fail, sio.getvalue()) |
||
304 | |||
305 | apply_path_desc = ApplyPatchAction().get_metadata().desc |
||
306 | self.assertEqual(sio.getvalue().count(apply_path_desc), 1) |
||
307 | |||
308 | ApplyPatchAction.is_applicable = old_applypatch_is_applicable |
||
309 | |||
310 | def test_print_result_no_input(self): |
||
311 | with make_temp() as testfile_path: |
||
312 | file_dict = {testfile_path: ["1\n", "2\n", "3\n"]} |
||
313 | diff = Diff(file_dict[testfile_path]) |
||
314 | diff.delete_line(2) |
||
315 | diff.change_line(3, "3\n", "3_changed\n") |
||
316 | with simulate_console_inputs(1, 2, 3) as generator, \ |
||
317 | retrieve_stdout() as stdout: |
||
318 | ApplyPatchAction.is_applicable = staticmethod( |
||
319 | lambda *args: True) |
||
320 | print_results_no_input(self.log_printer, |
||
321 | Section("someSection"), |
||
322 | [Result("origin", "message", diffs={ |
||
323 | testfile_path: diff})], |
||
324 | file_dict, |
||
325 | self.file_diff_dict, |
||
326 | color=False) |
||
327 | self.assertEqual(generator.last_input, -1) |
||
328 | self.assertEqual(stdout.getvalue(), |
||
329 | """ |
||
330 | Project wide: |
||
331 | | | [NORMAL] origin: |
||
332 | | | message |
||
333 | """) |
||
334 | |||
335 | def test_print_section_beginning(self): |
||
336 | with retrieve_stdout() as stdout: |
||
337 | print_section_beginning(self.console_printer, Section("name")) |
||
338 | self.assertEqual(stdout.getvalue(), "Executing section name...\n") |
||
339 | |||
340 | def test_nothing_done(self): |
||
341 | with retrieve_stdout() as stdout: |
||
342 | nothing_done(self.log_printer) |
||
343 | self.assertIn("No existent section was targeted or enabled. " |
||
344 | "Nothing to do.\n", |
||
345 | stdout.getvalue()) |
||
346 | |||
347 | def test_print_results_empty(self): |
||
348 | with retrieve_stdout() as stdout: |
||
349 | print_results(self.log_printer, Section(""), [], {}, {}) |
||
350 | self.assertEqual(stdout.getvalue(), "") |
||
351 | |||
352 | def test_print_results_project_wide(self): |
||
353 | with retrieve_stdout() as stdout: |
||
354 | print_results(self.log_printer, |
||
355 | Section(""), |
||
356 | [Result("origin", "message")], |
||
357 | {}, |
||
358 | {}, |
||
359 | color=False) |
||
360 | self.assertEqual( |
||
361 | "\n{}\n| | [NORMAL] origin:\n| | message" |
||
362 | "\n".format(STR_PROJECT_WIDE), |
||
363 | stdout.getvalue()) |
||
364 | |||
365 | def test_print_results_for_file(self): |
||
366 | with retrieve_stdout() as stdout: |
||
367 | print_results( |
||
368 | self.log_printer, |
||
369 | Section(""), |
||
370 | [Result.from_values("SpaceConsistencyBear", |
||
371 | "Trailing whitespace found", |
||
372 | file="filename", |
||
373 | line=2)], |
||
374 | {abspath("filename"): ["test line\n", "line 2\n", "line 3\n"]}, |
||
375 | {}, |
||
376 | color=False) |
||
377 | self.assertEqual("""\nfilename |
||
378 | | 2| line 2 |
||
379 | | | [NORMAL] SpaceConsistencyBear: |
||
380 | | | Trailing whitespace found |
||
381 | """, |
||
382 | stdout.getvalue()) |
||
383 | |||
384 | with retrieve_stdout() as stdout: |
||
385 | print_results( |
||
386 | self.log_printer, |
||
387 | Section(""), |
||
388 | [Result.from_values("SpaceConsistencyBear", |
||
389 | "Trailing whitespace found", |
||
390 | file="filename", |
||
391 | line=5)], |
||
392 | {abspath("filename"): ["test line\n", |
||
393 | "line 2\n", |
||
394 | "line 3\n", |
||
395 | "line 4\n", |
||
396 | "line 5\n"]}, |
||
397 | {}, |
||
398 | color=False) |
||
399 | self.assertEqual("""\nfilename |
||
400 | | 5| line 5 |
||
401 | | | [NORMAL] SpaceConsistencyBear: |
||
402 | | | Trailing whitespace found |
||
403 | """, |
||
404 | stdout.getvalue()) |
||
405 | |||
406 | def test_print_results_sorting(self): |
||
407 | with retrieve_stdout() as stdout: |
||
408 | print_results(self.log_printer, |
||
409 | Section(""), |
||
410 | [Result.from_values("SpaceConsistencyBear", |
||
411 | "Trailing whitespace found", |
||
412 | file="file", |
||
413 | line=5), |
||
414 | Result.from_values("SpaceConsistencyBear", |
||
415 | "Trailing whitespace found", |
||
416 | file="file", |
||
417 | line=2)], |
||
418 | {abspath("file"): ["test line\n", |
||
419 | "line 2\n", |
||
420 | "line 3\n", |
||
421 | "line 4\n", |
||
422 | "line 5\n"]}, |
||
423 | {}, |
||
424 | color=False) |
||
425 | |||
426 | self.assertEqual(""" |
||
427 | file |
||
428 | | 2| line 2 |
||
429 | | | [NORMAL] SpaceConsistencyBear: |
||
430 | | | Trailing whitespace found |
||
431 | |||
432 | file |
||
433 | | 5| line 5 |
||
434 | | | [NORMAL] SpaceConsistencyBear: |
||
435 | | | Trailing whitespace found |
||
436 | """, |
||
437 | stdout.getvalue()) |
||
438 | |||
439 | def test_print_results_multiple_ranges(self): |
||
440 | affected_code = ( |
||
441 | SourceRange.from_values("some_file", 5, end_line=7), |
||
442 | SourceRange.from_values("another_file", 1, 3, 1, 5), |
||
443 | SourceRange.from_values("another_file", 3, 3, 3, 5)) |
||
444 | with retrieve_stdout() as stdout: |
||
445 | print_results( |
||
446 | self.log_printer, |
||
447 | Section(""), |
||
448 | [Result("ClangCloneDetectionBear", |
||
449 | "Clone Found", |
||
450 | affected_code)], |
||
451 | {abspath("some_file"): ["line " + str(i + 1) + "\n" |
||
452 | for i in range(10)], |
||
453 | abspath("another_file"): ["line " + str(i + 1) + "\n" |
||
454 | for i in range(10)]}, |
||
455 | {}, |
||
456 | color=False) |
||
457 | self.assertEqual(""" |
||
458 | another_file |
||
459 | | 1| line 1 |
||
460 | |||
461 | another_file |
||
462 | | 3| line 3 |
||
463 | |||
464 | some_file |
||
465 | | 5| line 5 |
||
466 | | 6| line 6 |
||
467 | | 7| line 7 |
||
468 | | | [NORMAL] ClangCloneDetectionBear: |
||
469 | | | Clone Found |
||
470 | """, |
||
471 | stdout.getvalue()) |
||
472 | |||
473 | def test_print_results_missing_file(self): |
||
474 | self.log_printer = LogPrinter(NullPrinter()) |
||
475 | with retrieve_stdout() as stdout: |
||
476 | print_results( |
||
477 | self.log_printer, |
||
478 | Section(""), |
||
479 | [Result("t", "msg"), |
||
480 | Result.from_values("t", "msg", file="file", line=5)], |
||
481 | {}, |
||
482 | {}, |
||
483 | color=False) |
||
484 | self.assertEqual("\n" + STR_PROJECT_WIDE + "\n" |
||
485 | "| | [NORMAL] t:\n" |
||
486 | "| | msg\n" |
||
487 | # Second results file isn't there, no context is |
||
488 | # printed, only a warning log message which we |
||
489 | # don't catch |
||
490 | "| | [NORMAL] t:\n" |
||
491 | "| | msg\n", stdout.getvalue()) |
||
492 | |||
493 | def test_print_results_missing_line(self): |
||
494 | with retrieve_stdout() as stdout: |
||
495 | print_results( |
||
496 | self.log_printer, |
||
497 | Section(""), |
||
498 | [Result.from_values("t", "msg", file="file", line=5), |
||
499 | Result.from_values("t", "msg", file="file", line=6)], |
||
500 | {abspath("file"): ["line " + str(i + 1) for i in range(5)]}, |
||
501 | {}, |
||
502 | color=False) |
||
503 | self.assertEqual("\n" |
||
504 | "file\n" |
||
505 | "| 5| line 5\n" |
||
506 | "| | [NORMAL] t:\n" |
||
507 | "| | msg\n" |
||
508 | "\n" |
||
509 | "file\n" |
||
510 | "| | {}\n" |
||
511 | "| | [NORMAL] t:\n" |
||
512 | "| | msg\n".format(STR_LINE_DOESNT_EXIST), |
||
513 | stdout.getvalue()) |
||
514 | |||
515 | def test_print_results_without_line(self): |
||
516 | with retrieve_stdout() as stdout: |
||
517 | print_results( |
||
518 | self.log_printer, |
||
519 | Section(""), |
||
520 | [Result.from_values("t", "msg", file="file")], |
||
521 | {abspath("file"): []}, |
||
522 | {}, |
||
523 | color=False) |
||
524 | self.assertEqual( |
||
525 | "\nfile\n" |
||
526 | "| | [NORMAL] t:\n" |
||
527 | "| | msg\n", |
||
528 | stdout.getvalue()) |
||
529 | |||
530 | def test_print_bears_empty(self): |
||
531 | with retrieve_stdout() as stdout: |
||
532 | bears = {} |
||
533 | print_bears(self.log_printer.printer, bears, True) |
||
534 | self.assertEqual("No bears to show.\n", stdout.getvalue()) |
||
535 | with retrieve_stdout() as stdout: |
||
536 | bears = {} |
||
537 | print_bears(self.log_printer.printer, bears, False) |
||
538 | self.assertEqual("No bears to show.\n", stdout.getvalue()) |
||
539 | |||
540 | def test_print_bears(self): |
||
541 | with retrieve_stdout() as stdout: |
||
542 | bears = {TestBear: ["default", "docs"]} |
||
543 | print_bears(self.log_printer.printer, bears, False) |
||
544 | expected_string = "TestBear:\n" |
||
545 | expected_string += " Test bear Description.\n\n" |
||
546 | expected_string += " Used in:\n" |
||
547 | expected_string += " * default\n" |
||
548 | expected_string += " * docs\n\n" |
||
549 | expected_string += " Needed Settings:\n" |
||
550 | expected_string += " * setting1: Required Setting.\n\n" |
||
551 | expected_string += " Optional Settings:\n" |
||
552 | expected_string += " * setting2: Optional Setting. (" |
||
553 | expected_string += "Optional, defaults to 'None'." |
||
554 | expected_string += ")\n\n" |
||
555 | |||
556 | self.assertEqual(expected_string, stdout.getvalue()) |
||
557 | |||
558 | def test_print_bears_no_settings(self): |
||
559 | with retrieve_stdout() as stdout: |
||
560 | bears = {SomeBear: ["default"]} |
||
561 | print_bears(self.log_printer.printer, bears, False) |
||
562 | expected_string = "SomeBear:\n" |
||
563 | expected_string += " Some Description.\n\n" |
||
564 | expected_string += " Used in:\n" |
||
565 | expected_string += " * default\n\n" |
||
566 | expected_string += " No needed settings.\n\n" |
||
567 | expected_string += " No optional settings.\n\n" |
||
568 | |||
569 | self.assertEqual(expected_string, stdout.getvalue()) |
||
570 | |||
571 | def test_print_bears_no_needed_settings(self): |
||
572 | with retrieve_stdout() as stdout: |
||
573 | bears = {SomeOtherBear: ["test"]} |
||
574 | print_bears(self.log_printer.printer, bears, False) |
||
575 | expected_string = "SomeOtherBear:\n" |
||
576 | expected_string += " This is a Bear.\n\n" |
||
577 | expected_string += " Used in:\n" |
||
578 | expected_string += " * test\n\n" |
||
579 | expected_string += " No needed settings.\n\n" |
||
580 | expected_string += " Optional Settings:\n" |
||
581 | expected_string += " * setting: This is an optional setting. (" |
||
582 | expected_string += "Optional, defaults to 'None'." |
||
583 | expected_string += ")\n\n" |
||
584 | |||
585 | self.assertEqual(expected_string, stdout.getvalue()) |
||
586 | |||
587 | def test_print_bears_no_optional_settings(self): |
||
588 | with retrieve_stdout() as stdout: |
||
589 | bears = {TestBear2: ["test"]} |
||
590 | print_bears(self.log_printer.printer, bears, False) |
||
591 | expected_string = "TestBear2:\n" |
||
592 | expected_string += " Test bear 2 description.\n\n" |
||
593 | expected_string += " Used in:\n" |
||
594 | expected_string += " * test\n\n" |
||
595 | expected_string += " Needed Settings:\n" |
||
596 | expected_string += " * setting1: Required Setting.\n\n" |
||
597 | expected_string += " No optional settings.\n\n" |
||
598 | |||
599 | self.assertEqual(expected_string, stdout.getvalue()) |
||
600 | |||
601 | def test_print_bears_no_sections(self): |
||
602 | with retrieve_stdout() as stdout: |
||
703 |