1
0
Fork 0
Code Issues Pull requests Projects Releases 2 Packages Wiki Activity Actions Pages

Make dependency validation linear

This commit is contained in:
Andraxion 2026-07-29 03:45:09 -04:00
parent 7e0eff347c
commit 3bee200234
4 changed files with 152 additions and 18 deletions

View file

@ -8,7 +8,10 @@ import sqlite3
import sys
import tempfile
import unittest
from collections.abc import Iterator
from dataclasses import replace
from pathlib import Path
from typing import TypeVar, cast
from unittest import mock
ROOT = Path(__file__).resolve().parents[1]
@ -18,9 +21,26 @@ from docforge.cli import main # noqa: E402
from docforge.context import compile_context # noqa: E402
from docforge.errors import DocForgeError # noqa: E402
from docforge.index import ProjectIndex # noqa: E402
from docforge.project import Project # noqa: E402
from docforge.models import Edge # noqa: E402
from docforge.project import Project, validate_graph # noqa: E402
FIXTURES = ROOT / "tests" / "fixtures"
T = TypeVar("T")
class CountingTuple(tuple[T, ...]):
"""Count complete iteration passes without changing tuple behavior."""
iterations: int
def __new__(cls, values: tuple[T, ...]) -> CountingTuple[T]:
instance = super().__new__(cls, values)
instance.iterations = 0
return instance
def __iter__(self) -> Iterator[T]:
self.iterations += 1
return super().__iter__()
class DocForgeCoreTests(unittest.TestCase):
@ -149,6 +169,31 @@ class DocForgeCoreTests(unittest.TestCase):
with self.assertRaisesRegex(DocForgeError, "cycle"):
Project.open(root).load()
def test_graph_validation_uses_a_bounded_number_of_edge_passes(self) -> None:
snapshot = Project.open(FIXTURES / "alpha").load()
nodes = tuple(
replace(
snapshot.nodes[0],
node_id=f"linear.node-{index:05d}",
source_path=f"docs/node-{index:05d}.md",
)
for index in range(2_000)
)
edges = CountingTuple(
tuple(
Edge(
f"linear.node-{index:05d}",
"depends_on",
f"linear.node-{index - 1:05d}",
)
for index in range(1, len(nodes))
)
)
validate_graph(nodes, cast(tuple[Edge, ...], edges))
self.assertLessEqual(edges.iterations, 4)
def test_index_build_is_repeatable_and_validates_every_row(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = self.copy_fixture("alpha", Path(directory))