def test_multiple_mutations(original, expected): mutations = list_mutations(Context(source=original)) assert len(mutations) == 3 assert mutate(Context(source=original, mutation_id=mutations[0])) == (expected[0], 1) assert mutate(Context(source=original, mutation_id=mutations[1])) == (expected[1], 1)
def test_context_exclude_line(): context = Context( source="__import__('pkg_resources').declare_namespace(__name__)\n") assert context.exclude_line() is True context = Context(source="__all__ = ['hi']\n") assert context.exclude_line() is True
def test_mutate_both(): source = 'a = b + c' mutations = list_mutations(Context(source=source)) assert len(mutations) == 2 assert mutate(Context(source=source, mutation_id=mutations[0])) == ('a = b - c', 1) assert mutate(Context(source=source, mutation_id=mutations[1])) == ('a = None', 1)
def test_perform_one_indexed_mutation(): assert mutate( Context(source='1+1', mutation_id=MutationID(line='1+1', index=0, line_number=0))) == ('2+1', 1) assert mutate( Context(source='1+1', mutation_id=MutationID('1+1', 1, line_number=0))) == ('1-1', 1) assert mutate( Context(source='1+1', mutation_id=MutationID('1+1', 2, line_number=0))) == ('1+2', 1)
def test_function(): source = "def capitalize(s):\n return s[0].upper() + s[1:] if s else s\n" assert mutate( Context(source=source, mutate_id=(source.split('\n')[1], 0)) ) == ("def capitalize(s):\n return s[1].upper() + s[1:] if s else s\n", 1) assert mutate( Context(source=source, mutate_id=(source.split('\n')[1], 1)) ) == ("def capitalize(s):\n return s[0].upper() - s[1:] if s else s\n", 1) assert mutate( Context(source=source, mutate_id=(source.split('\n')[1], 2)) ) == ("def capitalize(s):\n return s[0].upper() + s[2:] if s else s\n", 1)
def do_apply(mutation_pk, dict_synonyms, backup): """Apply a specified mutant to the source code :param mutation_pk: mutmut cache primary key of the mutant to apply :type mutation_pk: str :param dict_synonyms: list of synonym keywords for a python dictionary :type dict_synonyms: list[str] :param backup: if :obj:`True` create a backup of the source file before applying the mutation :type backup: bool """ filename, mutation_id = filename_and_mutation_id_from_pk(int(mutation_pk)) context = Context( mutation_id=mutation_id, filename=filename, dict_synonyms=dict_synonyms, ) mutate_file( backup=backup, context=context, ) if context.number_of_performed_mutations == 0: raise RuntimeError( 'No mutations performed. Are you sure the index is not too big?')
def get_unified_diff(argument, dict_synonyms, update_cache=True, source=None): filename, mutation_id = filename_and_mutation_id_from_pk(argument) if update_cache: update_line_numbers(filename) if source is None: with open(filename) as f: source = f.read() context = Context( source=source, filename=filename, mutation_id=mutation_id, dict_synonyms=dict_synonyms, ) mutated_source, number_of_mutations_performed = mutate(context) if not number_of_mutations_performed: return "" output = "" for line in unified_diff(source.split('\n'), mutated_source.split('\n'), fromfile=filename, tofile=filename, lineterm=''): output += line + "\n" return output
def test_mutate_body_of_function_with_return_type_annotation(): source = """ def foo() -> int: return 0 """ assert mutate(Context(source=source, mutation_id=ALL))[0] == source.replace('0', '1')
def do_apply(mutation_pk, dict_synonyms, backup): """Apply a specified mutant to the source code :param mutation_pk: mutmut cache primary key of the mutant to apply :type mutation_pk: str :param dict_synonyms: list of synonym keywords for a python dictionary :type dict_synonyms: list[str] :param backup: if :obj:`True` create a backup of the source file before applying the mutation :type backup: bool """ filename, mutation_id = filename_and_mutation_id_from_pk(int(mutation_pk)) update_line_numbers(filename) context = Context( mutation_id=mutation_id, filename=filename, dict_synonyms=dict_synonyms, ) mutate_file( backup=backup, context=context, )
def test_mutate_dict2(): source = "dict(a=b, c=d, e=f, g=h)" assert mutate( Context(source=source, mutation_id=MutationID( source, 3, line_number=0))) == ("dict(a=b, c=d, e=f, gXX=h)", 1)
def test_basic_mutations(original, expected): actual, number_of_performed_mutations = mutate( Context(source=original, mutation_id=ALL, dict_synonyms=['Struct', 'FooBarDict'])) assert actual == expected, 'Performed {} mutations for original "{}"'.format( number_of_performed_mutations, original)
def test_mutate_dict(): source = "dict(a=b, c=d)" assert mutate( Context(source=source, mutation_id=MutationID(source, 1, line_number=0))) == ("dict(a=b, cXX=d)", 1)
def run_mutation(config, filename, mutation_id): """ :type config: Config :type filename: str :type mutation_id: MutationID :return: (computed or cached) status of the tested mutant :rtype: str """ context = Context( mutation_id=mutation_id, filename=filename, exclude=config.exclude_callback, dict_synonyms=config.dict_synonyms, config=config, ) cached_status = cached_mutation_status(filename, mutation_id, config.hash_of_tests) if cached_status == BAD_SURVIVED: config.surviving_mutants += 1 elif cached_status == BAD_TIMEOUT: config.surviving_mutants_timeout += 1 elif cached_status == OK_KILLED: config.killed_mutants += 1 elif cached_status == OK_SUSPICIOUS: config.suspicious_mutants += 1 else: assert cached_status == UNTESTED, cached_status config.print_progress() if cached_status != UNTESTED: return cached_status try: number_of_mutations_performed = mutate_file(backup=True, context=context) assert number_of_mutations_performed start = time() try: survived = tests_pass(config) except TimeoutError: context.config.surviving_mutants_timeout += 1 return BAD_TIMEOUT time_elapsed = time() - start if time_elapsed > config.test_time_base + ( config.baseline_time_elapsed * config.test_time_multipler): config.suspicious_mutants += 1 return OK_SUSPICIOUS if survived: context.config.surviving_mutants += 1 return BAD_SURVIVED else: context.config.killed_mutants += 1 return OK_KILLED finally: move(filename + '.bak', filename)
def test_multiline_dunder_whitelist(): source = """ __all__ = [ 1, 2, ] """ assert mutate(Context(source=source)) == (source, 0)
def test_bug_github_issue_18(): source = """@register.simple_tag(name='icon') def icon(name): if name is None: return '' tpl = '<span class="glyphicon glyphicon-{}"></span>' return format_html(tpl, name)""" mutate(Context(source=source))
def test_function_with_annotation(): source = "def capitalize(s : str):\n return s[0].upper() + s[1:] if s else s\n" assert mutate( Context(source=source, mutation_id=MutationID(source.split('\n')[1], 0, line_number=1)) ) == ( "def capitalize(s : str):\n return s[1].upper() + s[1:] if s else s\n", 1)
def test_simple_apply(): CliRunner().invoke(main, [ 'foo.py', '--apply', '--mutation', mutation_id_separator.join([file_to_mutate_lines[0], '0']) ]) with open('foo.py') as f: assert f.read() == mutate( Context(source=file_to_mutate_contents, mutate_id=(file_to_mutate_lines[0], 0)))[0]
def test_performed_mutation_ids(): source = "dict(a=b, c=d)" context = Context(source=source) mutate(context) # we found two mutation points: mutate "a" and "c" assert context.performed_mutation_ids == [ MutationID(source, 0, 0), MutationID(source, 1, 0) ]
def test_bug_github_issue_162(): source = """ primes: List[int] = [] foo = 'bar' """ assert mutate( Context(source=source, mutation_id=RelativeMutationID("foo = 'bar'", 0, 2))) == (source.replace( "'bar'", "'XXbarXX'"), 1)
def test_function(): source = "def capitalize(s):\n return s[0].upper() + s[1:] if s else s\n" assert mutate( Context(source=source, mutation_id=RelativeMutationID(source.split('\n')[1], 0, line_number=1)) ) == ("def capitalize(s):\n return s[1].upper() + s[1:] if s else s\n", 1) assert mutate( Context(source=source, mutation_id=RelativeMutationID(source.split('\n')[1], 1, line_number=1)) ) == ("def capitalize(s):\n return s[0].upper() - s[1:] if s else s\n", 1) assert mutate( Context(source=source, mutation_id=RelativeMutationID(source.split('\n')[1], 2, line_number=1)) ) == ("def capitalize(s):\n return s[0].upper() + s[2:] if s else s\n", 1)
def run_mutation(config: Config, filename: str, mutation_id: MutationID, callback) -> str: """ :return: (computed or cached) status of the tested mutant, one of mutant_statuses """ context = Context( mutation_id=mutation_id, filename=filename, dict_synonyms=config.dict_synonyms, config=config, ) cached_status = cached_mutation_status(filename, mutation_id, config.hash_of_tests) if cached_status != UNTESTED: return cached_status if config.pre_mutation: result = subprocess.check_output(config.pre_mutation, shell=True).decode().strip() if result and not config.swallow_output: print(result) try: mutate_file(backup=True, context=context) start = time() try: survived = tests_pass(config=config, callback=callback) except TimeoutError: return BAD_TIMEOUT time_elapsed = time() - start if not survived and time_elapsed > config.test_time_base + ( config.baseline_time_elapsed * config.test_time_multipler): return OK_SUSPICIOUS if survived: return BAD_SURVIVED else: return OK_KILLED finally: move(filename + '.bak', filename) if config.post_mutation: result = subprocess.check_output(config.post_mutation, shell=True).decode().strip() if result and not config.swallow_output: print(result)
def add_mutations_by_file(mutations_by_file, filename, dict_synonyms, config): """ :type mutations_by_file: dict[str, list[MutationID]] :type filename: str :type exclude: Callable[[Context], bool] :type dict_synonyms: list[str] """ with open(filename) as f: source = f.read() context = Context( source=source, filename=filename, config=config, dict_synonyms=dict_synonyms, ) try: mutations_by_file[filename] = list_mutations(context) register_mutants(mutations_by_file) except Exception as e: raise RuntimeError('Failed while creating mutations for {}, for line "{}"'.format(context.filename, context.current_source_line)) from e
def test_bug_github_issue_77(): # Don't crash on this Context(source='')
def test_bug_github_issue_30(): source = """ def from_checker(cls: Type['BaseVisitor'], checker) -> 'BaseVisitor': pass """ assert mutate(Context(source=source)) == (source, 0)
def test_bug_github_issue_26(): source = """ class ConfigurationOptions(Protocol): min_name_length: int """ mutate(Context(source=source))
def test_bug_github_issue_19(): source = """key = lambda a: "foo" filters = dict((key(field), False) for field in fields)""" mutate(Context(source=source))
def test_mutate_all(): assert mutate(Context(source='def foo():\n return 1+1', mutation_id=ALL)) == ('def foo():\n return 2-2', 3)
def test_syntax_error(): with pytest.raises(Exception): mutate(Context(source=':!'))
def test_mutate_decorator(): source = """@foo\ndef foo():\n pass\n""" assert mutate(Context(source=source, mutation_id=ALL)) == (source.replace('@foo', ''), 1)
def test_pragma_no_mutate_and_no_cover(): source = """def foo():\n return 1+1 # pragma: no cover, no mutate\n""" assert mutate(Context(source=source, mutation_id=ALL)) == (source, 0)