fix(cpp): guard empty-normalize collapse for punctuation-only test names (#2594)
The #2751 recovery minted node ids via _make_id(stem, name); a punctuation-only name (TEST_CASE("***")) normalizes to empty, collapsing onto the bare file-stem id — colliding with the file namespace and swallowing every later such test under one id via seen_ids (#1899). Detect the collapse and fall back to a stable line-positional id so each stays distinct. Adds a regression test (also covers SCENARIO) and the CHANGELOG entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
54b3b78955
commit
e6b0efb66b
@@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu
|
||||
|
||||
## 0.9.44 (unreleased)
|
||||
|
||||
- Fix: doctest/Catch2 string-named test cases (`TEST_CASE("...")`, `SCENARIO`, `TEST_CASE_TEMPLATE`), which tree-sitter-cpp drops as ERROR nodes, are recovered as callable nodes contained by the file (#2594, thanks @ousamabenyounes); a punctuation-only test name gets a distinct line-positional id instead of collapsing onto the file-stem id.
|
||||
- Fix: `graphify affected` resolves an absolute-path seed against the repo root derived from the graph's own location instead of the current working directory, so a blast-radius query with an absolute seed run from anywhere (an editor, a script) no longer silently returns nothing; a seed outside the root still misses cleanly (#2706, thanks @ousamabenyounes).
|
||||
- Fix: a lazy CommonJS `require(...)` inside a function body (the idiom for breaking circular dependencies) now emits the same `imports_from`/`imports` dependency edges as a top-level require, attributed to the enclosing function, instead of being silently dropped; a dynamic `require(variable)` is still skipped (#2700, thanks @rajanpanth).
|
||||
- Fix: a JS/TS identifier bound by an import whose target resolves outside the scanned corpus (e.g. a `lucide-react` icon) is now shadowed, so using it as a value no longer fabricates an INFERRED `indirect_call` onto an unrelated same-named callable elsewhere in the corpus; a relative/in-corpus import still resolves to its real target (#2757, thanks @phudayyy).
|
||||
|
||||
@@ -1910,6 +1910,11 @@ def _augment_cpp_string_tests(path: Path, result: dict) -> dict:
|
||||
str_path = str(path)
|
||||
stem = _file_stem(path)
|
||||
file_nid = _make_id(str_path)
|
||||
# A test name that is all punctuation (TEST_CASE("***")) normalizes to empty,
|
||||
# so _make_id(stem, name) collapses onto this bare-stem id — colliding with
|
||||
# the file's namespace and silently swallowing every later such test under
|
||||
# one id (#1899). Detect that collapse and fall back to a line-positional id.
|
||||
stem_collapse_id = _make_id(stem)
|
||||
nodes = result.setdefault("nodes", [])
|
||||
edges = result.setdefault("edges", [])
|
||||
seen_ids = {n.get("id") for n in nodes}
|
||||
@@ -1918,6 +1923,8 @@ def _augment_cpp_string_tests(path: Path, result: dict) -> dict:
|
||||
test_name = m.group(1)
|
||||
line = source.count("\n", 0, m.start()) + 1
|
||||
test_nid = _make_id(stem, test_name)
|
||||
if test_nid == stem_collapse_id:
|
||||
test_nid = _make_id(stem, "test", f"L{line}")
|
||||
if test_nid in seen_ids:
|
||||
continue
|
||||
seen_ids.add(test_nid)
|
||||
|
||||
@@ -215,6 +215,31 @@ def test_cpp_recovers_doctest_string_named_test_cases():
|
||||
}
|
||||
assert test_ids and test_ids <= contained
|
||||
|
||||
|
||||
def test_cpp_string_tests_punctuation_only_names_stay_distinct(tmp_path):
|
||||
"""A punctuation-only test name normalizes to empty, so a naive
|
||||
``_make_id(stem, name)`` collapses onto the bare file-stem id — colliding
|
||||
with the file namespace and swallowing every later such test under one id
|
||||
(#1899). The guard gives each a distinct line-positional id."""
|
||||
f = tmp_path / "punct_tests.cpp"
|
||||
f.write_text(
|
||||
'TEST_CASE("***") { CHECK(1); }\n'
|
||||
'TEST_CASE("...") { CHECK(2); }\n'
|
||||
'SCENARIO("boots up") { REQUIRE(1); }\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
r = extract_cpp(f)
|
||||
from graphify.extract import _make_id, _file_stem
|
||||
stem_collapse = _make_id(_file_stem(f))
|
||||
tests = [n for n in r["nodes"] if n["label"].startswith('"')]
|
||||
ids = [n["id"] for n in tests]
|
||||
# both punctuation-only cases recovered, plus the SCENARIO macro
|
||||
assert '"***"' in {n["label"] for n in tests}
|
||||
assert '"..."' in {n["label"] for n in tests}
|
||||
assert '"boots up"' in {n["label"] for n in tests}
|
||||
assert len(set(ids)) == len(ids) # all distinct
|
||||
assert all(i != stem_collapse for i in ids) # none squats on the file stem
|
||||
|
||||
def test_cpp_finds_includes():
|
||||
r = extract_cpp(FIXTURES / "sample.cpp")
|
||||
assert "imports" in _relations(r)
|
||||
|
||||
Reference in New Issue
Block a user