1+ import os
2+ from unittest .mock import Mock , patch
13import pytest
24from libcst import parse_statement
35
6+ import mutmut
47from mutmut .__main__ import (
58 CLASS_NAME_SEPARATOR ,
69 get_diff_for_mutant ,
710 orig_function_and_class_names_from_key ,
11+ run_forced_fail_test ,
12+ Config ,
13+ MutmutProgrammaticFailException ,
14+ CatchOutput ,
815)
916from mutmut .trampoline_templates import trampoline_impl , yield_from_trampoline_impl , mangle_function_name
1017from mutmut .file_mutation import create_mutations , mutate_file_contents , is_generator
@@ -448,6 +455,76 @@ def bar():
448455 assert not is_generator (parse_statement (source )) # type: ignore
449456
450457
458+ # Negate the effects of CatchOutput because it does not play nicely with capfd in GitHub Actions
459+ @patch .object (CatchOutput , 'dump_output' )
460+ @patch .object (CatchOutput , 'stop' )
461+ @patch .object (CatchOutput , 'start' )
462+ def test_run_forced_fail_test_with_failing_test (_start , _stop , _dump_output , capfd ):
463+ mutmut .config = _default_mutmut_config ()
464+ runner = _mocked_runner_run_forced_failed (return_value = 1 )
465+
466+ run_forced_fail_test (runner )
467+
468+ out , err = capfd .readouterr ()
469+
470+ print ()
471+ print (f"out: { out } " )
472+ print (f"err: { err } " )
473+ assert 'Running forced fail test' in out
474+ assert 'done' in out
475+ assert os .environ ['MUTANT_UNDER_TEST' ] is ''
476+
477+
478+ # Negate the effects of CatchOutput because it does not play nicely with capfd in GitHub Actions
479+ @patch .object (CatchOutput , 'dump_output' )
480+ @patch .object (CatchOutput , 'stop' )
481+ @patch .object (CatchOutput , 'start' )
482+ def test_run_forced_fail_test_with_mutmut_programmatic_fail_exception (_start , _stop , _dump_output , capfd ):
483+ mutmut .config = _default_mutmut_config ()
484+ runner = _mocked_runner_run_forced_failed (side_effect = MutmutProgrammaticFailException ())
485+
486+ run_forced_fail_test (runner )
487+
488+ out , err = capfd .readouterr ()
489+ assert 'Running forced fail test' in out
490+ assert 'done' in out
491+ assert os .environ ['MUTANT_UNDER_TEST' ] is ''
492+
493+
494+ # Negate the effects of CatchOutput because it does not play nicely with capfd in GitHub Actions
495+ @patch .object (CatchOutput , 'dump_output' )
496+ @patch .object (CatchOutput , 'stop' )
497+ @patch .object (CatchOutput , 'start' )
498+ def test_run_forced_fail_test_with_all_tests_passing (_start , _stop , _dump_output , capfd ):
499+ mutmut .config = _default_mutmut_config ()
500+ runner = _mocked_runner_run_forced_failed (return_value = 0 )
501+
502+ with pytest .raises (SystemExit ) as error :
503+ run_forced_fail_test (runner )
504+
505+ assert error .value .code is 1
506+ out , err = capfd .readouterr ()
507+ assert 'Running forced fail test' in out
508+ assert 'FAILED: Unable to force test failures' in out
509+
510+
511+ def _default_mutmut_config ():
512+ return Config (
513+ do_not_mutate = [],
514+ also_copy = [],
515+ max_stack_depth = - 1 ,
516+ debug = False ,
517+ paths_to_mutate = []
518+ )
519+
520+ def _mocked_runner_run_forced_failed (return_value = None , side_effect = None ):
521+ runner = Mock ()
522+ runner .run_forced_fail = Mock (
523+ return_value = return_value ,
524+ side_effect = side_effect
525+ )
526+ return runner
527+
451528def test_do_not_mutate_top_level_decorators ():
452529 # Modifying top-level decorators could influence all mutations
453530 # because they are executed at import time
@@ -587,4 +664,4 @@ def add(self, *args, **kwargs):
587664 add.__signature__ = _mutmut_signature(xǁAdderǁadd__mutmut_orig)
588665 xǁAdderǁadd__mutmut_orig.__name__ = 'xǁAdderǁadd'
589666
590- print(Adder(1).add(2))"""
667+ print(Adder(1).add(2))"""
0 commit comments