Exemplo n.º 1
0
def filter_wl_bl_categories(
        sample_space: List[Tuple[str, LocIndex]],
        wlbl_categories: Set[str]) -> List[Tuple[str, LocIndex]]:
    """Filter the sample by white/blacklist categories.

    Args:
        sample_space: sample space to filter
        wlbl_categories: set of categories for filtering

    Returns:
        restricted sample space
    """
    LOGGER.info("Category restriction, valid categories: %s",
                sorted(wlbl_categories))
    category_sample = []
    allowed_operations = []

    for m in get_compatible_operation_sets():
        if m.category in wlbl_categories:
            allowed_operations.extend([i for i in m.operations])

    for fn, locidx in sample_space:
        if locidx.op_type in allowed_operations:
            category_sample.append((fn, locidx))

    LOGGER.info("Category restricted sample size: %s", len(category_sample))
    return category_sample
Exemplo n.º 2
0
    def valid_mutations(self) -> Set[Any]:
        """Valid mutations for the set of category codes.

        Returns:
            Set of valid mutations for the codes, types will vary
        """
        # unpack iterable of sets of compatible operations defined in transformers
        return set(
            itertools.chain.from_iterable(
                op.operations
                for op in transformers.get_compatible_operation_sets()
                if op.category in self.codes))
Exemplo n.º 3
0
    def __call__(self, parser, namespace, values, option_string=None):  # type: ignore
        if len(values) > 0:

            valid_categories = {m.category for m in get_compatible_operation_sets()}
            values_set = set(values)

            if not values_set.issubset(valid_categories):
                parser.error(
                    "{0} must only hold valid categories. Use --help to see options.".format(
                        option_string
                    )
                )

        setattr(namespace, self.dest, values)
Exemplo n.º 4
0
def selected_categories(whitelist: List[str], blacklist: List[str]) -> Set[str]:
    """Create the selected categories from the whitelist/blacklist set.

    Args:
        whitelist: list of categories
        blacklist: list of categories

    Returns:
        Selection set of mutation categories
    """
    all_mutations = {m.category for m in get_compatible_operation_sets()}
    w_set = set(whitelist)
    b_set = set(blacklist)

    if len(w_set) > 0:
        return w_set - b_set

    return all_mutations - b_set
Exemplo n.º 5
0
def selected_categories(whitelist: List[str], blacklist: List[str]) -> List[str]:
    """Create the selected categories from the whitelist/blacklist set to use in filtering.

    Args:
        whitelist: list of categories
        blacklist: list of categories

    Returns:
        Selection set of mutation categories
    """
    all_mutations = {m.category for m in transformers.get_compatible_operation_sets()}
    w_set = set(whitelist)
    b_set = set(blacklist)

    if len(w_set) > 0:
        return list(w_set - b_set)

    return list(all_mutations - b_set)
Exemplo n.º 6
0
def cli_epilog() -> str:

    main_epilog = dedent(
        """
    Additional command argument information:
    ========================================

    Black/White List:
    -----------------
     - Use -b and -w to set black/white lists of mutation categories. If -w categories are set then
       all mutation categories except those specified are skipped during trials. If -b categories
       are set then all mutations categories except those specified are considered. If you set both
       -w and -b then the whitelisted categories are selected first, and then the blacklisted
       categories are removed from the candidate set.

    Exclude:
    --------
     - Useful for excluding files that are not included in test coverage. You can set the arg
       multiple times for additional files e.g. mutatest -e src/__init__.py -e src/_devtools.py
       would exclude both src/__init__.py and src/_devtools.py from mutation processing.

    Mode:
    ------
     - f: full mode, run all possible combinations (slowest but most thorough).
     - s: break on first SURVIVOR per mutated location e.g. if there is a single surviving mutation
          at a location move to the next location without further testing.
          This is the default mode.
     - d: break on the first DETECTION per mutated location e.g. if there is a detected mutation on
          at a location move to the next one.
     - sd: break on the first SURVIVOR or DETECTION (fastest, and least thorough).

     The API for mutatest.controller.run_mutation_trials offers finer control over the
     run method beyond the CLI.

    Output:
    -------
     - You can specify a file name or a full path. The folders in the path will be created if they
       do not already exist. The output is a text file formatted in RST headings.

    Src:
    ----
     - This can be a file or a directory. If it is a directory it is recursively searched for .py
       files. Note that the __pycache__ file associated with the file (or sub-files in a directory)
       will be manipulated during mutation testing. If this argument is unspecified, mutatest will
       attempt to find Python packages (using setuptools.find_packages) and use the first
       entry from that auto-detection attempt.

    Testcmds:
    ---------
     - Specify custom test commands as a string e.g. 'pytest -m "not slow"' for running only
       the test suite without the marked "slow" tests. Shlex.split() is used to parse the
       entered command string. Mutant status e.g. SURVIVED vs. DETECTED is based on the
       return code of the command. Return code 0 = SURVIVED, 1 = DETECTED, 2 = ERROR, and
       all others are UNKNOWN. Stdout is shown from the command if --debug mode is enabled.

    Exception:
    ----------
     - A count of survivors for raising an exception after the trails. This is useful if you want
       to raise a system-exit error in automatic running of the trials. For example, you could
       have a continuous integration pipeline stage that runs mutatest over an important section
       of tests (optionally specifying a random seed or categories) and cause a system exit if
       a set number of allowable survivors is exceeded.
    """
    )

    header = "Supported mutation sets"
    description = (
        "These are the current operations that are mutated as compatible sets. "
        "Use the category code for whitelist/blacklist selections."
    )
    mutation_epilog = [header, "=" * len(header), description, "\n"]
    for mutop in get_compatible_operation_sets():
        mutation_epilog.extend(
            [
                mutop.name,
                "-" * len(mutop.name),
                f" - Description: {mutop.desc}",
                f" - Members: {str(mutop.operations)}",
                f" - Category Code: {str(mutop.category)}\n",
            ]
        )

    meta_info = dedent(
        """
    Mutatest information
    ====================
     - Version: {version}
     - License: {license}
     - URL: {url}
     - {copyright}
    """
    ).format_map(
        {
            "version": mutatest.__version__,
            "license": mutatest.__license__,
            "url": mutatest.__uri__,
            "copyright": mutatest.__copyright__,
        }
    )

    return "\n".join([main_epilog] + mutation_epilog + [meta_info])