- return False+ return None
`return False` -> `return None`
Assert the return value; calling the function is not enough.
Scope: all files · 403 mutants generated · 23 tests collected
Showing 16 mutants. Press / to search, Esc to reset.
- return False+ return None
`return False` -> `return None`
Assert the return value; calling the function is not enough.
- return False+ return None
`return False` -> `return None`
Assert the return value; calling the function is not enough.
- compile(candidate, self.sf.path, "exec", dont_inherit=True)+ compile(candidate, self.sf.path, "exec", dont_inherit=False)
`True` -> `False`
Assert against a different value so this constant is observable.
- return False+ return True
`False` -> `True`
Assert against a different value so this constant is observable.
- if isinstance(target, ast.Name) and target.id.startswith("__") and target.id.endswith("__"):+ if isinstance(target, ast.Name) and target.id.startswith("__") and target.id.endswith(""):
string '__' -> ""
Assert against a different value so this constant is observable.
- self.visit(node.value)+ pass
remove `self.visit(node.value)`
Assert the side effect of this call (state, output, or log).
- return False+ return True
`False` -> `True`
Assert against a different value so this constant is observable.
- "negate condition `%s`" % truncate(source, 64),+ "negate condition `%s`" % truncate(source, 65),
`64` -> `65`
Assert against a different value so this constant is observable.
- found = self._token_between(node.values[index], node.values[index + 1], _BOOL_PATTERN)+ found = self._token_between(node.values[index], node.values[index - 1], _BOOL_PATTERN)
`+` -> `-` in `index + 1`
Assert the exact numeric result, not just its type.
- "remove negation: `%s` -> `%s`" % (truncate(self.sf.segment(node), 48), truncate(operand, 48)),+ "remove negation: `%s` -> `%s`" % (truncate(self.sf.segment(node), 48), truncate(operand, 49)),
`48` -> `49`
Assert against a different value so this constant is observable.
- "remove `not`: `%s`" % truncate(operand, 64),+ "remove `not`: `%s`" % truncate(operand, 65),
`64` -> `65`
Assert against a different value so this constant is observable.
- self.generic_visit(node)+ pass
remove `self.generic_visit(node)`
Assert the side effect of this call (state, output, or log).
- source = truncate(self.sf.text[start:end], 64)+ source = truncate(self.sf.text[start:end], 65)
`64` -> `65`
Assert against a different value so this constant is observable.
- if value is None or value is Ellipsis:+ if value is None and value is Ellipsis:
`or` -> `and` in `value is None or value is Ellipsis`
Cover a case where only one operand is true.
- new_value = 1 if value == 0 else (0 if value == 1 else value + 1)+ new_value = 1 if value == 0 else (0 if value != 1 else value + 1)
`==` -> `!=` in `value == 1`
Add a test at the boundary where this comparison flips.
- if len(text) > 32:+ if len(text) > 33:
`32` -> `33`
Assert against a different value so this constant is observable.
- "statement": "statement removal",+ "": "statement removal",
string 'statement' -> ""
Assert against a different value so this constant is observable.
- ast.NotEq: "!=",+ ast.NotEq: "",
string '!=' -> ""
Assert against a different value so this constant is observable.
- ast.GtE: ">=",+ ast.GtE: "",
string '>=' -> ""
Assert against a different value so this constant is observable.
- ast.IsNot: "is not",+ ast.IsNot: "",
string 'is not' -> ""
Assert against a different value so this constant is observable.
- "<": "<=",+ "": "<=",
string '<' -> ""
Assert against a different value so this constant is observable.
- "is": "is not",+ "is": "",
string 'is not' -> ""
Assert against a different value so this constant is observable.
- "is not": "is",+ "": "is",
string 'is not' -> ""
Assert against a different value so this constant is observable.
- ast.Add: ("+", "-"),+ ast.Add: ("+", ""),
string '-' -> ""
Assert against a different value so this constant is observable.
- ast.Sub: ("-=", "+="),+ ast.Sub: ("", "+="),
string '-=' -> ""
Assert against a different value so this constant is observable.
- ast.Div: ("/=", "*="),+ ast.Div: ("", "*="),
string '/=' -> ""
Assert against a different value so this constant is observable.
- ast.Div: ("/=", "*="),+ ast.Div: ("/=", ""),
string '*=' -> ""
Assert against a different value so this constant is observable.
- r"\bnot\s+in\b|\bis\s+not\b|==|!=|<=|>=|<|>|\bin\b|\bis\b"+ ""
string '\\bnot\\s+in\\b|\\bis\\s+not... -> ""
Assert against a different value so this constant is observable.
- "comparison": "Add a test at the boundary where this comparison flips.",+ "comparison": "",
string 'Add a test at the boundary w... -> ""
Assert against a different value so this constant is observable.
- "return": "Assert the return value; calling the function is not enough.",+ "": "Assert the return value; calling the function is not enough.",
string 'return' -> ""
Assert against a different value so this constant is observable.
- if isinstance(node, holders) and node.body:+ if isinstance(node, holders) or node.body:
`and` -> `or` in `isinstance(node, holders) and node.body`
Cover a case where only one operand is true.
- isinstance(first, ast.Expr) and isinstance(first.value, ast.Constant) and isinstance(first.value.value, str)+ not (isinstance(first, ast.Expr) and isinstance(first.value, ast.Constant) and isinstance(first.value.value, str))
negate condition `isinstance(first, ast.Expr) and isinstance(first.value, ast.C...`
Test the branch this condition guards, not only the happy path.
- return ".".join(self.context)+ return "".join(self.context)
string '.' -> ""
Assert against a different value so this constant is observable.
- if self.only_lines is None:+ if self.only_lines is not None:
`is` -> `is not` in `self.only_lines is None`
Add a test at the boundary where this comparison flips.
- return any(line in self.only_lines for line in range(first, last + 1))+ return None
`return any(line in self.only_lines for line in range(first, l...` -> `return None`
Assert the return value; calling the function is not enough.
- if line == end_line:+ if not (line == end_line):
negate condition `line == end_line`
Test the branch this condition guards, not only the happy path.
- + replacement+ - replacement
`+` -> `-` in `source_line[: col - 1] + replacement`
Assert the exact numeric result, not just its type.
- return start + index, start + index + len(needle), needle+ return start - index, start + index + len(needle), needle
`+` -> `-` in `start + index`
Assert the exact numeric result, not just its type.
- return False+ return True
`False` -> `True`
Assert against a different value so this constant is observable.
- if isinstance(op, ast.Eq) and isinstance(comparator, ast.Constant) and comparator.value == "__main__":+ if isinstance(op, ast.Eq) and isinstance(comparator, ast.Constant) and comparator.value != "__main__":
`==` -> `!=` in `comparator.value == "__main__"`
Add a test at the boundary where this comparison flips.
- return True+ return False
`True` -> `False`
Assert against a different value so this constant is observable.
- "negate condition `%s`" % truncate(source, 64),+ "" % truncate(source, 64),
string 'negate condition `%s`' -> ""
Assert against a different value so this constant is observable.
- found = self._token_between(operands[index], operands[index + 1], _COMPARE_PATTERN)+ found = self._token_between(operands[index], operands[index + 0], _COMPARE_PATTERN)
`1` -> `0`
Assert against a different value so this constant is observable.
- if replacement is None:+ if replacement is not None:
`is` -> `is not` in `replacement is None`
Add a test at the boundary where this comparison flips.
- self._add( "comparison", start, end, replacement, node, "`%s` -> `%s` in `%s`" % (token, replacement, truncate(self.sf.segment(node), 64)), )+ pass
remove `self._add( "comparison", start, end, replacement, node, "`%s`...`
Assert the side effect of this call (state, output, or log).
- if "boolean" in self.operators:+ if "boolean" not in self.operators:
`in` -> `not in` in `"boolean" in self.operators`
Add a test at the boundary where this comparison flips.
- replacement = "or" if token == "and" else "and"+ replacement = "" if token == "and" else "and"
string 'or' -> ""
Assert against a different value so this constant is observable.
- self._add( "boolean", start, end, replacement, node, "`%s` -> `%s` in `%s`" % (token, replacement, truncate(self.sf.segment(node), 64)), )+ pass
remove `self._add( "boolean", start, end, replacement, node, "`%s` ->...`
Assert the side effect of this call (state, output, or log).
- if found:+ if not (found):
negate condition `found`
Test the branch this condition guards, not only the happy path.
- self.generic_visit(node)+ pass
remove `self.generic_visit(node)`
Assert the side effect of this call (state, output, or log).
- if isinstance(node.op, ast.USub) and "arithmetic" in self.operators:+ if isinstance(node.op, ast.USub) or "arithmetic" in self.operators:
`and` -> `or` in `isinstance(node.op, ast.USub) and "arithmetic" in self.operators`
Cover a case where only one operand is true.
- elif isinstance(node.op, ast.Not) and "boolean" in self.operators:+ elif isinstance(node.op, ast.Not) and "" in self.operators:
string 'boolean' -> ""
Assert against a different value so this constant is observable.
- if isinstance(node.value, ast.Constant) and node.value.value is None:+ if isinstance(node.value, ast.Constant) or node.value.value is None:
`and` -> `or` in `isinstance(node.value, ast.Constant) and node.value.value is ...`
Cover a case where only one operand is true.
- if self.context and self.context[-1] == "__init__":+ if self.context or self.context[-1] == "__init__":
`and` -> `or` in `self.context and self.context[-1] == "__init__"`
Cover a case where only one operand is true.
- "return",+ "",
string 'return' -> ""
Assert against a different value so this constant is observable.
- "`%s` -> `return None`" % source,+ "" % source,
string '`%s` -> `return None`' -> ""
Assert against a different value so this constant is observable.
- if "constant" not in self.operators or id(node) in self.docstrings:+ if not ("constant" not in self.operators or id(node) in self.docstrings):
negate condition `"constant" not in self.operators or id(node) in self.docstrings`
Test the branch this condition guards, not only the happy path.
- if value is None or value is Ellipsis:+ if not (value is None or value is Ellipsis):
negate condition `value is None or value is Ellipsis`
Test the branch this condition guards, not only the happy path.
- new_value = 1.0 if value == 0.0 else value + 1.0+ new_value = 2.0 if value == 0.0 else value + 1.0
`1.0` -> `2.0`
Assert against a different value so this constant is observable.
- if name.lower() not in self.skip_calls:+ if not (name.lower() not in self.skip_calls):
negate condition `name.lower() not in self.skip_calls`
Test the branch this condition guards, not only the happy path.
| file | killed | survived | score | |
|---|---|---|---|---|
| fang/mutators.py | 44 | 16 | 73% |
sampled 60 of 403 mutants (seed 0); score is an estimate
Mutation score is the share of generated mutants your suite detected. A mutant is a small, syntactically valid change to your code: a flipped comparison, a changed constant, a removed return value. If the suite still passes, the mutant survived, which means no test observed that behaviour.
Survivors are not automatically bugs. Some mutants are equivalent (the change cannot alter observable behaviour, such as changing the rounding precision of a value that is already exact). Treat survivors as questions, not verdicts. The hint on each card suggests the kind of assertion that would settle it.
Fang only mutates the lines in scope, runs the suite with fail-fast, and treats a timeout or a crash caused by the mutant as detection. A green baseline is required; a red suite cannot distinguish a surviving mutant from a pre-existing failure.
Sampled 60 of 403 mutants. The score is an estimate; the 95% Wilson interval is 61.0% to 82.9%.