diff --git a/src/mutmut/mutation/mutators.py b/src/mutmut/mutation/mutators.py index 40b074d9..d6fa5252 100644 --- a/src/mutmut/mutation/mutators.py +++ b/src/mutmut/mutation/mutators.py @@ -1,5 +1,7 @@ """This module contains the mutations for indidvidual nodes, e.g. replacing a != b with a == b.""" +import cmath +import math import re from collections.abc import Callable from collections.abc import Iterable @@ -22,10 +24,19 @@ def operator_number(node: cst.BaseNumber) -> Iterable[cst.BaseNumber]: + # A float literal too large for a float, like 1e999 (a common way to spell + # infinity), evaluates to inf. inf + 1 is still inf, which has no literal + # form, so there is no number mutant to make. if isinstance(node, cst.Integer | cst.Float): - yield node.with_changes(value=repr(node.evaluated_value + 1)) + value = node.evaluated_value + 1 + if isinstance(value, float) and math.isinf(value): + return + yield node.with_changes(value=repr(value)) elif isinstance(node, cst.Imaginary): - yield node.with_changes(value=repr(node.evaluated_value + 1j)) + complex_value = node.evaluated_value + 1j + if cmath.isinf(complex_value): + return + yield node.with_changes(value=repr(complex_value)) else: print("Unexpected number type", node) diff --git a/tests/mutation/test_mutation.py b/tests/mutation/test_mutation.py index 0ff0d198..8ee2a644 100644 --- a/tests/mutation/test_mutation.py +++ b/tests/mutation/test_mutation.py @@ -299,6 +299,11 @@ def mutated_module(source: str) -> str: ("1.0j", "2j"), ("0o1", "2"), ("1.0e10", "10000000001.0"), + # too large for a float, so they evaluate to inf, which has no literal form + ("1e999", []), + ("1e999j", []), + ("a = 1e999", "a = None"), + ("1.5e400 + 2", ["1.5e400 - 2", "1.5e400 + 3"]), ("a = {x for x in y}", "a = None"), ("x+=1", ["x = 1", "x -= 1", "x+=2"]), ("x-=1", ["x = 1", "x += 1", "x-=2"]),