File size: 2,192 Bytes
2ce2625
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""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