hatchimera / tests /test_assembler.py
arkai2025's picture
feat(edit): parts fuse and redistribute instead of stacking
e8d38ed
Raw
History Blame Contribute Delete
3.83 kB
from buddy_fusion.assembler import bbox, assemble_part
# A 2x2x2 cube centered at origin, sitting on the ground.
CUBE = [{"x": 0, "y": 0, "z": 0, "w": 2, "h": 2, "d": 2, "color": "#888888"}]
def test_bbox_center_x_bottom_y():
minx, maxx, miny, maxy, minz, maxz = bbox(CUBE)
assert (minx, maxx) == (-1, 1)
assert (miny, maxy) == (0, 2)
assert (minz, maxz) == (-1, 1)
def test_assemble_appends_and_keeps_original():
out = assemble_part(CUBE, "horns", "top", 1, None)
assert out[: len(CUBE)] == CUBE # original preserved, prepended
assert len(out) > len(CUBE) # part boxes appended
def test_top_anchor_sits_on_top():
out = assemble_part(CUBE, "horns", "top", 1, None)
added = out[len(CUBE):]
assert min(b["y"] for b in added) >= 2 # at or above the creature's max-y
def test_symmetric_part_is_mirrored():
out = assemble_part(CUBE, "horns", "top", 1, None)
added = out[len(CUBE):]
xs = {b["x"] for b in added}
assert any(x < 0 for x in xs) and any(x > 0 for x in xs) # both sides present
def test_scale_enlarges_part_footprint():
small = assemble_part(CUBE, "house", "rear", 1, None)[len(CUBE):]
big = assemble_part(CUBE, "house", "rear", 2, None)[len(CUBE):]
assert max(b["w"] for b in big) >= max(b["w"] for b in small)
def test_color_override_recolors_added_boxes():
out = assemble_part(CUBE, "house", "rear", 1, "#ff0000")
added = out[len(CUBE):]
assert all(b["color"] == "#ff0000" for b in added)
def test_unknown_part_returns_original_unchanged():
assert assemble_part(CUBE, "nope", "top", 1, None) == CUBE
def _cell_count(boxes):
return sum(b["w"] * b["h"] * b["d"] for b in boxes)
def test_float_scale_grows_cell_count():
one = assemble_part(CUBE, "house", "rear", 1.0, None)[len(CUBE):]
big = assemble_part(CUBE, "house", "rear", 1.5, None)[len(CUBE):]
assert _cell_count(big) > _cell_count(one)
def test_count_distributes_more_instances():
one = assemble_part(CUBE, "tail", "rear", 1, None, count=1)[len(CUBE):]
three = assemble_part(CUBE, "tail", "rear", 1, None, count=3)[len(CUBE):]
assert _cell_count(three) > _cell_count(one) * 2 # roughly 3x the geometry
def test_rotation_preserves_cell_count():
base = assemble_part(CUBE, "horns", "top", 1, None)[len(CUBE):]
rot = assemble_part(CUBE, "horns", "top", 1, None, rotation=("y", 1))[len(CUBE):]
assert _cell_count(rot) == _cell_count(base) # rotation moves cells, never drops them
BIG = [{"x": 0, "y": 0, "z": 0, "w": 6, "h": 6, "d": 6, "color": "#caa06f"}]
def test_repeated_add_accumulates_not_stacks():
once = assemble_part(BIG, "wing_bird", "left", 1, None)
twice = assemble_part(once, "wing_bird", "left", 1, None)
p1 = [b for b in once if b.get("_part") == "wing_bird"]
p2 = [b for b in twice if b.get("_part") == "wing_bird"]
assert p1[0]["_pc"] == 1 and p2[0]["_pc"] == 2 # instance count accumulates
assert _cell_count(p2) == 2 * _cell_count(p1) # two instances, not one piled twice
# the second add re-distributes along z (front-back), not the same spot
assert len({b["z"] for b in p2}) > len({b["z"] for b in p1})
def test_symmetric_part_straddles_both_faces():
out = assemble_part(BIG, "wing_bird", "left", 1, None)
added = [b for b in out if b.get("_part") == "wing_bird"]
assert any(b["x"] < 0 for b in added) and any(b["x"] > 0 for b in added) # both sides
def test_distribution_hugs_body_extent():
# four instances stay within (roughly) the body's z footprint, not flung far out
out = assemble_part(BIG, "wing_bird", "left", 1, None, count=4)
zs = [b["z"] for b in out if b.get("_part") == "wing_bird"]
assert min(zs) >= -6 and max(zs) <= 6 # body z is -3..3; parts fan within a tight margin