Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions scripts/formatters/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,12 +1155,13 @@ def _md_diff(data: Dict, lines: list) -> None:
removed = be.get("removed_count", 0)
changed = be.get("changed_count", 0)
lines.append(f"### Backend — +{added} / -{removed} / ~{changed}")
# `name`, not `fn`: _diff_backend() renames the field on the way out.
for node in be.get("added_nodes", [])[:5]:
lines.append(f"- + `{node.get('fn', '')}` ({node.get('file', '')})")
lines.append(f"- + `{node.get('name', '')}` ({node.get('file', '')})")
for node in be.get("removed_nodes", [])[:5]:
lines.append(f"- - `{node.get('fn', '')}`")
lines.append(f"- - `{node.get('name', '')}`")
for node in be.get("changed_nodes", [])[:5]:
lines.append(f"- ~ `{node.get('fn', '')}`")
lines.append(f"- ~ `{node.get('name', '')}`")
if be.get("new_dead"):
lines.append(f"- **New dead:** {len(be['new_dead'])}")
lines.append("")
Expand Down
98 changes: 98 additions & 0 deletions tests/test_markdown_diff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Tests for the markdown registry-diff renderer (issue #299).

_diff_backend() emits backend node entries keyed `name`, while _md_diff()
read `fn` and silently rendered every function name as an empty string.
These tests pin the producer/consumer contract on both sides.
"""

import os
import sys
import unittest

SCRIPT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts")
sys.path.insert(0, SCRIPT_DIR)

from diff_engine import _diff_backend # noqa: E402
from formatters.markdown import to_markdown # noqa: E402


def _render(backend, frontend=None):
return to_markdown(
{"status": "ok", "frontend": frontend or {}, "backend": backend}, "diff"
)


class TestBackendNodeNamesRendered(unittest.TestCase):
"""Backend function names must reach the markdown output."""

def test_added_node_name_is_rendered(self):
out = _render({
"added_count": 1, "removed_count": 0, "changed_count": 0,
"added_nodes": [{"name": "freshFn", "file": "a.py", "status": "active"}],
"removed_nodes": [], "changed_nodes": [],
})
self.assertIn("freshFn", out)
self.assertIn("a.py", out)
self.assertNotIn("- + ``", out)

def test_removed_node_name_is_rendered(self):
out = _render({
"added_count": 0, "removed_count": 1, "changed_count": 0,
"added_nodes": [], "changed_nodes": [],
"removed_nodes": [{"name": "goneFn", "file": "a.py"}],
})
self.assertIn("goneFn", out)
self.assertNotIn("- - ``", out)

def test_changed_node_name_is_rendered(self):
out = _render({
"added_count": 0, "removed_count": 0, "changed_count": 1,
"added_nodes": [], "removed_nodes": [],
"changed_nodes": [
{"name": "movedFn", "file": "a.py",
"ref_count": {"from": 2, "to": 1}}
],
})
self.assertIn("movedFn", out)
self.assertNotIn("- ~ ``", out)


class TestContractWithProducer(unittest.TestCase):
"""Render real _diff_backend() output, not a hand-written stand-in."""

def test_real_diff_backend_output_renders_names(self):
old = {
"nodes": [{"id": "a.py:1", "fn": "goneFn", "file": "a.py",
"ref_count": 1, "status": "active"}],
"edges": [],
}
new = {
"nodes": [{"id": "a.py:9", "fn": "freshFn", "file": "a.py",
"ref_count": 1, "status": "active"}],
"edges": [],
}

out = _render(_diff_backend(old, new))

self.assertIn("freshFn", out)
self.assertIn("goneFn", out)


class TestFrontendNotRegressed(unittest.TestCase):
"""The frontend block already read `name` correctly — keep it that way."""

def test_frontend_class_names_still_rendered(self):
out = _render(
{},
frontend={
"added_count": 1, "removed_count": 0, "changed_count": 0,
"added_classes": [{"name": "btn-primary", "status": "active"}],
"removed_classes": [], "changed_classes": [],
"added_ids": [], "removed_ids": [], "changed_ids": [],
},
)
self.assertIn("btn-primary", out)


if __name__ == "__main__":
unittest.main()
Loading