|
| 1 | +import json |
| 2 | +import subprocess |
| 3 | +import sys |
| 4 | +from pathlib import Path |
| 5 | + |
| 6 | +from conftest_v2 import assert_conformant |
| 7 | + |
| 8 | + |
| 9 | +def _run(proj, level): |
| 10 | + out = subprocess.run( |
| 11 | + [sys.executable, "-m", "codeanalyzer", "-i", str(proj), "-a", str(level), "--no-venv"], |
| 12 | + capture_output=True, text=True, check=True, |
| 13 | + ).stdout |
| 14 | + return json.loads(out) |
| 15 | + |
| 16 | + |
| 17 | +def _callables(app): |
| 18 | + def wc(c): |
| 19 | + yield c |
| 20 | + for ic in (c.get("inner_callables") or {}).values(): |
| 21 | + yield from wc(ic) |
| 22 | + for cl in (c.get("inner_classes") or {}).values(): |
| 23 | + yield from wcl(cl) |
| 24 | + |
| 25 | + def wcl(cl): |
| 26 | + for m in (cl.get("methods") or {}).values(): |
| 27 | + yield from wc(m) |
| 28 | + for ic in (cl.get("inner_classes") or {}).values(): |
| 29 | + yield from wcl(ic) |
| 30 | + |
| 31 | + for mod in app["symbol_table"].values(): |
| 32 | + for fn in (mod.get("functions") or {}).values(): |
| 33 | + yield from wc(fn) |
| 34 | + for cl in (mod.get("classes") or {}).values(): |
| 35 | + yield from wcl(cl) |
| 36 | + |
| 37 | + |
| 38 | +def test_l1_subset_of_l2(tmp_path): |
| 39 | + proj = tmp_path / "proj" |
| 40 | + proj.mkdir() |
| 41 | + (proj / "m.py").write_text("def g():\n return 1\ndef f():\n return g()\n", encoding="utf-8") |
| 42 | + l1, l2 = _run(proj, 1), _run(proj, 2) |
| 43 | + assert_conformant(l1, max_level=1) |
| 44 | + assert_conformant(l2, max_level=2) |
| 45 | + a1, a2 = l1["application"], l2["application"] |
| 46 | + # every module + callable id present at L1 is present at L2 |
| 47 | + ids1 = {c["id"] for c in _callables(a1)} |
| 48 | + ids2 = {c["id"] for c in _callables(a2)} |
| 49 | + assert ids1 <= ids2, "L2 dropped a callable present at L1" |
| 50 | + # every L1 body node key is present at L2 (callee may refine null→id) |
| 51 | + for c1 in _callables(a1): |
| 52 | + c2 = next(c for c in _callables(a2) if c["id"] == c1["id"]) |
| 53 | + assert set(c1.get("body", {})) <= set(c2.get("body", {})), \ |
| 54 | + f"L2 dropped a body node from {c1['id']}" |
0 commit comments