File size: 3,134 Bytes
31e282f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | """Regression tests for graph.json deserialization integrity."""
from __future__ import annotations
import json
from pathlib import Path
import networkx as nx
from networkx.readwrite import node_link_data
from ctx.core.graph import resolve_graph
def _write_graph_file(tmp_path: Path, content: bytes | str) -> Path:
path = tmp_path / "graph.json"
if isinstance(content, str):
path.write_text(content, encoding="utf-8")
else:
path.write_bytes(content)
return path
class TestLoadGraphIntegrity:
"""load_graph must return an empty graph rather than raise on bad input."""
def test_file_not_found_returns_empty_graph(self, tmp_path: Path) -> None:
missing = tmp_path / "nonexistent" / "graph.json"
graph = resolve_graph.load_graph(path=missing)
assert isinstance(graph, nx.Graph)
assert graph.number_of_nodes() == 0
def test_invalid_encoding_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, b"\xff\xfe{bad encoding\x00")
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_truncated_json_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, '{"nodes": [{"id": "skill:foo"')
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_missing_nodes_key_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, json.dumps({"links": []}))
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_missing_links_key_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, json.dumps({"nodes": []}))
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_wrong_schema_type_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, json.dumps([{"id": "skill:foo"}]))
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_null_json_returns_empty_graph(self, tmp_path: Path) -> None:
path = _write_graph_file(tmp_path, "null")
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 0
def test_valid_graph_loads_correctly(self, tmp_path: Path) -> None:
source_graph = nx.Graph()
source_graph.add_node(
"skill:fastapi-pro",
label="fastapi-pro",
type="skill",
tags=["python"],
)
source_graph.add_node(
"skill:docker-expert",
label="docker-expert",
type="skill",
tags=["docker"],
)
source_graph.add_edge("skill:fastapi-pro", "skill:docker-expert", weight=1.0)
path = _write_graph_file(tmp_path, json.dumps(node_link_data(source_graph)))
graph = resolve_graph.load_graph(path=path)
assert graph.number_of_nodes() == 2
assert graph.number_of_edges() == 1
|