Skip to content

Commit d65d70c

Browse files
CHB-0r1sЛузин Борис Евгеньевич
authored andcommitted
feat(str_call_mut): add str methods call mutations and tests
1 parent b7b4f90 commit d65d70c

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

mutmut/node_mutation.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,35 @@ def operator_arg_removal(
9696
yield node.with_changes(args=[*node.args[:i], *node.args[i + 1 :]])
9797

9898

99+
supported_str_methods_swap = [
100+
("lower", "upper"),
101+
("upper", "lower"),
102+
("lstrip", "rstrip"),
103+
("rstrip", "lstrip"),
104+
("find", "rfind"),
105+
("rfind", "find"),
106+
("ljust", "rjust"),
107+
("rjust", "ljust"),
108+
("index", "rindex"),
109+
("rindex", "index"),
110+
("split", "rsplit"),
111+
("rsplit", "split"),
112+
("removeprefix", "removesuffix"),
113+
("removesuffix", "removeprefix"),
114+
("partition", "rpartition"),
115+
("rpartition", "partition")
116+
]
117+
118+
def operator_string_methods_swap(
119+
node: cst.Call
120+
) -> Iterable[cst.Call]:
121+
"""try to swap string method to opposite e.g. a.lower() -> a.upper()"""
122+
123+
for old_call, new_call in supported_str_methods_swap:
124+
if m.matches(node.func, m.Attribute(value=m.DoNotCare(), attr=m.Name(value=old_call))):
125+
yield node.with_changes(func=cst.Attribute(value=node.func.value, attr=cst.Name(value=new_call)))
126+
127+
99128
def operator_remove_unary_ops(
100129
node: cst.UnaryOperation
101130
) -> Iterable[cst.BaseExpression]:
@@ -208,6 +237,7 @@ def operator_match(node: cst.Match) -> Iterable[cst.CSTNode]:
208237
(cst.UnaryOperation, operator_remove_unary_ops),
209238
(cst.Call, operator_dict_arguments),
210239
(cst.Call, operator_arg_removal),
240+
(cst.Call, operator_string_methods_swap),
211241
(cst.Lambda, operator_lambda),
212242
(cst.CSTNode, operator_keywords),
213243
(cst.CSTNode, operator_swap_op),

tests/test_mutation.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@ def mutated_module(source: str) -> str:
4040
# ('break', 'continue'), # probably a bad idea. Can introduce infinite loops.
4141
('break', 'return'),
4242
('continue', 'break'),
43+
('a.lower()', 'a.upper()'),
44+
('a.upper()', 'a.lower()'),
45+
('a.lstrip("!")', ['a.rstrip("!")', 'a.lstrip("XX!XX")', 'a.lstrip(None)']),
46+
('a.rstrip("!")', ['a.lstrip("!")', 'a.rstrip("XX!XX")', 'a.rstrip(None)']),
47+
('a.find("!")', ['a.rfind("!")', 'a.find("XX!XX")', 'a.find(None)']),
48+
('a.rfind("!")', ['a.find("!")', 'a.rfind("XX!XX")', 'a.rfind(None)']),
49+
('a.ljust(10, "+")', [
50+
'a.ljust("+")', 'a.ljust(10, "XX+XX")',
51+
'a.ljust(10, )', 'a.ljust(10, None)',
52+
'a.ljust(11, "+")', 'a.ljust(None, "+")',
53+
'a.rjust(10, "+")'
54+
]),
55+
('a.rjust(10, "+")', [
56+
'a.ljust(10, "+")', 'a.rjust("+")',
57+
'a.rjust(10, "XX+XX")', 'a.rjust(10, )',
58+
'a.rjust(10, None)', 'a.rjust(11, "+")',
59+
'a.rjust(None, "+")'
60+
]),
61+
('a.index("+")', ['a.rindex("+")', 'a.index("XX+XX")', 'a.index(None)']),
62+
('a.rindex("+")', ['a.index("+")', 'a.rindex("XX+XX")', 'a.rindex(None)']),
63+
('a.split()', 'a.rsplit()'),
64+
('a.rsplit()', 'a.split()'),
65+
('a.removeprefix("+")', ['a.removesuffix("+")', 'a.removeprefix("XX+XX")', 'a.removeprefix(None)']),
66+
('a.removesuffix("+")', ['a.removeprefix("+")', 'a.removesuffix("XX+XX")', 'a.removesuffix(None)']),
67+
('a.partition("++")', ['a.rpartition("++")', 'a.partition("XX++XX")', 'a.partition(None)']),
68+
('a.rpartition("++")', ['a.partition("++")', 'a.rpartition("XX++XX")', 'a.rpartition(None)']),
4369
('a(b)', 'a(None)'),
4470
("dict(a=None)", ["dict(aXX=None)"]),
4571
("dict(a=b)", ["dict(aXX=b)", 'dict(a=None)']),

0 commit comments

Comments
 (0)