143 lines
5.1 KiB
Python
143 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Unit tests for check_web_route_parity parser helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from scripts.check_web_route_parity import build_report, parse_frontend_routes, write_report_json
|
|
|
|
|
|
class ParseFrontendRoutesTest(unittest.TestCase):
|
|
def test_detects_direct_calls(self) -> None:
|
|
source = """
|
|
async function refresh() {
|
|
await requestJson("/api/status");
|
|
await requestJson("/api/control", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ action: "CALL" }),
|
|
});
|
|
}
|
|
"""
|
|
routes = parse_frontend_routes(source)
|
|
self.assertIn(("GET", "/api/status"), routes)
|
|
self.assertIn(("POST", "/api/control"), routes)
|
|
|
|
def test_detects_calls_inside_promise_all(self) -> None:
|
|
source = """
|
|
const [wifi, mqtt, espnow, peers] = await Promise.all([
|
|
requestJson("/api/network/wifi"),
|
|
requestJson("/api/network/mqtt"),
|
|
requestJson("/api/network/espnow"),
|
|
requestJson("/api/network/espnow/peer"),
|
|
]);
|
|
"""
|
|
routes = parse_frontend_routes(source)
|
|
self.assertIn(("GET", "/api/network/wifi"), routes)
|
|
self.assertIn(("GET", "/api/network/mqtt"), routes)
|
|
self.assertIn(("GET", "/api/network/espnow"), routes)
|
|
self.assertIn(("GET", "/api/network/espnow/peer"), routes)
|
|
|
|
def test_handles_nested_parentheses_in_payload(self) -> None:
|
|
source = """
|
|
await requestJson("/api/network/mqtt/publish", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
topic: "rtc/test",
|
|
payload: JSON.stringify({ ping: true }),
|
|
}),
|
|
});
|
|
"""
|
|
routes = parse_frontend_routes(source)
|
|
self.assertIn(("POST", "/api/network/mqtt/publish"), routes)
|
|
|
|
|
|
class ReportParityJsonTest(unittest.TestCase):
|
|
def test_build_report_has_expected_structure(self) -> None:
|
|
backend_routes = {("GET", "/api/status"), ("POST", "/api/control")}
|
|
frontend_routes = {("GET", "/api/status"), ("POST", "/api/control")}
|
|
report = build_report(
|
|
backend_routes=backend_routes,
|
|
frontend_routes=frontend_routes,
|
|
missing_in_backend=set(),
|
|
unused_backend=set(),
|
|
strict_unused_backend=False,
|
|
status="pass",
|
|
)
|
|
|
|
self.assertEqual(report["backend_count"], 2)
|
|
self.assertEqual(report["frontend_count"], 2)
|
|
self.assertEqual(report["status"], "pass")
|
|
self.assertIn("backend_routes", report)
|
|
self.assertIn("frontend_routes", report)
|
|
self.assertIn("missing_in_backend", report)
|
|
self.assertIn("unused_backend", report)
|
|
self.assertFalse(report["strict_unused_backend"])
|
|
|
|
def test_build_report_routes_are_stably_sorted(self) -> None:
|
|
backend_routes = {
|
|
("POST", "/api/network/mqtt/connect"),
|
|
("GET", "/api/status"),
|
|
("DELETE", "/api/network/espnow/peer"),
|
|
}
|
|
report = build_report(
|
|
backend_routes=backend_routes,
|
|
frontend_routes=set(),
|
|
missing_in_backend=set(),
|
|
unused_backend=backend_routes,
|
|
strict_unused_backend=True,
|
|
status="fail",
|
|
)
|
|
|
|
self.assertEqual(
|
|
report["backend_routes"],
|
|
[
|
|
{"method": "DELETE", "path": "/api/network/espnow/peer"},
|
|
{"method": "POST", "path": "/api/network/mqtt/connect"},
|
|
{"method": "GET", "path": "/api/status"},
|
|
],
|
|
)
|
|
|
|
def test_mismatch_report_marks_fail_and_lists_missing(self) -> None:
|
|
backend_routes = {("GET", "/api/status")}
|
|
frontend_routes = {("GET", "/api/status"), ("POST", "/api/control")}
|
|
missing = frontend_routes - backend_routes
|
|
report = build_report(
|
|
backend_routes=backend_routes,
|
|
frontend_routes=frontend_routes,
|
|
missing_in_backend=missing,
|
|
unused_backend=backend_routes - frontend_routes,
|
|
strict_unused_backend=False,
|
|
status="fail",
|
|
)
|
|
|
|
self.assertEqual(report["status"], "fail")
|
|
self.assertEqual(
|
|
report["missing_in_backend"],
|
|
[{"method": "POST", "path": "/api/control"}],
|
|
)
|
|
|
|
def test_write_report_json_writes_valid_json(self) -> None:
|
|
report = build_report(
|
|
backend_routes={("GET", "/api/status")},
|
|
frontend_routes={("GET", "/api/status")},
|
|
missing_in_backend=set(),
|
|
unused_backend=set(),
|
|
strict_unused_backend=False,
|
|
status="pass",
|
|
)
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path = Path(tmp) / "route_parity_report.json"
|
|
write_report_json(path, report)
|
|
loaded = json.loads(path.read_text(encoding="utf-8"))
|
|
self.assertEqual(loaded["status"], "pass")
|
|
self.assertEqual(loaded["backend_count"], 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|