175 lines
6.2 KiB
Python
175 lines
6.2 KiB
Python
import pytest
|
|
from pathlib import Path
|
|
from src.analyzers.complexity import ComplexityCalculator
|
|
from src.analyzers.dependencies import DependencyAnalyzer
|
|
from src.graph.builder import GraphBuilder, GraphType, GraphNode, NodeType, GraphEdge
|
|
from src.parsers.base import Entity, EntityType
|
|
|
|
|
|
class TestComplexityCalculator:
|
|
def setup_method(self):
|
|
self.calculator = ComplexityCalculator()
|
|
|
|
def test_simple_function_complexity(self):
|
|
entity = Entity(
|
|
name="simple_func",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=5,
|
|
code="def simple_func():\n pass",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["complexity_score"] == 1
|
|
assert result["name"] == "simple_func"
|
|
|
|
def test_function_with_if_statement(self):
|
|
entity = Entity(
|
|
name="func_with_if",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=10,
|
|
code="def func_with_if(x):\n if x > 0:\n return True\n return False",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["complexity_score"] == 2
|
|
assert result["decision_points"] == 1
|
|
|
|
def test_function_with_multiple_decision_points(self):
|
|
entity = Entity(
|
|
name="complex_func",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=20,
|
|
code="""def complex_func(x):
|
|
if x > 0:
|
|
if x > 10:
|
|
return "big"
|
|
else:
|
|
return "small"
|
|
elif x < 0:
|
|
return "negative"
|
|
else:
|
|
return "zero"
|
|
""",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["complexity_score"] >= 4
|
|
|
|
def test_function_with_loop(self):
|
|
entity = Entity(
|
|
name="func_with_loop",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=10,
|
|
code="def func_with_loop(items):\n for item in items:\n print(item)",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["complexity_score"] == 2
|
|
|
|
def test_method_complexity(self):
|
|
entity = Entity(
|
|
name="method",
|
|
entity_type=EntityType.METHOD,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=8,
|
|
code="def process(self, data):\n if data:\n for item in data:\n if item.valid:\n pass",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["entity_type"] == "method"
|
|
|
|
def test_complexity_threshold(self):
|
|
assert self.calculator.complexity_threshold == 10
|
|
|
|
def test_set_complexity_threshold(self):
|
|
self.calculator.set_complexity_threshold(15)
|
|
assert self.calculator.complexity_threshold == 15
|
|
|
|
def test_is_complex_flag(self):
|
|
entity = Entity(
|
|
name="simple",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=5,
|
|
code="def simple():\n pass",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["is_complex"] is False
|
|
|
|
def test_high_complexity_flag(self):
|
|
entity = Entity(
|
|
name="complex",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=30,
|
|
code="def complex():\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n if True:\n pass",
|
|
)
|
|
result = self.calculator.calculate_for_entity(entity)
|
|
assert result["is_complex"] is True
|
|
|
|
def test_calculate_project_complexity(self):
|
|
entities = [
|
|
Entity(
|
|
name="func1",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=1,
|
|
end_line=5,
|
|
code="def func1():\n pass",
|
|
),
|
|
Entity(
|
|
name="func2",
|
|
entity_type=EntityType.FUNCTION,
|
|
file_path=Path("/test.py"),
|
|
start_line=10,
|
|
end_line=20,
|
|
code="def func2():\n if True:\n pass",
|
|
),
|
|
]
|
|
report = self.calculator.calculate_project_complexity(entities)
|
|
assert report["total_functions"] == 2
|
|
assert report["total_cyclomatic_complexity"] >= 2
|
|
assert "complexity_distribution" in report
|
|
|
|
|
|
class TestDependencyAnalyzer:
|
|
def setup_method(self):
|
|
self.builder = GraphBuilder(GraphType.DIRECTED)
|
|
self.analyzer = DependencyAnalyzer(self.builder)
|
|
|
|
def test_analyze_empty_graph(self):
|
|
report = self.analyzer.analyze()
|
|
assert report.total_files == 0
|
|
assert report.total_functions == 0
|
|
assert report.total_classes == 0
|
|
|
|
def test_count_entities(self):
|
|
file_node = GraphNode(node_id="file1", node_type=NodeType.FILE, name="test.py")
|
|
func_node = GraphNode(node_id="func1", node_type=NodeType.FUNCTION, name="test_func")
|
|
class_node = GraphNode(node_id="class1", node_type=NodeType.CLASS, name="TestClass")
|
|
self.builder.add_node(file_node)
|
|
self.builder.add_node(func_node)
|
|
self.builder.add_node(class_node)
|
|
|
|
report = self.analyzer.analyze()
|
|
assert report.total_files == 1
|
|
assert report.total_functions == 1
|
|
assert report.total_classes == 1
|
|
|
|
def test_get_architecture_layers(self):
|
|
file_node = GraphNode(
|
|
node_id="controller",
|
|
node_type=NodeType.FILE,
|
|
name="controller.py",
|
|
file_path=Path("/src/ui/controller.py"),
|
|
)
|
|
self.builder.add_node(file_node)
|
|
layers = self.analyzer.get_architecture_layers()
|
|
assert "presentation" in layers or "other" in layers
|