test: sync refactoring opportunity finder tests (#210)
Some checks failed
Test / pytest (pull_request) Failing after 49s
Some checks failed
Test / pytest (pull_request) Failing after 49s
This commit is contained in:
@@ -19,208 +19,95 @@ FileMetrics = mod.FileMetrics
|
|||||||
|
|
||||||
|
|
||||||
def test_complexity_simple_function():
|
def test_complexity_simple_function():
|
||||||
"""Simple function should have low complexity."""
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||||
f.write("""
|
f.write("\ndef simple():\n return 42\n")
|
||||||
def simple():
|
|
||||||
return 42
|
|
||||||
""")
|
|
||||||
f.flush()
|
f.flush()
|
||||||
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
||||||
assert avg == 1.0, f"Expected 1.0, got {avg}"
|
assert avg == 1.0
|
||||||
assert max_c == 1, f"Expected 1, got {max_c}"
|
assert max_c == 1
|
||||||
assert funcs == 1, f"Expected 1, got {funcs}"
|
assert funcs == 1
|
||||||
assert classes == 0, f"Expected 0, got {classes}"
|
assert classes == 0
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
print("PASS: test_complexity_simple_function")
|
print("PASS: test_complexity_simple_function")
|
||||||
|
|
||||||
|
|
||||||
def test_complexity_with_conditionals():
|
def test_complexity_with_conditionals():
|
||||||
"""Function with if/else should have higher complexity."""
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||||
f.write("""
|
f.write("\ndef complex_func(x):\n if x > 0:\n if x > 10:\n return 'big'\n else:\n return 'small'\n elif x < 0:\n return 'negative'\n else:\n return 'zero'\n")
|
||||||
def complex_func(x):
|
|
||||||
if x > 0:
|
|
||||||
if x > 10:
|
|
||||||
return "big"
|
|
||||||
else:
|
|
||||||
return "small"
|
|
||||||
elif x < 0:
|
|
||||||
return "negative"
|
|
||||||
else:
|
|
||||||
return "zero"
|
|
||||||
""")
|
|
||||||
f.flush()
|
f.flush()
|
||||||
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
||||||
# Base 1 + 3 if/elif + 1 nested if = 5
|
assert max_c >= 4
|
||||||
assert max_c >= 4, f"Expected max_c >= 4, got {max_c}"
|
assert funcs == 1
|
||||||
assert funcs == 1, f"Expected 1, got {funcs}"
|
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
print("PASS: test_complexity_with_conditionals")
|
print("PASS: test_complexity_with_conditionals")
|
||||||
|
|
||||||
|
|
||||||
def test_complexity_with_loops():
|
def test_complexity_with_loops():
|
||||||
"""Function with loops should increase complexity."""
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||||
f.write("""
|
f.write("\ndef loop_func(items):\n result = []\n for item in items:\n if item > 0:\n result.append(item)\n while len(result) > 10:\n result.pop()\n return result\n")
|
||||||
def loop_func(items):
|
|
||||||
result = []
|
|
||||||
for item in items:
|
|
||||||
if item > 0:
|
|
||||||
result.append(item)
|
|
||||||
while len(result) > 10:
|
|
||||||
result.pop()
|
|
||||||
return result
|
|
||||||
""")
|
|
||||||
f.flush()
|
f.flush()
|
||||||
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
||||||
# Base 1 + 1 for + 1 if + 1 while = 4
|
assert max_c >= 3
|
||||||
assert max_c >= 3, f"Expected max_c >= 3, got {max_c}"
|
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
print("PASS: test_complexity_with_loops")
|
print("PASS: test_complexity_with_loops")
|
||||||
|
|
||||||
|
|
||||||
def test_complexity_with_class():
|
def test_complexity_with_class():
|
||||||
"""Class with methods should count both."""
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||||
f.write("""
|
f.write("\nclass MyClass:\n def method1(self):\n if True:\n pass\n def method2(self):\n for i in range(10):\n pass\n")
|
||||||
class MyClass:
|
|
||||||
def method1(self):
|
|
||||||
if True:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def method2(self):
|
|
||||||
for i in range(10):
|
|
||||||
pass
|
|
||||||
""")
|
|
||||||
f.flush()
|
f.flush()
|
||||||
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
||||||
assert classes == 1, f"Expected 1 class, got {classes}"
|
assert classes == 1
|
||||||
assert funcs == 2, f"Expected 2 functions, got {funcs}"
|
assert funcs == 2
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
print("PASS: test_complexity_with_class")
|
print("PASS: test_complexity_with_class")
|
||||||
|
|
||||||
|
|
||||||
def test_complexity_syntax_error():
|
def test_complexity_syntax_error():
|
||||||
"""File with syntax error should return zeros."""
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||||
f.write("def broken(:\n pass")
|
f.write("def broken(:\n pass")
|
||||||
f.flush()
|
f.flush()
|
||||||
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
avg, max_c, funcs, classes, lines = compute_file_complexity(f.name)
|
||||||
assert avg == 0.0, f"Expected 0.0, got {avg}"
|
assert avg == 0.0
|
||||||
assert funcs == 0, f"Expected 0, got {funcs}"
|
assert funcs == 0
|
||||||
os.unlink(f.name)
|
os.unlink(f.name)
|
||||||
print("PASS: test_complexity_syntax_error")
|
print("PASS: test_complexity_syntax_error")
|
||||||
|
|
||||||
|
|
||||||
def test_refactoring_score_high_complexity():
|
def test_refactoring_score_high_complexity():
|
||||||
"""High complexity should give high score."""
|
metrics = FileMetrics(path="test.py", lines=200, complexity=15.0, max_complexity=25, functions=10, classes=2, churn_30d=5, churn_90d=15, test_coverage=0.3, refactoring_score=0.0)
|
||||||
metrics = FileMetrics(
|
|
||||||
path="test.py",
|
|
||||||
lines=200,
|
|
||||||
complexity=15.0,
|
|
||||||
max_complexity=25,
|
|
||||||
functions=10,
|
|
||||||
classes=2,
|
|
||||||
churn_30d=5,
|
|
||||||
churn_90d=15,
|
|
||||||
test_coverage=0.3,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
score = calculate_refactoring_score(metrics)
|
score = calculate_refactoring_score(metrics)
|
||||||
assert score > 50, f"Expected score > 50, got {score}"
|
assert score > 50
|
||||||
print("PASS: test_refactoring_score_high_complexity")
|
print("PASS: test_refactoring_score_high_complexity")
|
||||||
|
|
||||||
|
|
||||||
def test_refactoring_score_low_complexity():
|
def test_refactoring_score_low_complexity():
|
||||||
"""Low complexity should give lower score."""
|
metrics = FileMetrics(path="test.py", lines=50, complexity=2.0, max_complexity=3, functions=3, classes=0, churn_30d=0, churn_90d=1, test_coverage=0.9, refactoring_score=0.0)
|
||||||
metrics = FileMetrics(
|
|
||||||
path="test.py",
|
|
||||||
lines=50,
|
|
||||||
complexity=2.0,
|
|
||||||
max_complexity=3,
|
|
||||||
functions=3,
|
|
||||||
classes=0,
|
|
||||||
churn_30d=0,
|
|
||||||
churn_90d=1,
|
|
||||||
test_coverage=0.9,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
score = calculate_refactoring_score(metrics)
|
score = calculate_refactoring_score(metrics)
|
||||||
assert score < 30, f"Expected score < 30, got {score}"
|
assert score < 30
|
||||||
print("PASS: test_refactoring_score_low_complexity")
|
print("PASS: test_refactoring_score_low_complexity")
|
||||||
|
|
||||||
|
|
||||||
def test_refactoring_score_high_churn():
|
def test_refactoring_score_high_churn():
|
||||||
"""High churn should increase score."""
|
metrics = FileMetrics(path="test.py", lines=100, complexity=5.0, max_complexity=8, functions=5, classes=0, churn_30d=10, churn_90d=20, test_coverage=0.5, refactoring_score=0.0)
|
||||||
metrics = FileMetrics(
|
|
||||||
path="test.py",
|
|
||||||
lines=100,
|
|
||||||
complexity=5.0,
|
|
||||||
max_complexity=8,
|
|
||||||
functions=5,
|
|
||||||
classes=0,
|
|
||||||
churn_30d=10,
|
|
||||||
churn_90d=20,
|
|
||||||
test_coverage=0.5,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
score = calculate_refactoring_score(metrics)
|
score = calculate_refactoring_score(metrics)
|
||||||
# Churn should contribute significantly
|
assert score > 40
|
||||||
assert score > 40, f"Expected score > 40 for high churn, got {score}"
|
|
||||||
print("PASS: test_refactoring_score_high_churn")
|
print("PASS: test_refactoring_score_high_churn")
|
||||||
|
|
||||||
|
|
||||||
def test_refactoring_score_no_coverage():
|
def test_refactoring_score_no_coverage():
|
||||||
"""No coverage data should assume medium risk."""
|
metrics = FileMetrics(path="test.py", lines=100, complexity=5.0, max_complexity=8, functions=5, classes=0, churn_30d=1, churn_90d=2, test_coverage=None, refactoring_score=0.0)
|
||||||
metrics = FileMetrics(
|
|
||||||
path="test.py",
|
|
||||||
lines=100,
|
|
||||||
complexity=5.0,
|
|
||||||
max_complexity=8,
|
|
||||||
functions=5,
|
|
||||||
classes=0,
|
|
||||||
churn_30d=1,
|
|
||||||
churn_90d=2,
|
|
||||||
test_coverage=None,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
score = calculate_refactoring_score(metrics)
|
score = calculate_refactoring_score(metrics)
|
||||||
# Should have some score from the 5-point coverage component
|
assert score > 0
|
||||||
assert score > 0, f"Expected positive score, got {score}"
|
|
||||||
print("PASS: test_refactoring_score_no_coverage")
|
print("PASS: test_refactoring_score_no_coverage")
|
||||||
|
|
||||||
|
|
||||||
def test_refactoring_score_large_file():
|
def test_refactoring_score_large_file():
|
||||||
"""Large files should score higher."""
|
metrics_small = FileMetrics(path="small.py", lines=50, complexity=5.0, max_complexity=8, functions=3, classes=0, churn_30d=1, churn_90d=2, test_coverage=0.8, refactoring_score=0.0)
|
||||||
metrics_small = FileMetrics(
|
metrics_large = FileMetrics(path="large.py", lines=1000, complexity=5.0, max_complexity=8, functions=3, classes=0, churn_30d=1, churn_90d=2, test_coverage=0.8, refactoring_score=0.0)
|
||||||
path="small.py",
|
|
||||||
lines=50,
|
|
||||||
complexity=5.0,
|
|
||||||
max_complexity=8,
|
|
||||||
functions=3,
|
|
||||||
classes=0,
|
|
||||||
churn_30d=1,
|
|
||||||
churn_90d=2,
|
|
||||||
test_coverage=0.8,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
metrics_large = FileMetrics(
|
|
||||||
path="large.py",
|
|
||||||
lines=1000,
|
|
||||||
complexity=5.0,
|
|
||||||
max_complexity=8,
|
|
||||||
functions=3,
|
|
||||||
classes=0,
|
|
||||||
churn_30d=1,
|
|
||||||
churn_90d=2,
|
|
||||||
test_coverage=0.8,
|
|
||||||
refactoring_score=0.0
|
|
||||||
)
|
|
||||||
score_small = calculate_refactoring_score(metrics_small)
|
score_small = calculate_refactoring_score(metrics_small)
|
||||||
score_large = calculate_refactoring_score(metrics_large)
|
score_large = calculate_refactoring_score(metrics_large)
|
||||||
assert score_large > score_small, \
|
assert score_large > score_small
|
||||||
f"Large file ({score_large}) should score higher than small ({score_small})"
|
|
||||||
print("PASS: test_refactoring_score_large_file")
|
print("PASS: test_refactoring_score_large_file")
|
||||||
|
|
||||||
|
|
||||||
@@ -239,4 +126,4 @@ def run_all():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_all()
|
run_all()
|
||||||
|
|||||||
Reference in New Issue
Block a user