Summary
The tests_for query pattern (and get_transitive_tests in graph.py) looks up TESTED_BY edges using target_qualified = <production_function>, but the parser stores these edges with source = production_function and target = test_function. Because the direction is inverted between build and query, tests_for never matches any TESTED_BY edges from the graph and silently falls back to naming-convention heuristics (test_{name} / Test{name}).
This means query_graph(pattern=\"tests_for\", target=\"...::add\") returns results only when a test happens to be named test_add or TestAdd, not when the parser actually discovered a TESTED_BY relationship.
Build side (parser.py)
In every parser path that handles test files, TESTED_BY edges are created by reversing a CALLS edge:
# code_review_graph/parser.py:977-993
if test_file:
test_qnames = set()
for n in nodes:
if n.is_test:
qn = self._qualify(n.name, n.file_path, n.parent_name)
test_qnames.add(qn)
for edge in list(edges):
if edge.kind == "CALLS" and edge.source in test_qnames:
edges.append(EdgeInfo(
kind="TESTED_BY",
source=edge.target, # production function
target=edge.source, # test function
file_path=edge.file_path,
line=edge.line,
))
So the stored edge is:
source_qualified = src/calc.py::add (production)
target_qualified = src/test_calc.py::test_add (test)
Query side (tools/query.py)
# code_review_graph/tools/query.py:295-308
elif pattern == "tests_for":
for e in store.get_edges_by_target(qn):
if e.kind == "TESTED_BY":
test = store.get_node(e.source_qualified)
qn is the production function. get_edges_by_target(qn) searches WHERE target_qualified = <production_function>. But the parser stored the production function in source_qualified, not target_qualified. Therefore this loop never yields any edges.
The same inverted assumption exists in graph.py:get_transitive_tests:
# code_review_graph/graph.py:418-430
for row in conn.execute(
\"SELECT source_qualified FROM edges \"
\"WHERE target_qualified = ? AND kind = 'TESTED_BY'\",
(qn,)
).fetchall():
Test data is also inconsistent
tests/test_tools.py:1165 creates TESTED_BY with source=\"auth.py::login\" (production) and target=\"tests/test_auth.py::test_login\" (test) — matching the parser.
tests/test_graph.py:382 creates TESTED_BY with source=test_qn (test) and target=callee_qn (production) — the opposite direction.
Expected behavior
tests_for should look up TESTED_BY edges by source (get_edges_by_source(qn)) because the parser stores the production function in source_qualified:
for e in store.get_edges_by_source(qn):
if e.kind == "TESTED_BY":
test = store.get_node(e.target_qualified) # target = test function
Alternatively, the parser could be changed to store source = test_function, target = production_function to match the current query convention. Either way, build and query must agree on the same direction.
Environment
- code-review-graph v2.3.5
- Python 3.10+
Summary
The
tests_forquery pattern (andget_transitive_testsingraph.py) looks upTESTED_BYedges usingtarget_qualified = <production_function>, but the parser stores these edges withsource = production_functionandtarget = test_function. Because the direction is inverted between build and query,tests_fornever matches anyTESTED_BYedges from the graph and silently falls back to naming-convention heuristics (test_{name}/Test{name}).This means
query_graph(pattern=\"tests_for\", target=\"...::add\")returns results only when a test happens to be namedtest_addorTestAdd, not when the parser actually discovered aTESTED_BYrelationship.Build side (parser.py)
In every parser path that handles test files,
TESTED_BYedges are created by reversing aCALLSedge:So the stored edge is:
source_qualified=src/calc.py::add(production)target_qualified=src/test_calc.py::test_add(test)Query side (tools/query.py)
qnis the production function.get_edges_by_target(qn)searchesWHERE target_qualified = <production_function>. But the parser stored the production function insource_qualified, nottarget_qualified. Therefore this loop never yields any edges.The same inverted assumption exists in
graph.py:get_transitive_tests:Test data is also inconsistent
tests/test_tools.py:1165createsTESTED_BYwithsource=\"auth.py::login\"(production) andtarget=\"tests/test_auth.py::test_login\"(test) — matching the parser.tests/test_graph.py:382createsTESTED_BYwithsource=test_qn(test) andtarget=callee_qn(production) — the opposite direction.Expected behavior
tests_forshould look upTESTED_BYedges by source (get_edges_by_source(qn)) because the parser stores the production function insource_qualified:Alternatively, the parser could be changed to store
source = test_function, target = production_functionto match the current query convention. Either way, build and query must agree on the same direction.Environment