219 lines
7.6 KiB
Python
219 lines
7.6 KiB
Python
# model3d_test.py - Unit test for Model3D 3D model resource
|
|
|
|
import mcrfpy
|
|
import sys
|
|
|
|
def test_model3d_cube():
|
|
"""Test Model3D.cube() creates valid model"""
|
|
cube = mcrfpy.Model3D.cube(2.0)
|
|
|
|
assert cube.name == "cube", f"Expected name='cube', got '{cube.name}'"
|
|
assert cube.vertex_count == 24, f"Expected 24 vertices, got {cube.vertex_count}"
|
|
assert cube.triangle_count == 12, f"Expected 12 triangles, got {cube.triangle_count}"
|
|
assert cube.has_skeleton == False, f"Expected has_skeleton=False, got {cube.has_skeleton}"
|
|
assert cube.mesh_count == 1, f"Expected 1 mesh, got {cube.mesh_count}"
|
|
|
|
# Check bounds for size=2.0 cube
|
|
bounds = cube.bounds
|
|
assert bounds is not None, "Bounds should not be None"
|
|
min_b, max_b = bounds
|
|
assert min_b == (-1.0, -1.0, -1.0), f"Expected min=(-1,-1,-1), got {min_b}"
|
|
assert max_b == (1.0, 1.0, 1.0), f"Expected max=(1,1,1), got {max_b}"
|
|
|
|
print("[PASS] test_model3d_cube")
|
|
|
|
def test_model3d_cube_default_size():
|
|
"""Test Model3D.cube() with default size"""
|
|
cube = mcrfpy.Model3D.cube()
|
|
|
|
# Default size is 1.0, so bounds should be -0.5 to 0.5
|
|
bounds = cube.bounds
|
|
min_b, max_b = bounds
|
|
assert abs(min_b[0] - (-0.5)) < 0.001, f"Expected min.x=-0.5, got {min_b[0]}"
|
|
assert abs(max_b[0] - 0.5) < 0.001, f"Expected max.x=0.5, got {max_b[0]}"
|
|
|
|
print("[PASS] test_model3d_cube_default_size")
|
|
|
|
def test_model3d_plane():
|
|
"""Test Model3D.plane() creates valid model"""
|
|
plane = mcrfpy.Model3D.plane(4.0, 2.0, 2)
|
|
|
|
assert plane.name == "plane", f"Expected name='plane', got '{plane.name}'"
|
|
# 2 segments = 3x3 grid = 9 vertices
|
|
assert plane.vertex_count == 9, f"Expected 9 vertices, got {plane.vertex_count}"
|
|
# 2x2 quads = 8 triangles
|
|
assert plane.triangle_count == 8, f"Expected 8 triangles, got {plane.triangle_count}"
|
|
assert plane.has_skeleton == False, f"Expected has_skeleton=False"
|
|
|
|
# Bounds should be width/2, 0, depth/2
|
|
bounds = plane.bounds
|
|
min_b, max_b = bounds
|
|
assert abs(min_b[0] - (-2.0)) < 0.001, f"Expected min.x=-2, got {min_b[0]}"
|
|
assert abs(max_b[0] - 2.0) < 0.001, f"Expected max.x=2, got {max_b[0]}"
|
|
assert abs(min_b[2] - (-1.0)) < 0.001, f"Expected min.z=-1, got {min_b[2]}"
|
|
assert abs(max_b[2] - 1.0) < 0.001, f"Expected max.z=1, got {max_b[2]}"
|
|
|
|
print("[PASS] test_model3d_plane")
|
|
|
|
def test_model3d_plane_default():
|
|
"""Test Model3D.plane() with default parameters"""
|
|
plane = mcrfpy.Model3D.plane()
|
|
|
|
# Default is 1x1 with 1 segment = 4 vertices, 2 triangles
|
|
assert plane.vertex_count == 4, f"Expected 4 vertices, got {plane.vertex_count}"
|
|
assert plane.triangle_count == 2, f"Expected 2 triangles, got {plane.triangle_count}"
|
|
|
|
print("[PASS] test_model3d_plane_default")
|
|
|
|
def test_model3d_sphere():
|
|
"""Test Model3D.sphere() creates valid model"""
|
|
sphere = mcrfpy.Model3D.sphere(1.0, 8, 6)
|
|
|
|
assert sphere.name == "sphere", f"Expected name='sphere', got '{sphere.name}'"
|
|
# vertices = (segments+1) * (rings+1) = 9 * 7 = 63
|
|
assert sphere.vertex_count == 63, f"Expected 63 vertices, got {sphere.vertex_count}"
|
|
# triangles = 2 * segments * rings = 2 * 8 * 6 = 96
|
|
assert sphere.triangle_count == 96, f"Expected 96 triangles, got {sphere.triangle_count}"
|
|
|
|
# Bounds should be radius in all directions
|
|
bounds = sphere.bounds
|
|
min_b, max_b = bounds
|
|
assert abs(min_b[0] - (-1.0)) < 0.001, f"Expected min.x=-1, got {min_b[0]}"
|
|
assert abs(max_b[0] - 1.0) < 0.001, f"Expected max.x=1, got {max_b[0]}"
|
|
|
|
print("[PASS] test_model3d_sphere")
|
|
|
|
def test_model3d_sphere_default():
|
|
"""Test Model3D.sphere() with default parameters"""
|
|
sphere = mcrfpy.Model3D.sphere()
|
|
|
|
# Default radius=0.5, segments=16, rings=12
|
|
# vertices = 17 * 13 = 221
|
|
assert sphere.vertex_count == 221, f"Expected 221 vertices, got {sphere.vertex_count}"
|
|
# triangles = 2 * 16 * 12 = 384
|
|
assert sphere.triangle_count == 384, f"Expected 384 triangles, got {sphere.triangle_count}"
|
|
|
|
print("[PASS] test_model3d_sphere_default")
|
|
|
|
def test_model3d_empty():
|
|
"""Test creating empty Model3D"""
|
|
empty = mcrfpy.Model3D()
|
|
|
|
assert empty.name == "unnamed", f"Expected name='unnamed', got '{empty.name}'"
|
|
assert empty.vertex_count == 0, f"Expected 0 vertices, got {empty.vertex_count}"
|
|
assert empty.triangle_count == 0, f"Expected 0 triangles, got {empty.triangle_count}"
|
|
assert empty.mesh_count == 0, f"Expected 0 meshes, got {empty.mesh_count}"
|
|
|
|
print("[PASS] test_model3d_empty")
|
|
|
|
def test_model3d_repr():
|
|
"""Test Model3D string representation"""
|
|
cube = mcrfpy.Model3D.cube()
|
|
repr_str = repr(cube)
|
|
|
|
assert "Model3D" in repr_str, f"Expected 'Model3D' in repr, got {repr_str}"
|
|
assert "cube" in repr_str, f"Expected 'cube' in repr, got {repr_str}"
|
|
assert "24" in repr_str, f"Expected vertex count in repr, got {repr_str}"
|
|
|
|
print("[PASS] test_model3d_repr")
|
|
|
|
def test_entity3d_model_property():
|
|
"""Test Entity3D.model property"""
|
|
e = mcrfpy.Entity3D(pos=(0, 0))
|
|
|
|
# Initially no model
|
|
assert e.model is None, f"Expected model=None, got {e.model}"
|
|
|
|
# Assign model
|
|
cube = mcrfpy.Model3D.cube()
|
|
e.model = cube
|
|
assert e.model is not None, "Expected model to be set"
|
|
assert e.model.name == "cube", f"Expected model.name='cube', got {e.model.name}"
|
|
|
|
# Swap model
|
|
sphere = mcrfpy.Model3D.sphere()
|
|
e.model = sphere
|
|
assert e.model.name == "sphere", f"Expected model.name='sphere', got {e.model.name}"
|
|
|
|
# Clear model
|
|
e.model = None
|
|
assert e.model is None, f"Expected model=None after clearing"
|
|
|
|
print("[PASS] test_entity3d_model_property")
|
|
|
|
def test_entity3d_model_type_error():
|
|
"""Test Entity3D.model raises TypeError for invalid input"""
|
|
e = mcrfpy.Entity3D()
|
|
|
|
try:
|
|
e.model = "not a model"
|
|
print("[FAIL] test_entity3d_model_type_error: Expected TypeError")
|
|
return
|
|
except TypeError:
|
|
pass
|
|
|
|
try:
|
|
e.model = 123
|
|
print("[FAIL] test_entity3d_model_type_error: Expected TypeError")
|
|
return
|
|
except TypeError:
|
|
pass
|
|
|
|
print("[PASS] test_entity3d_model_type_error")
|
|
|
|
def test_entity3d_with_model_in_viewport():
|
|
"""Test Entity3D with model in a Viewport3D"""
|
|
vp = mcrfpy.Viewport3D()
|
|
vp.set_grid_size(16, 16)
|
|
|
|
# Create entity with model
|
|
cube = mcrfpy.Model3D.cube(0.5)
|
|
e = mcrfpy.Entity3D(pos=(8, 8))
|
|
e.model = cube
|
|
|
|
# Add to viewport
|
|
vp.entities.append(e)
|
|
|
|
# Verify model is preserved
|
|
retrieved = vp.entities[0]
|
|
assert retrieved.model is not None, "Expected model to be preserved"
|
|
assert retrieved.model.name == "cube", f"Expected model.name='cube', got {retrieved.model.name}"
|
|
|
|
print("[PASS] test_entity3d_with_model_in_viewport")
|
|
|
|
def run_all_tests():
|
|
"""Run all Model3D tests"""
|
|
tests = [
|
|
test_model3d_cube,
|
|
test_model3d_cube_default_size,
|
|
test_model3d_plane,
|
|
test_model3d_plane_default,
|
|
test_model3d_sphere,
|
|
test_model3d_sphere_default,
|
|
test_model3d_empty,
|
|
test_model3d_repr,
|
|
test_entity3d_model_property,
|
|
test_entity3d_model_type_error,
|
|
test_entity3d_with_model_in_viewport,
|
|
]
|
|
|
|
passed = 0
|
|
failed = 0
|
|
|
|
for test in tests:
|
|
try:
|
|
test()
|
|
passed += 1
|
|
except AssertionError as e:
|
|
print(f"[FAIL] {test.__name__}: {e}")
|
|
failed += 1
|
|
except Exception as e:
|
|
print(f"[ERROR] {test.__name__}: {type(e).__name__}: {e}")
|
|
failed += 1
|
|
|
|
print(f"\n=== Results: {passed} passed, {failed} failed ===")
|
|
return failed == 0
|
|
|
|
if __name__ == "__main__":
|
|
success = run_all_tests()
|
|
sys.exit(0 if success else 1)
|