From 230c05e545a80c8fc651ce29eb2233b58b480db6 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Fri, 30 Jan 2026 22:12:55 +0000 Subject: [PATCH] Initial upload with CI/CD workflow --- tests/unit/test_dependency_graph.py | 177 ++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 tests/unit/test_dependency_graph.py diff --git a/tests/unit/test_dependency_graph.py b/tests/unit/test_dependency_graph.py new file mode 100644 index 0000000..57023a2 --- /dev/null +++ b/tests/unit/test_dependency_graph.py @@ -0,0 +1,177 @@ +"""Unit tests for dependency graph module.""" + +import pytest +from pathlib import Path +from codesnap.core.dependency_graph import DependencyGraphBuilder, DependencyParser, Dependency + + +class TestDependencyParser: + """Tests for DependencyParser class.""" + + def setup_method(self) -> None: + self.parser = DependencyParser() + + def test_parse_python_import(self) -> None: + code = "import os" + deps = self.parser.parse_file(Path("test.py"), code, "python") + assert len(deps) >= 1 + + def test_parse_python_from_import(self) -> None: + code = "from pathlib import Path" + deps = self.parser.parse_file(Path("test.py"), code, "python") + assert len(deps) >= 1 + + def test_parse_python_multiple_imports(self) -> None: + code = """ +import os +import sys +from pathlib import Path +from collections import defaultdict +""" + deps = self.parser.parse_file(Path("test.py"), code, "python") + assert len(deps) >= 3 + + def test_parse_javascript_require(self) -> None: + code = "const express = require('express');" + deps = self.parser.parse_file(Path("test.js"), code, "javascript") + assert len(deps) >= 1 + + def test_parse_javascript_import(self) -> None: + code = "import { useState } from 'react';" + deps = self.parser.parse_file(Path("test.js"), code, "javascript") + assert len(deps) >= 1 + + def test_parse_go_import(self) -> None: + code = 'import "fmt"' + deps = self.parser.parse_file(Path("test.go"), code, "go") + assert len(deps) >= 1 + + def test_parse_rust_use(self) -> None: + code = "use std::collections::HashMap;" + deps = self.parser.parse_file(Path("test.rs"), code, "rust") + assert len(deps) >= 1 + + def test_parse_java_import(self) -> None: + code = "import java.util.ArrayList;" + deps = self.parser.parse_file(Path("test.java"), code, "java") + assert len(deps) >= 1 + + def test_parse_unsupported_language(self) -> None: + code = "some random code" + deps = self.parser.parse_file(Path("test.xyz"), code, "unsupported") + assert len(deps) == 0 + + +class TestDependencyGraphBuilder: + """Tests for DependencyGraphBuilder class.""" + + def setup_method(self) -> None: + self.graph = DependencyGraphBuilder() + + def test_add_file(self) -> None: + self.graph.add_file(Path("main.py"), "python", 100, 10, 2, 1) + assert self.graph.graph.number_of_nodes() == 1 + assert Path("main.py") in self.graph.graph.nodes() + + def test_add_dependency(self) -> None: + self.graph.add_file(Path("a.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("b.py"), "python", 60, 6, 1, 0) + + dep = Dependency( + source_file=Path("a.py"), + target_file=Path("b.py"), + import_statement="import b", + import_type="import" + ) + self.graph.add_dependency(dep) + + assert self.graph.graph.has_edge(Path("a.py"), Path("b.py")) + + def test_build_from_analysis(self) -> None: + analysis_result = { + "files": [ + {"path": "main.py", "language": "python", "size": 100, "lines": 10, "functions": ["main"], "classes": []}, + {"path": "utils.py", "language": "python", "size": 50, "lines": 5, "functions": ["helper"], "classes": []} + ], + "dependencies": [ + {"source": "main.py", "target": "utils.py", "type": "import"} + ] + } + self.graph.build_from_analysis(analysis_result) + + assert self.graph.graph.number_of_nodes() == 2 + assert self.graph.graph.has_edge(Path("main.py"), Path("utils.py")) + + def test_find_cycles(self) -> None: + self.graph.add_file(Path("a.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("b.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("c.py"), "python", 50, 5, 1, 0) + + dep1 = Dependency(Path("a.py"), Path("b.py"), "import b", "import") + dep2 = Dependency(Path("b.py"), Path("c.py"), "import c", "import") + dep3 = Dependency(Path("c.py"), Path("a.py"), "import a", "import") + + self.graph.add_dependency(dep1) + self.graph.add_dependency(dep2) + self.graph.add_dependency(dep3) + + cycles = self.graph.find_cycles() + assert len(cycles) >= 1 + + def test_find_no_cycles(self) -> None: + self.graph.add_file(Path("a.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("b.py"), "python", 50, 5, 1, 0) + + dep = Dependency(Path("a.py"), Path("b.py"), "import b", "import") + self.graph.add_dependency(dep) + + cycles = self.graph.find_cycles() + assert len(cycles) == 0 + + def test_find_orphaned_files(self) -> None: + self.graph.add_file(Path("orphan.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("main.py"), "python", 100, 10, 2, 1) + self.graph.add_file(Path("used.py"), "python", 50, 5, 1, 0) + + dep = Dependency(Path("main.py"), Path("used.py"), "import used", "import") + self.graph.add_dependency(dep) + + orphaned = self.graph.find_orphaned_files() + assert Path("orphan.py") in orphaned + assert Path("main.py") not in orphaned + assert Path("used.py") not in orphaned + + def test_calculate_metrics(self) -> None: + self.graph.add_file(Path("main.py"), "python", 100, 10, 2, 1) + self.graph.add_file(Path("utils.py"), "python", 50, 5, 1, 0) + + dep = Dependency(Path("main.py"), Path("utils.py"), "import utils", "import") + self.graph.add_dependency(dep) + + metrics = self.graph.calculate_metrics() + + assert metrics.total_files == 2 + assert metrics.total_edges == 1 + assert metrics.density >= 0 + + def test_get_transitive_closure(self) -> None: + self.graph.add_file(Path("a.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("b.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("c.py"), "python", 50, 5, 1, 0) + + self.graph.add_dependency(Dependency(Path("a.py"), Path("b.py"), "import b", "import")) + self.graph.add_dependency(Dependency(Path("b.py"), Path("c.py"), "import c", "import")) + + dependents = self.graph.get_transitive_closure(Path("c.py")) + assert len(dependents) >= 0 + + def test_get_dependencies(self) -> None: + self.graph.add_file(Path("a.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("b.py"), "python", 50, 5, 1, 0) + self.graph.add_file(Path("c.py"), "python", 50, 5, 1, 0) + + self.graph.add_dependency(Dependency(Path("a.py"), Path("b.py"), "import b", "import")) + self.graph.add_dependency(Dependency(Path("a.py"), Path("c.py"), "import c", "import")) + + deps = self.graph.get_dependencies(Path("a.py")) + assert isinstance(deps, set)