"""TaskGraph(黑板/工作记忆)单元测试——拓扑排序契约。 契约(与 2026-09 优化前行为一致,复杂度 O(V²logV) -> O(V+E)): - 依赖在前;初始就绪层按插入序稳定输出 - 未知依赖 id 忽略;重复依赖不重复产出 - 循环依赖:剩余节点按插入序兜底追加(不崩溃) """ from router_system.memory import TaskGraph, TaskNode def _node(nid: str, deps=()) -> TaskNode: return TaskNode(id=nid, kind="solve", domain="general", query="q", deps=list(deps)) def test_topo_chain_order(): g = TaskGraph() g.add_node(_node("a")) g.add_node(_node("b", ["a"])) g.add_node(_node("c", ["b"])) assert [n.id for n in g.topo_order()] == ["a", "b", "c"] def test_topo_diamond_initial_ready_by_insertion(): """菱形依赖:初始就绪层按插入序。""" g = TaskGraph() g.add_node(_node("s")) g.add_node(_node("y", ["s"])) # 先插入 y g.add_node(_node("x", ["s"])) g.add_node(_node("t", ["x", "y"])) order = [n.id for n in g.topo_order()] assert order == ["s", "y", "x", "t"] def test_topo_independent_nodes_keep_insertion_order(): g = TaskGraph() g.add_node(_node("n3")) g.add_node(_node("n1")) g.add_node(_node("n2")) assert [n.id for n in g.topo_order()] == ["n3", "n1", "n2"] def test_topo_unknown_dep_ignored(): g = TaskGraph() g.add_node(_node("a", ["不存在的依赖"])) assert [n.id for n in g.topo_order()] == ["a"] def test_topo_cycle_fallback_by_insertion(): g = TaskGraph() g.add_node(_node("p", ["q"])) g.add_node(_node("q", ["p"])) g.add_node(_node("r")) order = [n.id for n in g.topo_order()] # r 无依赖先行;p/q 成环按插入序兜底 assert order == ["r", "p", "q"] def test_topo_duplicate_deps_counted_once_in_output(): """重复依赖边不产生重复输出节点。""" g = TaskGraph() g.add_node(_node("a")) g.add_node(_node("b", ["a", "a"])) assert [n.id for n in g.topo_order()] == ["a", "b"]