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