#!/usr/bin/env python3 """Tests for dependency_graph.py — transitive closure and deep chain detection.""" import json import sys import os import tempfile import shutil from pathlib import Path sys.path.insert(0, os.path.dirname(__file__) or ".") import importlib.util spec = importlib.util.spec_from_file_location( "dg", os.path.join(os.path.dirname(__file__) or ".", "dependency_graph.py") ) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) transitive_closure = mod.transitive_closure find_deep_chains = mod.find_deep_chains detect_cycles = mod.detect_cycles def make_graph(edges: dict[str, list[str]]) -> dict: """Build graph dict in expected format: {repo: {"dependencies": [...]}}.""" return { node: {"dependencies": sorted(deps), "files_scanned": 1} for node, deps in edges.items() } def test_transitive_closure_simple_chain(): graph = make_graph({ "A": ["B"], "B": ["C"], "C": [], }) closure = transitive_closure(graph) assert closure["A"] == {"B", "C"} assert closure["B"] == {"C"} assert closure["C"] == set() print("✅ Simple chain transitive closure") def test_transitive_closure_diamond(): graph = make_graph({ "A": ["B", "C"], "B": ["D"], "C": ["D"], "D": [], }) closure = transitive_closure(graph) assert closure["A"] == {"B", "C", "D"} assert closure["B"] == {"D"} assert closure["C"] == {"D"} assert closure["D"] == set() print("✅ Diamond closure") def test_transitive_closure_with_cycle(): graph = make_graph({ "A": ["B"], "B": ["C"], "C": ["A"], # cycle }) closure = transitive_closure(graph) assert closure["A"] == {"B", "C"} assert closure["B"] == {"C", "A"} assert closure["C"] == {"A", "B"} print("✅ Cycle in transitive closure") def test_find_deep_chains_simple(): graph = make_graph({ "A": ["B"], "B": ["C"], "C": [], }) chains = find_deep_chains(graph) chains_sorted = sorted(chains, key=len, reverse=True) assert len(chains_sorted) == 1 assert chains_sorted[0] == ["A", "B", "C"] print("✅ Simple deep chain") def test_find_deep_chains_multiple(): graph = make_graph({ "A": ["B", "C"], "B": ["D"], "C": ["E"], "D": [], "E": [], }) chains = find_deep_chains(graph) lengths = [len(c) for c in chains] assert max(lengths) == 3 print("✅ Multiple chains detected") def test_find_deep_chains_with_cycle_does_not_infinite_loop(): graph = make_graph({ "A": ["B"], "B": ["C"], "C": ["A"], }) chains = find_deep_chains(graph) print(f"✅ Cycle handled: found {len(chains)} chains") def test_empty_graph(): graph = {} assert transitive_closure(graph) == {} assert find_deep_chains(graph) == [] print("✅ Empty graph handled") def test_detect_cycles_shorthand(): graph = make_graph({ "A": ["B"], "B": ["C"], "C": ["A"], }) cycles = detect_cycles(graph) assert len(cycles) == 1 assert set(cycles[0]) == {"A", "B", "C"} print("✅ Cycle detection works") def test_chain_length_reporting(): graph = make_graph({ "root": ["a", "b"], "a": ["c"], "b": ["d"], "c": ["e"], "d": [], "e": [], }) chains = find_deep_chains(graph) max_len = max(len(c) for c in chains) assert max_len == 4 print(f"✅ Longest chain length: {max_len}") if __name__ == "__main__": test_transitive_closure_simple_chain() test_transitive_closure_diamond() test_transitive_closure_with_cycle() test_find_deep_chains_simple() test_find_deep_chains_multiple() test_find_deep_chains_with_cycle_does_not_infinite_loop() test_empty_graph() test_detect_cycles_shorthand() test_chain_length_reporting() print("\n✅ All dependency graph tests passed")