Ejemplo n.º 1
0
def get_unified_diff(argument, dict_synonyms):
    filename, mutation_id = filename_and_mutation_id_from_pk(argument)
    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
Ejemplo n.º 2
0
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,
    )
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
def test_mutate_dict():
    source = "dict(a=b, c=d)"
    assert mutate(Context(source=source,
                          mutate_id=(source, 1))) == ("dict(a=b, cXX=d)", 1)
Ejemplo n.º 5
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 == [(source, 0), (source, 1)]
Ejemplo n.º 6
0
def test_bug_github_issue_30():
    source = """
def from_checker(cls: Type['BaseVisitor'], checker) -> 'BaseVisitor':
    pass
"""
    assert mutate(Context(source=source)) == (source, 0)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
def test_mutate_decorator():
    source = """@foo\ndef foo():\n    pass\n"""
    assert mutate(Context(source=source,
                          mutation_id=ALL)) == (source.replace('@foo', ''), 1)
Ejemplo n.º 9
0
def test_bug_github_issue_19():
    source = """key = lambda a: "foo"
filters = dict((key(field), False) for field in fields)"""
    mutate(Context(source=source))
Ejemplo n.º 10
0
def test_basic_mutations_python36(original, expected):
    actual = mutate(
        Context(source=original,
                mutation_id=ALL,
                dict_synonyms=['Struct', 'FooBarDict']))[0]
    assert actual == expected
Ejemplo n.º 11
0
def test_mutate_all():
    assert mutate(Context(source='def foo():\n    return 1+1',
                          mutation_id=ALL)) == ('def foo():\n    return 2-2',
                                                3)
Ejemplo n.º 12
0
def test_context_exclude_line():
    source = "__import__('pkg_resources').declare_namespace(__name__)\n"
    assert mutate(Context(source=source)) == (source, 0)

    source = "__all__ = ['hi']\n"
    assert mutate(Context(source=source)) == (source, 0)
Ejemplo n.º 13
0
def test_count_available_mutations():
    assert count_mutations(Context(source='def foo():\n    return 1+1')) == 3
def killed_mutants_raw(module_under_test_path,
                       project_root,
                       not_failing_node_ids,
                       timeout=None,
                       cache_key=None):
    logger.debug(
        "Killed mutants of project {proj} will be saved in folder {f}",
        proj=project_root,
        f=cache_location)
    test_time_multiplier = 2.0
    test_time_base = 0.0
    swallow_output = True
    cache_only = False,
    pre_mutation = None
    post_mutation = None
    backup = False

    save_working_dir = os.getcwd()
    os.chdir(project_root)

    os.environ[
        'PYTHONDONTWRITEBYTECODE'] = '1'  # stop python from creating .pyc files

    pytest_args = []
    pytest_args += not_failing_node_ids

    baseline_time_elapsed = time_test_suite(swallow_output=not swallow_output,
                                            test_command=pytest_args,
                                            working_dir=project_root,
                                            using_testmon=False)

    mutations: List[MutationID] = get_mutants_of(module_under_test_path)

    total = len(mutations)

    timed_out_mutants = set()
    killed = defaultdict(set)
    st = time.time()
    prog = 0
    for mutation_id in tqdm(mutations):
        prog += 1
        mut = mutation_id.line, mutation_id.index

        config = Config(
            swallow_output=not swallow_output,
            test_command=pytest_args,
            working_dir=project_root,
            baseline_time_elapsed=baseline_time_elapsed,
            backup=backup,
            dict_synonyms=[],
            total=total,
            using_testmon=False,
            cache_only=cache_only,
            tests_dirs=[],
            hash_of_tests=hash_of_tests([]),
            test_time_multiplier=test_time_multiplier,
            test_time_base=test_time_base,
            pre_mutation=pre_mutation,
            post_mutation=post_mutation,
            coverage_data=None,
            covered_lines_by_filename=None,
        )

        context = Context(
            mutation_id=mutation_id,
            filename=module_under_test_path,
            dict_synonyms=config.dict_synonyms,
            config=config,
        )

        try:
            mutate_file(backup=True, context=context)

            try:
                # those test cases that killed this mutant
                # they failed - which is good
                failed_test_cases_ids = tests_pass_expanded(
                    config=config, working_dir=project_root, callback=print)
            except TimeoutError:
                failed_test_cases_ids = None
            if failed_test_cases_ids is None:
                # This means test cases timed out
                # we can't figure out which ones exactly
                # so we don't use this mutant in statistics
                timed_out_mutants.add(mut)
            else:
                for test_case_id in failed_test_cases_ids:
                    killed[test_case_id].add(mut)

            if timeout and prog > 2 and prog < total / 2:
                time_per_item = (time.time() - st) / prog
                estimate = time_per_item * total
                if estimate > timeout * 1.1:
                    raise TimeoutError("It will take too much time")

        except Exception:
            raise
        finally:
            move(module_under_test_path + '.bak', module_under_test_path)
            os.chdir(save_working_dir)

    return killed, total
Ejemplo n.º 15
0
def test_bad_mutation_str_type_definition():
    source = """
foo: 'SomeType'
    """
    assert mutate(Context(source=source)) == (source, 0)
Ejemplo n.º 16
0
def test_mutate_dict():
    source = "dict(a=b, c=d)"
    assert mutate(
        Context(source=source,
                mutation_id=RelativeMutationID(
                    source, 1, line_number=0))) == ("dict(a=b, cXX=d)", 1)
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
def test_perform_one_indexed_mutation():
    assert mutate(Context(source='1+1', mutate_id=('1+1', 0))) == ('2+1', 1)
    assert mutate(Context(source='1+1', mutate_id=('1+1', 1))) == ('1-1', 1)
    assert mutate(Context(source='1+1', mutate_id=('1+1', 2))) == ('1+2', 1)
Ejemplo n.º 20
0
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]
Ejemplo n.º 21
0
def test_do_not_mutate_python3(source):
    actual = mutate(
        Context(source=source,
                mutation_id=ALL,
                dict_synonyms=['Struct', 'FooBarDict']))[0]
    assert actual == source
Ejemplo n.º 22
0
def test_mutate_dict2():
    source = "dict(a=b, c=d, e=f, g=h)"
    assert mutate(Context(source=source, mutate_id=(source, 3))) == ("dict(a=b, c=d, e=f, gXX=h)", 1)
Ejemplo n.º 23
0
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)
Ejemplo n.º 24
0
def test_mutate_both():
    source = 'a = b + c'
    mutations = list_mutations(Context(source=source))
    assert len(mutations) == 2
    assert mutate(Context(source=source, mutate_id=mutations[0])) == ('a = b - c', 1)
    assert mutate(Context(source=source, mutate_id=mutations[1])) == ('a = None', 1)
Ejemplo n.º 25
0
def test_syntax_error():
    with pytest.raises(Exception):
        mutate(Context(source=':!'))
Ejemplo n.º 26
0
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)
Ejemplo n.º 27
0
def test_bug_github_issue_26():
    source = """
class ConfigurationOptions(Protocol):
    min_name_length: int
    """
    mutate(Context(source=source))
Ejemplo n.º 28
0
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

    if config.pre_mutation:
        result = subprocess.check_output(config.pre_mutation,
                                         shell=True).decode().strip()
        if result:
            print(result)

    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)

        if config.post_mutation:
            result = subprocess.check_output(config.post_mutation,
                                             shell=True).decode().strip()
            if result:
                print(result)
Ejemplo n.º 29
0
def test_bug_github_issue_77():
    # Don't crash on this
    Context(source='')
Ejemplo n.º 30
0
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 %s mutations for original "%s"' % (number_of_performed_mutations, original)