Spaces:
Running
Running
| """Phase J2 — kernel exposure of the assembly API (SPEC_ASSEMBLY.md §6, §8). | |
| A generator may use the injected `asm` helpers; it still cannot import anything | |
| outside the allowlist (asm is injected, not imported). | |
| """ | |
| import sys | |
| from pathlib import Path | |
| import pytest | |
| ROOT = Path(__file__).resolve().parent.parent | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| from geometry import kernel, metrics, repair # noqa: E402 | |
| GEN_ASM = ''' | |
| def build(p): | |
| cyl = asm.cylinder(r=1.0, h=2.0, name="cylinder") | |
| cone = asm.cone(r=1.0, h=1.5, name="cone") | |
| asm.attach(cone, "base", cyl, "top") | |
| return asm.combine([cyl, cone]) | |
| ''' | |
| # A generator that tries to reach the assembly module by IMPORT (not the injected | |
| # asm) must still be rejected by the allowlist. | |
| GEN_IMPORT_GEOMETRY = ''' | |
| import geometry | |
| def build(p): | |
| return [[0,0,0],[1,0,0],[0,1,0]], [[0,1,2,"x"]] | |
| ''' | |
| def test_asm_generator_runs_through_kernel(): | |
| V, F = kernel.run(GEN_ASM) | |
| assert len(V) > 8 and len(F) > 8 | |
| cids = {f[3] for f in F} | |
| assert "cylinder" in cids and "cone" in cids # two joined components | |
| v, f = repair.repair(V, F, "composite") | |
| assert metrics.passes(v, f, "composite")[0] | |
| def test_asm_parts_are_joined(): | |
| # After mating, the cone base ring sits on the cylinder top — i.e. the meshes | |
| # actually connect (not two disjoint blobs floating apart). | |
| V, F = kernel.run(GEN_ASM) | |
| ys = sorted(v[1] for v in V) | |
| # cylinder spans y∈[-1,1]; cone sits above with apex highest, contiguous. | |
| assert min(ys) < -0.9 and max(ys) > 1.0 | |
| def test_generator_cannot_import_geometry(): | |
| with pytest.raises(kernel.KernelError) as e: | |
| kernel.run(GEN_IMPORT_GEOMETRY) | |
| assert "disallowed import" in str(e.value) | |
| def test_plain_generator_still_works(): | |
| # asm injection must not break a generator that doesn't use it. | |
| code = ("def build(p):\n" | |
| " v=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]]\n" | |
| " return v,[[4,0,2,'f'],[4,2,1,'f'],[4,1,3,'f'],[4,3,0,'f']," | |
| "[5,2,0,'f'],[5,1,2,'f'],[5,3,1,'f'],[5,0,3,'f']]\n") | |
| V, F = kernel.run(code) | |
| assert len(V) == 6 and len(F) == 8 | |