Example #1
0
def clean_trial(src_loc: Path, test_cmds: List[str]) -> timedelta:
    """Remove all existing cache files and run the test suite.

    Args:
        src_loc: the directory of the package for cache removal, may be a file
        test_cmds: test running commands for subprocess.run()

    Returns:
        None

    Raises:
        BaselineTestException: if the clean trial does not pass from the test run.
    """
    cache.remove_existing_cache_files(src_loc)

    LOGGER.info("Running clean trial")

    # clean trial will show output all the time for diagnostic purposes
    start = datetime.now()
    clean_run = subprocess.run(test_cmds, capture_output=False)
    end = datetime.now()

    if clean_run.returncode != 0:
        raise BaselineTestException(
            f"Clean trial does not pass, mutant tests will be meaningless.\n"
            f"Output: {str(clean_run.stdout)}")

    return end - start
Example #2
0
def create_mutation_run_trial(genome: Genome, target_idx: LocIndex,
                              mutation_op: Any,
                              test_cmds: List[str]) -> MutantTrialResult:
    """Run a single mutation trial by creating a new mutated cache file, running the
    test commands, and then removing the mutated cache file.

    Args:
        genome: the genome to mutate
        target_idx: the mutation location
        mutation_op: the mutation operation
        test_cmds: the test commands to execute with the mutated code

    Returns:
        The mutation trial result
    """

    LOGGER.debug("Running trial for %s", mutation_op)
    mutant = genome.mutate(target_idx, mutation_op, write_cache=True)
    mutant_trial = subprocess.run(test_cmds,
                                  capture_output=capture_output(
                                      LOGGER.getEffectiveLevel()))
    cache.remove_existing_cache_files(mutant.src_file)

    return MutantTrialResult(mutant=mutant,
                             return_code=mutant_trial.returncode)
Example #3
0
def test_remove_existing_cache_files_from_folder(tmp_path):
    """Removing multiple cache files based on scanning a directory."""
    # structure matches expectation of get_cache_file_loc return
    tag = sys.implementation.cache_tag
    test_cache_path = tmp_path / "__pycache__"
    test_cache_path.mkdir()

    # create multiple test files in the tmp folder
    test_files = ["first.py", "second.py", "third.py"]
    test_cache_files = []

    for tf in test_files:
        with open(tmp_path / tf, "w") as temp_py:
            temp_py.write("import this")

        test_cache_file = test_cache_path / ".".join(
            [Path(tf).stem, tag, "pyc"])
        test_cache_file.write_bytes(b"temporary bytes")
        test_cache_files.append(test_cache_file)

    for tcf in test_cache_files:
        assert tcf.exists()

    remove_existing_cache_files(tmp_path)

    for tcf in test_cache_files:
        assert not tcf.exists()
Example #4
0
def write_mutant_cache_file(mutant: Mutant) -> None:
    """Create the cache file for the mutant on disk in __pycache__.

    Existing target cache files are removed to ensure clean overwrites.

    Reference: https://github.com/python/cpython/blob/master/Lib/py_compile.py#L157

    Args:
        mutant: the mutant definition to create

    Returns:
        None, creates the cache file on disk.
    """
    check_cache_invalidation_mode()

    bytecode = importlib._bootstrap_external._code_to_timestamp_pyc(  # type: ignore
        mutant.mutant_code, mutant.source_stats["mtime"],
        mutant.source_stats["size"])

    remove_existing_cache_files(mutant.src_file)

    create_cache_dirs(mutant.cfile)

    LOGGER.debug("Writing mutant cache file: %s", mutant.cfile)
    importlib._bootstrap_external._write_atomic(mutant.cfile, bytecode,
                                                mutant.mode)  # type: ignore
Example #5
0
def test_remove_existing_cache_files(tmp_path):
    """Removing a single existing cache file."""
    test_file = tmp_path / "first.py"

    # structure matches expectation of get_cache_file_loc return
    tag = sys.implementation.cache_tag
    test_cache_path = tmp_path / "__pycache__"
    test_cache_file = test_cache_path / ".".join([Path(test_file).stem, tag, "pyc"])

    # create the temp dir and tmp cache file
    test_cache_path.mkdir()
    test_cache_file.write_bytes(b"temporary bytes")

    assert test_cache_file.exists()

    remove_existing_cache_files(test_file)

    assert not test_cache_file.exists()
Example #6
0
def create_mutation_run_trial(genome: Genome, target_idx: LocIndex,
                              mutation_op: Any, test_cmds: List[str],
                              max_runtime: float) -> MutantTrialResult:
    """Run a single mutation trial by creating a new mutated cache file, running the
    test commands, and then removing the mutated cache file.

    Args:
        genome: the genome to mutate
        target_idx: the mutation location
        mutation_op: the mutation operation
        test_cmds: the test commands to execute with the mutated code
        max_runtime: timeout for the trial

    Returns:
        The mutation trial result
    """
    LOGGER.debug("Running trial for %s", mutation_op)

    mutant = genome.mutate(target_idx, mutation_op, write_cache=True)

    try:
        mutant_trial = subprocess.run(
            test_cmds,
            capture_output=capture_output(LOGGER.getEffectiveLevel()),
            timeout=max_runtime,
        )
        return_code = mutant_trial.returncode

    except subprocess.TimeoutExpired:
        return_code = 3

    cache.remove_existing_cache_files(mutant.src_file)

    return MutantTrialResult(
        mutant=MutantReport(src_file=mutant.src_file,
                            src_idx=mutant.src_idx,
                            mutation=mutant.mutation),
        return_code=return_code,
    )
Example #7
0
def create_mutation_and_run_trial(
    src_tree: ast.Module,
    src_file: str,
    target_idx: LocIndex,
    mutation_op: Any,
    test_cmds: List[str],
    tree_inplace: bool = False,
) -> MutantTrialResult:
    """Write the mutation to the cache location and runs the trial based on test_cmds

    Args:
        src_tree: the source AST
        src_file:  the source file location to determine cache location
        target_idx: the mutation target in the source AST
        mutation_op: the mutation to apply
        test_cmds: test command string for running the trial
        tree_inplace: flag for in-place mutations, default to False

    Returns:
        MutationTrialResult from the trial run
    """

    # mutatest requires deep-copy to avoid in-place reference changes to AST
    tree = src_tree if tree_inplace else deepcopy(src_tree)

    mutant = create_mutant(tree=tree,
                           src_file=src_file,
                           target_idx=target_idx,
                           mutation_op=mutation_op)

    write_mutant_cache_file(mutant)

    mutant_trial = subprocess.run(test_cmds,
                                  capture_output=capture_output(
                                      LOGGER.getEffectiveLevel()))
    remove_existing_cache_files(mutant.src_file)

    return MutantTrialResult(mutant=mutant,
                             return_code=mutant_trial.returncode)