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
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))
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)
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
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)
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])