From e7b698327cd91b371ff4fd43d1c117637224fded Mon Sep 17 00:00:00 2001 From: Himanshi Kalra Date: Thu, 17 Dec 2020 20:44:55 +0530 Subject: Updated and extended Regression Testing frameworks (Gsoc 2020) This revision contains the following changes- - Updated the existing testing framework for Modifiers for Regression Testing. - Tests for Physics modifiers and remaining Generate and Deform modifiers are added. - The existing `ModifierSpec` is updated with backward compatibility to support Physics Modifiers. - Now there is support for frame number and giving nested parameters for attributes. - Some Deform modifiers required Object Operators, e.g. "Bind" in Mesh Deform, so a new class was added to support that functionality. - A separate class for holding Particles System, they are tested by converting all the particles to mesh and joining it to the mesh they were added. - Updated the format to add tests for Bevel, Boolean and Operators as well. Reviewed By: zazizizou, mont29, campbellbarton Differential Revision: https://developer.blender.org/D8507 --- tests/python/CMakeLists.txt | 42 +++ tests/python/bevel_operator.py | 366 ++++++++++++++------ tests/python/boolean_operator.py | 48 ++- tests/python/deform_modifiers.py | 119 +++++++ tests/python/modifiers.py | 352 ++++++++++++------- tests/python/modules/mesh_test.py | 557 ++++++++++++++++++------------ tests/python/operators.py | 181 ++++++---- tests/python/physics_cloth.py | 28 +- tests/python/physics_dynamic_paint.py | 58 ++++ tests/python/physics_ocean.py | 54 +++ tests/python/physics_particle_instance.py | 56 +++ tests/python/physics_particle_system.py | 55 +++ tests/python/physics_softbody.py | 23 +- 13 files changed, 1395 insertions(+), 544 deletions(-) create mode 100644 tests/python/deform_modifiers.py create mode 100644 tests/python/physics_dynamic_paint.py create mode 100644 tests/python/physics_ocean.py create mode 100644 tests/python/physics_particle_instance.py create mode 100644 tests/python/physics_particle_system.py (limited to 'tests') diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 97f5df3ec09..bf949d66286 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -204,6 +204,48 @@ add_blender_test( --run-all-tests ) +add_blender_test( + physics_dynamic_paint + ${TEST_SRC_DIR}/physics/dynamic_paint_test.blend + --python ${TEST_PYTHON_DIR}/physics_dynamic_paint.py + -- + --run-all-tests +) + +add_blender_test( + deform_modifiers + ${TEST_SRC_DIR}/modeling/deform_modifiers.blend + --python ${TEST_PYTHON_DIR}/deform_modifiers.py + -- + --run-all-tests +) + +add_blender_test( + physics_ocean + ${TEST_SRC_DIR}/physics/ocean_test.blend + --python ${TEST_PYTHON_DIR}/physics_ocean.py + -- + --run-all-tests +) + + +add_blender_test( + physics_particle_system + ${TEST_SRC_DIR}/physics/physics_particle_test.blend + --python ${TEST_PYTHON_DIR}/physics_particle_system.py + -- + --run-all-tests +) + +# Particle Instance disabling currently broken in master +# add_blender_test( +# physics_particle_instance +# ${TEST_SRC_DIR}/physics/physics_particle_instance.blend +# --python ${TEST_PYTHON_DIR}/physics_particle_instance.py +# -- +# --run-all-tests +# ) + add_blender_test( constraints --python ${CMAKE_CURRENT_LIST_DIR}/bl_constraints.py diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py index 50f52b958f7..c732d437b57 100644 --- a/tests/python/bevel_operator.py +++ b/tests/python/bevel_operator.py @@ -27,151 +27,287 @@ import os import sys sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import OperatorTest +from modules.mesh_test import MeshTest, OperatorSpecEditMode, RunTest def main(): tests = [ # 0 - ['EDGE', {10}, 'Cube_test', 'Cube_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_2', 'bevel', {'offset': 0.2, 'offset_type': 'WIDTH'}], - ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_3', 'bevel', {'offset': 0.2, 'offset_type': 'DEPTH'}], - ['EDGE', {10}, 'Cube_test', 'Cube_result_4', 'bevel', {'offset': 0.4, 'segments': 2}], - ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_5', 'bevel', {'offset': 0.4, 'segments': 3}], + MeshTest('Cube_test_1', 'Cube_test', 'Cube_result_1', + + [OperatorSpecEditMode('bevel', + {'offset': 0.2}, 'EDGE', {10})]), + MeshTest('Cube_test_2', 'Cube_test', 'Cube_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'offset_type': 'WIDTH'}, 'EDGE', {10, 7}, )]), + MeshTest('Cube_test_3', 'Cube_test', 'Cube_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'offset_type': 'DEPTH'}, 'EDGE', {8, 10, 7}, )]), + MeshTest('Cube_test_4', 'Cube_test', 'Cube_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.4, 'segments': 2}, 'EDGE', {10}, )]), + MeshTest('Cube_test_5', 'Cube_test', 'Cube_result_5', + [OperatorSpecEditMode('bevel', {'offset': 0.4, 'segments': 3}, 'EDGE', {10, 7}, )]), # 5 - ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_6', 'bevel', {'offset': 0.4, 'segments': 4}], - ['EDGE', {0, 10, 4, 7}, 'Cube_test', 'Cube_result_7', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.2}], - ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_8', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.25}], - ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_9', 'bevel', {'offset': 0.4, 'segments': 6, 'profile': 0.9}], - ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_10', 'bevel', {'offset': 0.4, 'segments': 4, 'profile': 1.0}], + MeshTest('Cube_test_6', 'Cube_test', 'Cube_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.4, 'segments': 4}, 'EDGE', {8, 10, 7}, )]), + MeshTest('Cube_test_7', 'Cube_test', 'Cube_result_7', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 5, 'profile': 0.2}, 'EDGE', {0, 10, 4, 7}, )]), + MeshTest('Cube_test_8', 'Cube_test', 'Cube_result_8', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 5, 'profile': 0.25}, 'EDGE', {8, 10, 7}, )]), + MeshTest('Cube_test_9', 'Cube_test', 'Cube_result_9', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 6, 'profile': 0.9}, 'EDGE', {8, 10, 7}, )]), + MeshTest('Cube_test_10', 'Cube_test', 'Cube_result_10', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 4, 'profile': 1.0}, 'EDGE', {10, 7}, )]), # 10 - ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_11', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 1.0}], - ['EDGE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cube_test', 'Cube_result_12', 'bevel', - {'offset': 0.4, 'segments': 8}], - ['EDGE', {5}, 'Pyr4_test', 'Pyr4_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {2, 5}, 'Pyr4_test', 'Pyr4_result_2', 'bevel', {'offset': 0.2}], - ['EDGE', {2, 3, 5}, 'Pyr4_test', 'Pyr4_result_3', 'bevel', {'offset': 0.2}], + MeshTest('Cube_test_11', 'Cube_test', 'Cube_result_11', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 5, 'profile': 1.0}, 'EDGE', {8, 10, 7}, )]), + MeshTest("test 12", 'Cube_test', 'Cube_result_12', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 8}, 'EDGE', + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, )]), + MeshTest('Pyramid4_test_1', 'Pyr4_test', 'Pyr4_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {5}, )]), + MeshTest('Pyramid4_test_2', 'Pyr4_test', 'Pyr4_result_2', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {2, 5}, )]), + MeshTest('Pyramid4_test_3', 'Pyr4_test', 'Pyr4_result_3', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {2, 3, 5}, )]), # 15 - ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_4', 'bevel', {'offset': 0.2}], - ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_5', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {2, 3}, 'Pyr4_test', 'Pyr4_result_6', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_7', 'bevel', {'offset': 0.2, 'segments': 4, 'profile': 0.15}], - ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_8', 'bevel', {'offset': 0.75, 'segments': 4, 'affect': 'VERTICES'}], + MeshTest('Pyramid4_test_4', 'Pyr4_test', 'Pyr4_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {1, 2, 3, 5}, )]), + MeshTest('Pyramid4_test_5', 'Pyr4_test', 'Pyr4_result_5', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3}, 'EDGE', {1, 2, 3, 5}, )]), + MeshTest('Pyramid4_test_6', 'Pyr4_test', 'Pyr4_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {2, 3}, )]), + MeshTest('Pyramid4_test_7', 'Pyr4_test', 'Pyr4_result_7', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 4, 'profile': 0.15}, 'EDGE', {1, 2, 3, 5}, )]), + MeshTest('Pyramid4_test_8', 'Pyr4_test', 'Pyr4_result_8', + [OperatorSpecEditMode('bevel', + {'offset': 0.75, 'segments': 4, 'affect': 'VERTICES'}, 'VERT', {1}, )]), # 20 - ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_9', 'bevel', - {'offset': 0.75, 'segments': 3, 'affect': 'VERTICES', 'profile': 0.25}], - ['EDGE', {2, 3}, 'Pyr6_test', 'Pyr6_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {8, 2, 3}, 'Pyr6_test', 'Pyr6_result_2', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {0, 2, 3, 4, 6, 7, 9, 10, 11}, 'Pyr6_test', 'Pyr6_result_3', 'bevel', - {'offset': 0.2, 'segments': 4, 'profile': 0.8}], - ['EDGE', {8, 9, 3, 11}, 'Sept_test', 'Sept_result_1', 'bevel', {'offset': 0.1}], + MeshTest('Pyramid4_test_9', 'Pyr4_test', 'Pyr4_result_9', + [OperatorSpecEditMode('bevel', + {'offset': 0.75, 'segments': 3, 'affect': 'VERTICES', 'profile': 0.25}, 'VERT', + {1}, )]), + MeshTest('Pyramid6_test_1', 'Pyr6_test', 'Pyr6_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {2, 3}, )]), + MeshTest('Pyramid6_test_2', 'Pyr6_test', 'Pyr6_result_2', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {8, 2, 3}, )]), + MeshTest('Pyramid6_test_3', 'Pyr6_test', 'Pyr6_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 4, 'profile': 0.8}, 'EDGE', + {0, 2, 3, 4, 6, 7, 9, 10, 11}, )]), + MeshTest('Sept_test_1', 'Sept_test', 'Sept_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.1}, 'EDGE', {8, 9, 3, 11}, )]), # 25 - ['EDGE', {8, 9, 11}, 'Sept_test', 'Sept_result_2', 'bevel', {'offset': 0.1, 'offset_type': 'WIDTH'}], - ['EDGE', {2, 8, 9, 12, 13, 14}, 'Saddle_test', 'Saddle_result_1', 'bevel', {'offset': 0.3, 'segments': 5}], - ['VERT', {4}, 'Saddle_test', 'Saddle_result_2', 'bevel', {'offset': 0.6, 'segments': 6, 'affect': 'VERTICES'}], - ['EDGE', {2, 5, 8, 11, 14, 18, 21, 24, 27, 30, 34, 37, 40, 43, 46, 50, 53, 56, 59, 62, 112, 113, 114, 115}, - 'Bent_test', 'Bent_result_1', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {1, 8, 9, 10, 11}, 'Bentlines_test', 'Bentlines_result_1', 'bevel', {'offset': 0.2, 'segments': 3}], + MeshTest('Sept_test_2', 'Sept_test', 'Sept_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.1, 'offset_type': 'WIDTH'}, 'EDGE', {8, 9, 11}, )]), + MeshTest('Saddle_test_1', 'Saddle_test', 'Saddle_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.3, 'segments': 5}, 'EDGE', {2, 8, 9, 12, 13, 14}, )]), + MeshTest('Saddle_test_2', 'Saddle_test', 'Saddle_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.6, 'segments': 6, 'affect': 'VERTICES'}, 'VERT', {4}, )]), + + MeshTest('Bent_test', 'Bent_test', 'Bent_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, + 'EDGE', + {2, 5, 8, 11, 14, 18, 21, 24, 27, 30, 34, 37, 40, 43, 46, 50, 53, 56, 59, 62, + 112, 113, 114, 115}, )]), + MeshTest('Bentlines_test_1', 'Bentlines_test', 'Bentlines_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3}, 'EDGE', {1, 8, 9, 10, 11}, )]), # 30 - ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_1', 'bevel', {'offset': 0.4, 'segments': 2}], - ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_2', 'bevel', - {'offset': 0.4, 'segments': 2, 'profile': 1.0}], - ['FACE', {1, 6, 7, 8, 9, 10, 11, 12}, 'Flaretop_test', 'Flaretop_result_3', 'bevel', - {'offset': 0.4, 'segments': 4}], - ['EDGE', {4, 8, 10, 18, 24}, 'BentL_test', 'BentL_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {0, 1, 2, 10}, 'Wires_test', 'Wires_test_result_1', 'bevel', {'offset': 0.3}], + MeshTest('Flaretop_test_1', 'Flaretop_test', 'Flaretop_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 2}, 'EDGE', {26, 12, 20}, )]), + MeshTest('Flaretop_test_2', 'Flaretop_test', 'Flaretop_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 2, 'profile': 1.0}, 'EDGE', {26, 12, 20}, )]), + MeshTest('Flaretop_test_3', 'Flaretop_test', 'Flaretop_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.4, 'segments': 4}, 'FACE', {1, 6, 7, 8, 9, 10, 11, 12}, )]), + MeshTest('BentL_test', 'BentL_test', 'BentL_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {4, 8, 10, 18, 24}, )]), + MeshTest('Wires_test_1', 'Wires_test', 'Wires_test_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.3}, 'EDGE', {0, 1, 2, 10}, )]), # 35 - ['VERT', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 'Wires_test', 'Wires_test_result_2', 'bevel', - {'offset': 0.3, 'affect': 'VERTICES'}], - ['EDGE', {3, 4, 5}, 'tri', 'tri_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4, 5}, 'tri', 'tri_result_2', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {3, 4, 5}, 'tri', 'tri_result_3', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {3, 4}, 'tri', 'tri_result_4', 'bevel', {'offset': 0.2}], + MeshTest('Wires_test_2', 'Wires_test', 'Wires_test_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.3, 'affect': 'VERTICES'}, 'VERT', + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, )]), + MeshTest('tri_test_1', 'tri', 'tri_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri_test_2', 'tri', 'tri_result_2', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri_test_3', 'tri', 'tri_result_3', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri_test_4', 'tri', 'tri_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4}, )]), # 40 - ['EDGE', {3, 4}, 'tri', 'tri_result_5', 'bevel', {'offset': 0.2, 'segments': 2}], - ['VERT', {3}, 'tri', 'tri_result_6', 'bevel', {'offset': 0.2, 'affect': 'VERTICES'}], - ['VERT', {3}, 'tri', 'tri_result_7', 'bevel', {'offset': 0.2, 'segments': 2, 'affect': 'VERTICES'}], - ['VERT', {3}, 'tri', 'tri_result_8', 'bevel', {'offset': 0.2, 'segments': 3, 'affect': 'VERTICES'}], - ['VERT', {1}, 'tri', 'tri_result_9', 'bevel', {'offset': 0.2, 'affect': 'VERTICES'}], + MeshTest('tri_test_5', 'tri', 'tri_result_5', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4}, )]), + MeshTest('tri_test_6', 'tri', 'tri_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'affect': 'VERTICES'}, 'VERT', {3}, )]), + MeshTest('tri_test_7', 'tri', 'tri_result_7', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'affect': 'VERTICES'}, 'VERT', {3}, )]), + MeshTest('tri_test_8', 'tri', 'tri_result_8', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3, 'affect': 'VERTICES'}, 'VERT', {3}, )]), + MeshTest('tri_test_9', 'tri', 'tri_result_9', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'affect': 'VERTICES'}, 'VERT', {1}, )]), # 45 - ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_2', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_3', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_4', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_5', 'bevel', {'offset': 0.2, 'segments': 2}], + MeshTest('tri1gap_test_2', 'tri1gap', 'tri1gap_result_2', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri1gap_test_3', 'tri1gap', 'tri1gap_result_3', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri1gap_test_1', 'tri1gap', 'tri1gap_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri1gap_test_4', 'tri1gap', 'tri1gap_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4}, )]), + MeshTest('tri1gap_test_5', 'tri1gap', 'tri1gap_result_5', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4}, )]), # 50 - ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_6', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_7', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_8', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_9', 'bevel', {'offset': 0.2, 'segments': 3}], - ['VERT', {3}, 'tri1gap', 'tri1gap_result_10', 'bevel', {'offset': 0.2, 'affect': 'VERTICES'}], + MeshTest('tri1gap_test_6', 'tri1gap', 'tri1gap_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4}, )]), + MeshTest('tri1gap_test_7', 'tri1gap', 'tri1gap_result_7', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 5}, )]), + MeshTest('tri1gap_test_8', 'tri1gap', 'tri1gap_result_8', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 5}, )]), + MeshTest('tri1gap_test_9', 'tri1gap', 'tri1gap_result_9', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 5}, )]), + MeshTest('tri1gap_test_10', 'tri1gap', 'tri1gap_result_10', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'affect': 'VERTICES'}, 'VERT', {3}, )]), # 55 - ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_4', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_5', 'bevel', {'offset': 0.2, 'segments': 2}], + MeshTest('tri2gaps_test_1', 'tri2gaps', 'tri2gaps_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri2gaps_test_2', 'tri2gaps', 'tri2gaps_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri2gaps_test_3', 'tri2gaps', 'tri2gaps_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri2gaps_test_4', 'tri2gaps', 'tri2gaps_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4}, )]), + MeshTest('tri2gaps_test_5', 'tri2gaps', 'tri2gaps_result_5', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4}, )]), # 60 - ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_6', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}], - ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_1', 'bevel', {'offset': 0.2}], + MeshTest('tri2gaps_test_6', 'tri2gaps', 'tri2gaps_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4}, )]), + MeshTest('tri3gaps_test_1', 'tri3gaps', 'tri3gaps_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri3gaps_test_2', 'tri3gaps', 'tri3gaps_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2}, 'EDGE', {3, 4, 5}, )]), + MeshTest('tri3gaps_test_3', 'tri3gaps', 'tri3gaps_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3}, 'EDGE', {3, 4, 5}, )]), + MeshTest('cube3_test_1', 'cube3', 'cube3_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.2}, 'EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, )]), # 65 - ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_2', 'bevel', - {'offset': 0.2, 'segments': 2}], - ['EDGE', {32, 35}, 'cube3', 'cube3_result_3', 'bevel', {'offset': 0.2}], - ['EDGE', {24, 35}, 'cube3', 'cube3_result_4', 'bevel', {'offset': 0.2}], - ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_5', 'bevel', {'offset': 0.2, 'segments': 2}], - ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_6', 'bevel', {'offset': 0.2, 'segments': 3}], + MeshTest('cube3_test_2', 'cube3', 'cube3_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2}, 'EDGE', + {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, )]), + MeshTest('cube3_test_3', 'cube3', 'cube3_result_3', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {32, 35}, )]), + MeshTest('cube3_test_4', 'cube3', 'cube3_result_4', + [OperatorSpecEditMode('bevel', {'offset': 0.2}, 'EDGE', {24, 35}, )]), + MeshTest('cube3_test_5', 'cube3', 'cube3_result_5', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 2}, 'EDGE', {24, 32, 35}, )]), + MeshTest('cube3_test_6', 'cube3', 'cube3_result_6', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {24, 32, 35}, )]), # 70 - ['EDGE', {0, 1, 6, 7, 12, 14, 16, 17}, 'Tray', 'Tray_result_1', 'bevel', {'offset': 0.01, 'segments': 2}], - ['EDGE', {33, 4, 38, 8, 41, 10, 42, 12, 14, 17, 24, 31}, 'Bumptop', 'Bumptop_result_1', 'bevel', - {'offset': 0.1, 'segments': 4}], - ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}], - ['EDGE', {19, 20, 23, 15}, 'Window_test', 'Window_result_1', 'bevel', {'offset': 0.05, 'segments': 2}], + MeshTest('Tray', 'Tray', 'Tray_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.01, 'segments': 2}, 'EDGE', {0, 1, 6, 7, 12, 14, 16, 17}, )]), + MeshTest("test 73", 'Bumptop', 'Bumptop_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.1, 'segments': 4}, 'EDGE', + {33, 4, 38, 8, 41, 10, 42, 12, 14, 17, 24, 31}, )]), + MeshTest('Multisegment_test_1', 'Multisegment_test', 'Multisegment_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.2}, 'EDGE', {16, 14, 15}, )]), + MeshTest('Window_test', 'Window_test', 'Window_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.05, 'segments': 2}, 'EDGE', {19, 20, 23, 15}, )]), # 75 - ['EDGE', {8}, 'Cube_hn_test', 'Cube_hn_result_1', 'bevel', {'offset': 0.2, 'harden_normals': True}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_1', 'bevel', - {'offset': 0.2, 'miter_outer': 'PATCH'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_2', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_3', 'bevel', - {'offset': 0.2, 'segments': 3, 'miter_outer': 'PATCH'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_4', 'bevel', - {'offset': 0.2, 'miter_outer': 'ARC'}], + MeshTest("test 77", 'Cube_hn_test', 'Cube_hn_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'harden_normals': True}, 'EDGE', {8}, )]), + MeshTest('Blocksteps_test_1', 'Blocksteps_test', 'Blocksteps_result_1', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'miter_outer': 'PATCH'}, 'EDGE', {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps_test_2', 'Blocksteps_test', 'Blocksteps_result_2', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps_test_3', 'Blocksteps_test', 'Blocksteps_result_3', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3, 'miter_outer': 'PATCH'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps_test_4', 'Blocksteps_test', 'Blocksteps_result_4', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'miter_outer': 'ARC'}, 'EDGE', {4, 7, 39, 27, 30, 31}, )]), # 80 - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_5', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_6', 'bevel', - {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_7', 'bevel', - {'offset': 0.2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_8', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps2_test', 'Blocksteps2_result_9', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}], + MeshTest('Blocksteps_test_5', 'Blocksteps_test', 'Blocksteps_result_5', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps_test_6', 'Blocksteps_test', 'Blocksteps_result_6', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps_test_7', 'Blocksteps_test', 'Blocksteps_result_7', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest("Blocksteps_test_8", 'Blocksteps_test', 'Blocksteps_result_8', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}, + 'EDGE', {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps2_test', 'Blocksteps2_test', 'Blocksteps2_result_9', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), # 85 - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps3_test', 'Blocksteps3_result_10', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_11', 'bevel', - {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}], - ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_12', 'bevel', - {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}], - ['EDGE', {1, 7}, 'Spike_test', 'Spike_result_1', 'bevel', {'offset': 0.2, 'segments': 3}] - ] + MeshTest('Blocksteps3_test', 'Blocksteps3_test', 'Blocksteps3_result_10', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps4_test_1', 'Blocksteps4_test', 'Blocksteps4_result_11', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Blocksteps4_test_2', 'Blocksteps4_test', 'Blocksteps4_result_12', + [OperatorSpecEditMode('bevel', + {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}, 'EDGE', + {4, 7, 39, 27, 30, 31}, )]), + MeshTest('Spike_test', 'Spike_test', 'Spike_result_1', + [OperatorSpecEditMode('bevel', {'offset': 0.2, 'segments': 3}, 'EDGE', {1, 7})]) - operator_test = OperatorTest(tests) + ] + operator_test = RunTest(tests) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": + operator_test.do_compare = True operator_test.run_all_tests() break elif cmd == "--run-test": - index = int(command[i + 1]) - operator_test.run_test(index) + name = command[i + 1] + operator_test.do_compare = False + operator_test.run_test(name) break diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py index b35c69b7ca5..0db6a074699 100644 --- a/tests/python/boolean_operator.py +++ b/tests/python/boolean_operator.py @@ -29,33 +29,53 @@ import os import sys sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import OperatorTest +from modules.mesh_test import MeshTest, OperatorSpecEditMode, RunTest def main(): tests = [ - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_3', 'intersect_boolean', {'operation': 'DIFFERENCE', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_4', 'intersect', {'separate_mode': 'CUT', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_5', 'intersect', {'separate_mode': 'ALL', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_6', 'intersect', {'separate_mode': 'NONE', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cubecube', 'Cubecube_result_7', 'intersect', - {'mode': 'SELECT', 'separate_mode': 'NONE', 'solver' : 'FAST'}], - ['FACE', {6, 7, 8, 9, 10}, 'Cubecone', 'Cubecone_result_1', 'intersect_boolean', {'operation': 'UNION', 'solver' : 'FAST'}], - ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecones', 'Cubecones_result_1', 'intersect_boolean', {'operation': 'UNION', 'solver' : 'FAST'}], + + MeshTest('Cubecube_intersect_union', 'Cubecube', 'Cubecube_result_1', + [OperatorSpecEditMode('intersect_boolean', + {'operation': 'UNION', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_intersect', 'Cubecube', 'Cubecube_result_2', + [OperatorSpecEditMode('intersect_boolean', {'operation': 'INTERSECT', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_difference', 'Cubecube', 'Cubecube_result_3', + [OperatorSpecEditMode('intersect_boolean', {'operation': 'DIFFERENCE', 'solver': 'FAST'}, 'FACE', + {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_cut', 'Cubecube', 'Cubecube_result_4', [OperatorSpecEditMode('intersect', + {'separate_mode': 'CUT', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_all', 'Cubecube', 'Cubecube_result_5', + [OperatorSpecEditMode('intersect', + {'separate_mode': 'ALL', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_none', 'Cubecube', 'Cubecube_result_6', + [OperatorSpecEditMode('intersect', + {'separate_mode': 'NONE', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + MeshTest('Cubecube_intersect_select_none', 'Cubecube', + 'Cubecube_result_7', + [OperatorSpecEditMode('intersect', + {'mode': 'SELECT', 'separate_mode': 'NONE', 'solver': 'FAST'}, 'FACE', + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, )]), + MeshTest('Cubecone_intersect_union', 'Cubecone', 'Cubecone_result_1', + [OperatorSpecEditMode('intersect_boolean', + {'operation': 'UNION', 'solver': 'FAST'}, 'FACE', {6, 7, 8, 9, 10}, )]), + MeshTest('Cubecones_intersect_union', 'Cubecones', 'Cubecones_result_1', + [OperatorSpecEditMode('intersect_boolean', {'operation': 'UNION', 'solver': 'FAST'}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), + ] - operator_test = OperatorTest(tests) + operator_test = RunTest(tests) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": + operator_test.do_compare = True operator_test.run_all_tests() break elif cmd == "--run-test": - index = int(command[i + 1]) - operator_test.run_test(index) + name = command[i + 1] + operator_test.do_compare = False + operator_test.run_test(name) break diff --git a/tests/python/deform_modifiers.py b/tests/python/deform_modifiers.py new file mode 100644 index 00000000000..7c4ea457e9d --- /dev/null +++ b/tests/python/deform_modifiers.py @@ -0,0 +1,119 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +# To run the test type: blender -b /path/to/the/blend/file --python path/to/this/py/file -- --run-all-tests -- --verbose +# Type the above line in cmd/terminal, for example, look below +# blender -b c:\blender-lib\deform_modifiers.blend --python c:\deform_modifiers.py -- --run-all-tests -- --verbose + + +import os +import sys +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import MeshTest, ModifierSpec, OperatorSpecObjectMode, DeformModifierSpec, RunTest + +tests = [ + + # Surface Deform Test, finally can bind to the Target object. + # Actual deformation occurs by animating imitating user input. + + MeshTest("SurfaceDeform", "testObjMonkeySurfaceDeform", "expObjMonkeySurfaceDeform", + [DeformModifierSpec(10, [ + ModifierSpec('surface_deform', 'SURFACE_DEFORM', {'target': bpy.data.objects["Cube"]})], + OperatorSpecObjectMode('surfacedeform_bind', {'modifier': 'surface_deform'}))]), + + # Mesh Deform Test, finally can bind to the Target object. + # Actual deformation occurs by animating imitating user input. + + MeshTest("MeshDeform", "testObjMonkeyMeshDeform", "expObjMonkeyMeshDeform", + [DeformModifierSpec(10, [ModifierSpec('mesh_deform', 'MESH_DEFORM', + {'object': bpy.data.objects["MeshCube"], 'precision': 2})], + OperatorSpecObjectMode('meshdeform_bind', {'modifier': 'mesh_deform'}))]), + + # Surface Deform Test, finally can bind to the Target object. + # Actual deformation occurs by animating imitating user input. + + MeshTest("Hook", "testObjHookPlane", "expObjHookPlane", + [DeformModifierSpec(10, [ModifierSpec('hook', 'HOOK', + {'object': bpy.data.objects["Empty"], 'falloff_radius': 1, + 'vertex_group': 'Group'})])]), + + # Laplacian Deform Test, first a hook is attached. + + MeshTest("Laplace", "testObjCubeLaplacian", "expObjCubeLaplacian", + [DeformModifierSpec(10, + [ModifierSpec('hook2', 'HOOK', {'object': bpy.data.objects["Empty.001"], + 'vertex_group': 'hook_vg'}), + ModifierSpec('laplace', 'LAPLACIANDEFORM', {'vertex_group': 'laplace_vg'})], + OperatorSpecObjectMode('laplaciandeform_bind', {'modifier': 'laplace'}))]), + + MeshTest("WarpPlane", "testObjPlaneWarp", "expObjPlaneWarp", + [DeformModifierSpec(10, [ModifierSpec('warp', 'WARP', + {'object_from': bpy.data.objects["From"], + 'object_to': bpy.data.objects["To"], + })])]), + + ############################################# + # Curves Deform Modifiers + ############################################# + MeshTest("CurveArmature", "testObjBezierCurveArmature", "expObjBezierCurveArmature", + [DeformModifierSpec(10, [ModifierSpec('curve_armature', 'ARMATURE', + {'object': bpy.data.objects['testArmatureHelper'], + 'use_vertex_groups': False, 'use_bone_envelopes': True})])]), + + MeshTest("CurveLattice", "testObjBezierCurveLattice", "expObjBezierCurveLattice", + [DeformModifierSpec(10, [ModifierSpec('curve_lattice', 'LATTICE', + {'object': bpy.data.objects['testLatticeCurve']})])]), + + # HOOK for Curves can't be tested with current framework, as it requires going to Edit Mode to select vertices, + # here is no equivalent of a vertex group in Curves. + # Dummy test for Hook, can also be called corner case + MeshTest("CurveHook", "testObjBezierCurveHook", "expObjBezierCurveHook", + [DeformModifierSpec(10, + [ModifierSpec('curve_Hook', 'HOOK', {'object': bpy.data.objects['EmptyCurve']})])]), + + MeshTest("MeshDeformCurve", "testObjCurveMeshDeform", "expObjCurveMeshDeform", + [DeformModifierSpec(10, [ + ModifierSpec('mesh_deform_curve', 'MESH_DEFORM', {'object': bpy.data.objects["Cylinder"], + 'precision': 2})], + OperatorSpecObjectMode('meshdeform_bind', {'modifier': 'mesh_deform_curve'}))]), + + MeshTest("WarpCurve", "testObjBezierCurveWarp", "expObjBezierCurveWarp", + [DeformModifierSpec(10, [ModifierSpec('warp_curve', 'WARP', + {'object_from': bpy.data.objects["From_curve"], + 'object_to': bpy.data.objects["To_curve"]})])]), + +] + +deform_tests = RunTest(tests) +command = list(sys.argv) +for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + deform_tests.apply_modifiers = True + deform_tests.do_compare = True + deform_tests.run_all_tests() + break + elif cmd == "--run-test": + deform_tests.apply_modifiers = False + deform_tests.do_compare = False + name = command[i + 1] + deform_tests.run_test(name) + break diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py index ba156cef8ea..24f71c4066d 100644 --- a/tests/python/modifiers.py +++ b/tests/python/modifiers.py @@ -26,7 +26,7 @@ from random import shuffle, seed import bpy sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import ModifierTest, ModifierSpec +from modules.mesh_test import RunTest, ModifierSpec, MeshTest seed(0) @@ -47,7 +47,7 @@ def get_generate_modifiers_list(test_object_name, randomize=False): ModifierSpec('array', 'ARRAY', {}), ModifierSpec('bevel', 'BEVEL', {'width': 0.1}), ModifierSpec('boolean', 'BOOLEAN', {'object': boolean_test_object, 'solver': 'FAST'}), - ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1}), + ModifierSpec('build', 'BUILD', {'frame_start': 1, 'frame_duration': 1}, 2), ModifierSpec('decimate', 'DECIMATE', {}), ModifierSpec('edge split', 'EDGE_SPLIT', {}), @@ -62,7 +62,6 @@ def get_generate_modifiers_list(test_object_name, randomize=False): # ModifierSpec('remesh', 'REMESH', {}), # ModifierSpec('screw', 'SCREW', {}), # screw can make the test very slow. Skipping for now. - # ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible . ModifierSpec('solidify', 'SOLIDIFY', {}), ModifierSpec('subsurf', 'SUBSURF', {}), @@ -78,7 +77,6 @@ def get_generate_modifiers_list(test_object_name, randomize=False): def main(): - mask_first_list = get_generate_modifiers_list("testCubeMaskFirst", randomize=True) mask_vertex_group = "testCubeMaskFirst" + "_mask" mask_first_list.insert(0, ModifierSpec('mask', 'MASK', {'vertex_group': mask_vertex_group})) @@ -88,169 +86,279 @@ def main(): # List of 'Generate' modifiers on a cube ############################### # 0 - # ["testCube", "expectedCube", get_generate_modifiers_list("testCube")], - ["testCubeRandom", "expectedCubeRandom", get_generate_modifiers_list("testCubeRandom", randomize=True)], - ["testCubeMaskFirst", "expectedCubeMaskFirst", mask_first_list], - - ["testCollapseDecimate", "expectedCollapseDecimate", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), - ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'COLLAPSE', 'ratio': 0.25, 'use_collapse_triangulate': True})]], - ["testPlanarDecimate", "expectedPlanarDecimate", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), - ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'DISSOLVE', 'angle_limit': math.radians(30)})]], - ["testUnsubdivideDecimate", "expectedUnsubdivideDecimate", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), - ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'UNSUBDIV', 'iterations': 2})]], + # MeshTest("testCube", "expectedCube", get_generate_modifiers_list("testCube")), + MeshTest("CubeRandom", "testCubeRandom", "expectedCubeRandom", + get_generate_modifiers_list("testCubeRandom", randomize=True)), + MeshTest("CubeMaskFirst", "testCubeMaskFirst", "expectedCubeMaskFirst", mask_first_list), + + MeshTest("CollapseDecimate", "testCollapseDecimate", "expectedCollapseDecimate", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), + ModifierSpec('decimate', 'DECIMATE', + {'decimate_type': 'COLLAPSE', 'ratio': 0.25, 'use_collapse_triangulate': True})]), + MeshTest("PlanarDecimate", "testPlanarDecimate", "expectedPlanarDecimate", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), + ModifierSpec('decimate', 'DECIMATE', + {'decimate_type': 'DISSOLVE', 'angle_limit': math.radians(30)})]), + MeshTest("UnsubdivideDecimate", "testUnsubdivideDecimate", "expectedUnsubdivideDecimate", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}), + ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'UNSUBDIV', 'iterations': 2})]), # 5 - ["testRadialBisectMirror", "expectedRadialBisectMirror", - [ModifierSpec('mirror1', 'MIRROR', {'use_bisect_axis': (True, False, False)}), - ModifierSpec('mirror2', 'MIRROR', {'use_bisect_axis': (True, False, False), 'mirror_object': bpy.data.objects["testRadialBisectMirrorHelper"]}), - ModifierSpec('mirror3', 'MIRROR', {'use_axis': (False, True, False), 'use_bisect_axis': (False, True, False), 'use_bisect_flip_axis': (False, True, False), 'mirror_object': bpy.data.objects["testRadialBisectMirrorHelper"]})]], - ["regressT58411Mirror", "expectedT58411Mirror", - [ModifierSpec('mirror', 'MIRROR', {}), - ModifierSpec('bevel', 'BEVEL', {'segments': 2, 'limit_method': 'WEIGHT'}), - ModifierSpec('subd', 'SUBSURF', {'levels': 1})]], - - ["testBasicScrew", "expectedBasicScrew", - [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testBasicScrewHelper"]}), - ModifierSpec("screw", 'SCREW', {'angle': math.radians(400), 'steps': 20, 'iterations': 2, 'screw_offset': 2, 'use_normal_calculate': True})]], - ["testObjectScrew", "expectedObjectScrew", - [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testObjectScrewHelper2"]}), - ModifierSpec("screw", 'SCREW', {"angle": math.radians(600), 'steps': 32, 'iterations': 1, 'use_object_screw_offset': True, 'use_normal_calculate': True, 'object': bpy.data.objects["testObjectScrewHelper1"]})]], + MeshTest("RadialBisectMirror", "testRadialBisectMirror", "expectedRadialBisectMirror", + [ModifierSpec('mirror1', 'MIRROR', {'use_bisect_axis': (True, False, False)}), + ModifierSpec('mirror2', 'MIRROR', {'use_bisect_axis': (True, False, False), + 'mirror_object': bpy.data.objects[ + "testRadialBisectMirrorHelper"]}), + ModifierSpec('mirror3', 'MIRROR', + {'use_axis': (False, True, False), 'use_bisect_axis': (False, True, False), + 'use_bisect_flip_axis': (False, True, False), + 'mirror_object': bpy.data.objects["testRadialBisectMirrorHelper"]})]), + MeshTest("T58411Mirror", "regressT58411Mirror", "expectedT58411Mirror", + [ModifierSpec('mirror', 'MIRROR', {}), + ModifierSpec('bevel', 'BEVEL', {'segments': 2, 'limit_method': 'WEIGHT'}), + ModifierSpec('subd', 'SUBSURF', {'levels': 1})]), + + MeshTest("BasicScrew", "testBasicScrew", "expectedBasicScrew", + [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testBasicScrewHelper"]}), + ModifierSpec("screw", 'SCREW', + {'angle': math.radians(400), 'steps': 20, 'iterations': 2, 'screw_offset': 2, + 'use_normal_calculate': True})]), + MeshTest("ObjectScrew", "testObjectScrew", "expectedObjectScrew", + [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testObjectScrewHelper2"]}), + ModifierSpec("screw", 'SCREW', + {"angle": math.radians(600), 'steps': 32, 'iterations': 1, + 'use_object_screw_offset': True, + 'use_normal_calculate': True, 'object': bpy.data.objects["testObjectScrewHelper1"]})]), # 9 - ["testMergedScrewWeld", "expectedMergedScrewWeld", - [ModifierSpec("screw", 'SCREW', {'angle': math.radians(360), 'steps': 12, 'iterations': 1, 'screw_offset': 1, 'use_normal_calculate': True, 'use_merge_vertices': True}), - ModifierSpec("weld", 'WELD', {"merge_threshold": 0.001})]], - ["regressT72380Weld", "expectedT72380Weld", - [ModifierSpec('vedit', 'VERTEX_WEIGHT_EDIT', {'vertex_group': 'Group', 'use_remove': True, 'remove_threshold': 1}), - ModifierSpec("weld", 'WELD', {"merge_threshold": 0.2, "vertex_group": "Group"})]], - ["regressT72792Weld", "expectedT72792Weld", - [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 2}), - ModifierSpec("weld", 'WELD', {"merge_threshold": 0.1, "vertex_group": "Group"})]], + MeshTest("MergedScrewWeld", "testMergedScrewWeld", "expectedMergedScrewWeld", + [ModifierSpec("screw", 'SCREW', + {'angle': math.radians(360), 'steps': 12, 'iterations': 1, 'screw_offset': 1, + 'use_normal_calculate': True, 'use_merge_vertices': True}), + ModifierSpec("weld", 'WELD', {"merge_threshold": 0.001})]), + MeshTest("T72380Weld", "regressT72380Weld", "expectedT72380Weld", + [ModifierSpec('vedit', 'VERTEX_WEIGHT_EDIT', + {'vertex_group': 'Group', 'use_remove': True, 'remove_threshold': 1}), + ModifierSpec("weld", 'WELD', {"merge_threshold": 0.2, "vertex_group": "Group"})]), + MeshTest("T72792Weld", "regressT72792Weld", "expectedT72792Weld", + [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 2}), + ModifierSpec("weld", 'WELD', {"merge_threshold": 0.1, "vertex_group": "Group"})]), ############################################ # One 'Generate' modifier on primitive meshes ############################################# # 12 - ["testCubeArray", "expectedCubeArray", [ModifierSpec('array', 'ARRAY', {})]], - ["testCapArray", "expectedCapArray", - [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIT_LENGTH', 'fit_length': 2.0, 'start_cap': bpy.data.objects["testCapStart"], 'end_cap': bpy.data.objects["testCapEnd"]})]], - ["testCurveArray", "expectedCurveArray", - [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIT_CURVE', 'curve': bpy.data.objects["testCurveArrayHelper"], 'use_relative_offset': False, 'use_constant_offset': True, 'constant_offset_displace': (0.5, 0, 0)})]], - ["testRadialArray", "expectedRadialArray", - [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 3, 'use_merge_vertices': True, 'use_merge_vertices_cap': True, 'use_relative_offset': False, 'use_object_offset': True, 'offset_object': bpy.data.objects["testRadialArrayHelper"]})]], - - ["testCylinderBuild", "expectedCylinderBuild", [ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1})]], + MeshTest("CubeArray", "testCubeArray", "expectedCubeArray", + [ModifierSpec('array', 'ARRAY', {})]), + MeshTest("CapArray", "testCapArray", "expectedCapArray", + [ModifierSpec('array', 'ARRAY', + {'fit_type': 'FIT_LENGTH', 'fit_length': 2.0, + 'start_cap': bpy.data.objects["testCapStart"], + 'end_cap': bpy.data.objects["testCapEnd"]})]), + MeshTest("CurveArray", "testCurveArray", "expectedCurveArray", + [ModifierSpec('array', 'ARRAY', + {'fit_type': 'FIT_CURVE', 'curve': bpy.data.objects["testCurveArrayHelper"], + 'use_relative_offset': False, 'use_constant_offset': True, + 'constant_offset_displace': (0.5, 0, 0)})]), + MeshTest("RadialArray", "testRadialArray", "expectedRadialArray", + [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 3, 'use_merge_vertices': True, + 'use_merge_vertices_cap': True, 'use_relative_offset': False, + 'use_object_offset': True, + 'offset_object': bpy.data.objects["testRadialArrayHelper"]})]), + + MeshTest("CylinderBuild", "testCylinderBuild", "expectedCylinderBuild", + [ModifierSpec('build', 'BUILD', {'frame_start': 1, 'frame_duration': 1}, 2)]), # 17 - ["testConeDecimate", "expectedConeDecimate", [ModifierSpec('decimate', 'DECIMATE', {'ratio': 0.5})]], - ["testCubeEdgeSplit", "expectedCubeEdgeSplit", [ModifierSpec('edge split', 'EDGE_SPLIT', {})]], - - ["testSphereMirror", "expectedSphereMirror", [ModifierSpec('mirror', 'MIRROR', {})]], - ["testLocalMirror", "expectedLocalMirror", - [ModifierSpec('mirror', 'MIRROR', {'use_clip': True})]], - ["testObjectOffsetMirror", "expectedObjectOffsetMirror", - [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testObjectOffsetMirrorHelper"]})]], - - ["testCylinderMask", "expectedCylinderMask", [ModifierSpec('mask', 'MASK', {'vertex_group': "mask_vertex_group"})]], - ["testConeMultiRes", "expectedConeMultiRes", [ModifierSpec('multires', 'MULTIRES', {})]], + MeshTest("ConeDecimate", "testConeDecimate", "expectedConeDecimate", + [ModifierSpec('decimate', 'DECIMATE', {'ratio': 0.5})]), + MeshTest("CubeEdgeSplit", "testCubeEdgeSplit", "expectedCubeEdgeSplit", + [ModifierSpec('edge split', 'EDGE_SPLIT', {})]), + + MeshTest("SphereMirror", "testSphereMirror", "expectedSphereMirror", + [ModifierSpec('mirror', 'MIRROR', {})]), + MeshTest("LocalMirror", "testLocalMirror", "expectedLocalMirror", + [ModifierSpec('mirror', 'MIRROR', {'use_clip': True})]), + MeshTest("ObjectOffsetMirror", "testObjectOffsetMirror", "expectedObjectOffsetMirror", + [ModifierSpec('mirror', 'MIRROR', + {'mirror_object': bpy.data.objects["testObjectOffsetMirrorHelper"]})]), + + MeshTest("CylinderMask", "testCylinderMask", "expectedCylinderMask", + [ModifierSpec('mask', 'MASK', {'vertex_group': "mask_vertex_group"})]), + MeshTest("ConeMultiRes", "testConeMultiRes", "expectedConeMultiRes", + [ModifierSpec('multires', 'MULTIRES', {})]), # 24 - ["testCubeScrew", "expectedCubeScrew", [ModifierSpec('screw', 'SCREW', {})]], - - ["testCubeSolidify", "expectedCubeSolidify", [ModifierSpec('solidify', 'SOLIDIFY', {})]], - ["testComplexSolidify", "expectedComplexSolidify", - [ModifierSpec('solidify', 'SOLIDIFY', {'solidify_mode': 'NON_MANIFOLD', 'thickness': 0.05, 'offset': 0, 'nonmanifold_thickness_mode': 'CONSTRAINTS'})]], - ["regressT63063Solidify", "expectedT63063Solidify", - [ModifierSpec('solid', 'SOLIDIFY', {'thickness': 0.1, 'offset': 0.7})]], - ["regressT61979Solidify", "expectedT61979Solidify", - [ModifierSpec('solid', 'SOLIDIFY', {'thickness': -0.25, 'use_even_offset': True, 'use_quality_normals': True})]], - - ["testMonkeySubsurf", "expectedMonkeySubsurf", [ModifierSpec('subsurf', 'SUBSURF', {})]], - ["testCatmullClarkSubdivisionSurface", "expectedCatmullClarkSubdivisionSurface", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]], - ["testSimpleSubdivisionSurface", "expectedSimpleSubdivisionSurface", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2, 'subdivision_type': 'SIMPLE'})]], - ["testCrease2dSubdivisionSurface", "expectedCrease2dSubdivisionSurface", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]], - ["testCrease3dSubdivisionSurface", "expectedCrease3dSubdivisionSurface", - [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]], + MeshTest("CubeScrew", "testCubeScrew", "expectedCubeScrew", + [ModifierSpec('screw', 'SCREW', {})]), + + MeshTest("CubeSolidify", "testCubeSolidify", "expectedCubeSolidify", + [ModifierSpec('solidify', 'SOLIDIFY', {})]), + MeshTest("ComplexSolidify", "testComplexSolidify", "expectedComplexSolidify", + [ModifierSpec('solidify', 'SOLIDIFY', {'solidify_mode': 'NON_MANIFOLD', 'thickness': 0.05, 'offset': 0, + 'nonmanifold_thickness_mode': 'CONSTRAINTS'})]), + MeshTest("T63063Solidify", "regressT63063Solidify", "expectedT63063Solidify", + [ModifierSpec('solid', 'SOLIDIFY', {'thickness': 0.1, 'offset': 0.7})]), + MeshTest("T61979Solidify", "regressT61979Solidify", "expectedT61979Solidify", + [ModifierSpec('solid', 'SOLIDIFY', + {'thickness': -0.25, 'use_even_offset': True, 'use_quality_normals': True})]), + + MeshTest("MonkeySubsurf", "testMonkeySubsurf", "expectedMonkeySubsurf", + [ModifierSpec('subsurf', 'SUBSURF', {})]), + MeshTest("CatmullClarkSubdivisionSurface", "testCatmullClarkSubdivisionSurface", + "expectedCatmullClarkSubdivisionSurface", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]), + MeshTest("SimpleSubdivisionSurface", "testSimpleSubdivisionSurface", "expectedSimpleSubdivisionSurface", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2, 'subdivision_type': 'SIMPLE'})]), + MeshTest("Crease2dSubdivisionSurface", "testCrease2dSubdivisionSurface", "expectedCrease2dSubdivisionSurface", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]), + MeshTest("Crease3dSubdivisionSurface", "testCrease3dSubdivisionSurface", "expectedCrease3dSubdivisionSurface", + [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]), # 34 - ["testSphereTriangulate", "expectedSphereTriangulate", [ModifierSpec('triangulate', 'TRIANGULATE', {})]], - ["testMonkeyWireframe", "expectedMonkeyWireframe", [ModifierSpec('wireframe', 'WIREFRAME', {})]], - #ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible . - ["testMergedWeld", "expectedMergedWeld", - [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.021})]], - ["testMergedAllWeld", "expectedMergedAllWeld", - [ModifierSpec("weld", 'WELD', {"merge_threshold": 1.8})]], - ["testMergedNoneWeld", "expectedMergedNoneWeld", - [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.019})]], + MeshTest("SphereTriangulate", "testSphereTriangulate", "expectedSphereTriangulate", + [ModifierSpec('triangulate', 'TRIANGULATE', {})]), + MeshTest("MonkeyWireframe", "testMonkeyWireframe", "expectedMonkeyWireframe", + [ModifierSpec('wireframe', 'WIREFRAME', {})]), + + # Duplicate the object, test object and expected object have same world coordinates. + MeshTest("Skin", "testObjPlaneSkin", "expObjPlaneSkin", + [ModifierSpec('skin', 'SKIN', {})]), + + MeshTest("MergedWeld", "testMergedWeld", "expectedMergedWeld", + [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.021})]), + MeshTest("MergedAllWeld", "testMergedAllWeld", "expectedMergedAllWeld", + [ModifierSpec("weld", 'WELD', {"merge_threshold": 1.8})]), + MeshTest("MergedNoneWeld", "testMergedNoneWeld", "expectedMergedNoneWeld", + [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.019})]), + ############################################# # One 'Deform' modifier on primitive meshes ############################################# # 39 - ["testMonkeyArmature", "expectedMonkeyArmature", - [ModifierSpec('armature', 'ARMATURE', {'object': bpy.data.objects['testArmature'], 'use_vertex_groups': True})]], - ["testTorusCast", "expectedTorusCast", [ModifierSpec('cast', 'CAST', {'factor': 2.64})]], - ["testCubeCurve", "expectedCubeCurve", - [ModifierSpec('curve', 'CURVE', {'object': bpy.data.objects['testBezierCurve']})]], - ["testMonkeyDisplace", "expectedMonkeyDisplace", [ModifierSpec('displace', "DISPLACE", {})]], - - # Hook modifier requires moving the hook object to get a mesh change, so can't test it with the current framework - # ["testMonkeyHook", "expectedMonkeyHook", - # [ModifierSpec('hook', 'HOOK', {'object': bpy.data.objects["EmptyHook"], 'vertex_group': "HookVertexGroup"})]], + MeshTest("MonkeyArmature", "testMonkeyArmature", "expectedMonkeyArmature", + [ModifierSpec('armature', 'ARMATURE', + {'object': bpy.data.objects['testArmature'], 'use_vertex_groups': True})]), + MeshTest("TorusCast", "testTorusCast", "expectedTorusCast", + [ModifierSpec('cast', 'CAST', {'factor': 2.64})]), + MeshTest("CubeCurve", "testCubeCurve", "expectedCubeCurve", + [ModifierSpec('curve', 'CURVE', {'object': bpy.data.objects['testBezierCurve']})]), + MeshTest("MonkeyDisplace", "testMonkeyDisplace", "expectedMonkeyDisplace", + [ModifierSpec('displace', "DISPLACE", {})]), + + # Hook modifier requires moving the hook object to get a mesh change + # so can't test it with the current framework + # MeshTest("MonkeyHook", "testMonkeyHook", "expectedMonkeyHook", + # [ModifierSpec('hook', 'HOOK', {'object': bpy.data.objects["EmptyHook"], 'vertex_group': + # "HookVertexGroup"})]), # 43 - #ModifierSpec('laplacian_deform', 'LAPLACIANDEFORM', {}) Laplacian requires a more complex mesh - ["testCubeLattice", "expectedCubeLattice", - [ModifierSpec('lattice', 'LATTICE', {'object': bpy.data.objects["testLattice"]})]], - # ModifierSpec('laplacian_deform', 'LAPLACIANDEFORM', {}) Laplacian requires a more complex mesh + MeshTest("CubeLattice", "testCubeLattice", "expectedCubeLattice", + [ModifierSpec('lattice', 'LATTICE', {'object': bpy.data.objects["testLattice"]})]), + + MeshTest("PlaneShrinkWrap", "testPlaneShrinkWrap", "expectedPlaneShrinkWrap", + [ModifierSpec('shrinkwrap', 'SHRINKWRAP', + {'target': bpy.data.objects["testCubeWrap"], 'offset': 0.5})]), - # Mesh Deform Modifier requires user input, so skip. + MeshTest("CylinderSimpleDeform", "testCylinderSimpleDeform", "expectedCylinderSimpleDeform", + [ModifierSpec('simple_deform', 'SIMPLE_DEFORM', {'angle': math.radians(180), 'deform_axis': 'Z'})]), - # mesh_test = MeshTest("testMonkeyDeform", "expectedMonkeyDeform",[ - # ModifierSpec('mesh_deform', 'MESH_DEFORM', {'object': bpy.data.objects["testDeformStructure"]}), - # OperatorSpec('meshdeform_bind',{'modifier':'MeshDeform'},'FACE',{i for in range(500)}) - # ] ,True) + MeshTest("PlaneSmooth", "testPlaneSmooth", "expectedPlaneSmooth", + [ModifierSpec('smooth', 'SMOOTH', {'iterations': 11})]), - ["testPlaneShrinkWrap", "expectedPlaneShrinkWrap", - [ModifierSpec('shrinkwrap', 'SHRINKWRAP', {'target': bpy.data.objects["testCubeWrap"], 'offset': 0.5})]], + # Smooth corrective requires a complex mesh. - ["testCylinderSimpleDeform", "expectedCylinderSimpleDeform", - [ModifierSpec('simple_deform', 'SIMPLE_DEFORM', {'angle': math.radians(180), 'deform_axis': 'Z'})]], + MeshTest("BalloonLaplacianSmooth", "testBalloonLaplacianSmooth", "expectedBalloonLaplacianSmooth", + [ModifierSpec('laplaciansmooth', 'LAPLACIANSMOOTH', {'lambda_factor': 12, 'lambda_border': 12})]), - ["testPlaneSmooth", "expectedPlaneSmooth", - [ModifierSpec('smooth', 'SMOOTH', {'iterations': 11})]], + # Gets updated often + MeshTest("WavePlane", "testObjPlaneWave", "expObjPlaneWave", + [ModifierSpec('wave', 'WAVE', {})]), - # Smooth corrective requires a complex mesh. + ############################################# + # CURVES Generate Modifiers + ############################################# + # Caution: Make sure test object has no modifier in "added" state, the test may fail. + MeshTest("BezCurveArray", "testObjBezierCurveArray", "expObjBezierCurveArray", + [ModifierSpec('array', 'ARRAY', {})]), + + MeshTest("CurveBevel", "testObjBezierCurveBevel", "expObjBezierCurveBevel", + [ModifierSpec('bevel', 'BEVEL', {})]), + + MeshTest("CurveBuild", "testObjBezierCurveBuild", "expObjBezierCurveBuild", + [ModifierSpec('build', 'BUILD', {'frame_start': 1, 'frame_duration': 1}, 2)]), + + MeshTest("CurveDecimate", "testObjBezierCurveDecimate", "expObjBezierCurveDecimate", + [ModifierSpec('decimate', 'DECIMATE', {'ratio': 0.5})]), + + MeshTest("CurveEdgeSplit", "testObjBezierCurveEdgeSplit", "expObjBezierCurveEdgeSplit", + [ModifierSpec('edgeSplit', 'EDGE_SPLIT', {})]), + + MeshTest("CurveMirror", "testObjBezierCurveMirror", "expObjBezierCurveMirror", + [ModifierSpec('mirror', 'MIRROR', {'use_axis': (True, True, False)})]), + + MeshTest("CurveScrew", "testObjBezierCurveScrew", "expObjBezierCurveScrew", + [ModifierSpec('screw', 'SCREW', {})]), + + MeshTest("CurveSolidify", "testObjBezierCurveSolidify", "expObjBezierCurveSolidify", + [ModifierSpec('solidify', 'SOLIDIFY', {'thickness': 1})]), + + MeshTest("CurveSubSurf", "testObjBezierCurveSubSurf", "expObjBezierCurveSubSurf", + [ModifierSpec('subSurf', 'SUBSURF', {})]), + + MeshTest("CurveTriangulate", "testObjBezierCurveTriangulate", "expObjBezierCurveTriangulate", + [ModifierSpec('triangulate', 'TRIANGULATE', {})]), + + # Test 60 + # Caution Weld: if the distance is increased beyond a limit, the object disappears + MeshTest("CurveWeld", "testObjBezierCurveWeld", "expObjBezierCurveWeld", + [ModifierSpec('weld', 'WELD', {})]), + + MeshTest("CurveWeld2", "testObjBezierCurveWeld2", "expObjBezierCurveWeld2", + [ModifierSpec('weld', 'WELD', {})]), + + ############################################# + # Curves Deform Modifiers + ############################################# + # Test 62 + MeshTest("CurveCast", "testObjBezierCurveCast", "expObjBezierCurveCast", + [ModifierSpec('Cast', 'CAST', {'cast_type': 'CYLINDER', 'factor': 10})]), + + MeshTest("CurveShrinkWrap", "testObjBezierCurveShrinkWrap", "expObjBezierCurveShrinkWrap", + [ModifierSpec('ShrinkWrap', 'SHRINKWRAP', + {'target': bpy.data.objects['testShrinkWrapHelperSuzanne']})]), + + MeshTest("CurveSimpleDeform", "testObjBezierCurveSimpleDeform", "expObjBezierCurveSimpleDeform", + [ModifierSpec('simple_deform', 'SIMPLE_DEFORM', {'angle': math.radians(90)})]), - ["testBalloonLaplacianSmooth", "expectedBalloonLaplacianSmooth", - [ModifierSpec('laplaciansmooth', 'LAPLACIANSMOOTH', {'lambda_factor': 12, 'lambda_border': 12})]], + MeshTest("CurveSmooth", "testObjBezierCurveSmooth", "expObjBezierCurveSmooth", + [ModifierSpec('smooth', 'SMOOTH', {'factor': 10})]), - # Surface Deform and Warp requires user input, so skip. + MeshTest("CurveWave", "testObjBezierCurveWave", "expObjBezierCurveWave", + [ModifierSpec('curve_wave', 'WAVE', {'time_offset': -1.5})]), - # Wave - requires complex mesh, so skip. + MeshTest("CurveCurve", "testObjBezierCurveCurve", "expObjBezierCurveCurve", + [ModifierSpec('curve_Curve', 'CURVE', {'object': bpy.data.objects['NurbsCurve']})]), ] - modifiers_test = ModifierTest(tests) + modifiers_test = RunTest(tests) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": modifiers_test.apply_modifiers = True + modifiers_test.do_compare = True modifiers_test.run_all_tests() break elif cmd == "--run-test": modifiers_test.apply_modifiers = False - index = int(command[i + 1]) - modifiers_test.run_test(index) + modifiers_test.do_compare = False + name = command[i + 1] + modifiers_test.run_test(name) break diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py index c85e7acf4e8..6671918a206 100644 --- a/tests/python/modules/mesh_test.py +++ b/tests/python/modules/mesh_test.py @@ -45,7 +45,6 @@ import functools import inspect import os - # Output from this module and from blender itself will occur during tests. # We need to flush python so that the output is properly interleaved, otherwise # blender's output for one test will end up showing in the middle of another test... @@ -54,37 +53,39 @@ print = functools.partial(print, flush=True) class ModifierSpec: """ - Holds one modifier and its parameters. + Holds a Generate or Deform or Physics modifier type and its parameters. """ - def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict): + def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict, frame_end=0): """ Constructs a modifier spec. :param modifier_name: str - name of object modifier, e.g. "myFirstSubsurfModif" :param modifier_type: str - type of object modifier, e.g. "SUBSURF" :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4} + :param frame_end: int - frame at which simulation needs to be baked or modifier needs to be applied. """ self.modifier_name = modifier_name self.modifier_type = modifier_type self.modifier_parameters = modifier_parameters + self.frame_end = frame_end def __str__(self): return "Modifier: " + self.modifier_name + " of type " + self.modifier_type + \ " with parameters: " + str(self.modifier_parameters) -class PhysicsSpec: +class ParticleSystemSpec: """ - Holds one Physics modifier and its parameters. + Holds a Particle System modifier and its parameters. """ def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict, frame_end: int): """ - Constructs a physics spec. - :param modifier_name: str - name of object modifier, e.g. "Cloth" - :param modifier_type: str - type of object modifier, e.g. "CLOTH" - :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4} - :param frame_end:int - the last frame of the simulation at which it is baked + Constructs a particle system spec. + :param modifier_name: str - name of object modifier, e.g. "Particles" + :param modifier_type: str - type of object modifier, e.g. "PARTICLE_SYSTEM" + :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"seed" : 1} + :param frame_end: int - the last frame of the simulation at which the modifier is applied """ self.modifier_name = modifier_name self.modifier_type = modifier_type @@ -96,14 +97,14 @@ class PhysicsSpec: " with parameters: " + str(self.modifier_parameters) + " with frame end: " + str(self.frame_end) -class OperatorSpec: +class OperatorSpecEditMode: """ Holds one operator and its parameters. """ def __init__(self, operator_name: str, operator_parameters: dict, select_mode: str, selection: set): """ - Constructs an operatorSpec. Raises ValueError if selec_mode is invalid. + Constructs an OperatorSpecEditMode. Raises ValueError if selec_mode is invalid. :param operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill" :param operator_parameters: dict - {name : val} dictionary containing operator parameters. :param select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE' @@ -121,6 +122,45 @@ class OperatorSpec: " in selection mode: " + self.select_mode + ", selecting " + str(self.selection) +class OperatorSpecObjectMode: + """ + Holds an object operator and its parameters. Helper class for DeformModifierSpec. + Needed to support operations in Object Mode and not Edit Mode which is supported by OperatorSpecEditMode. + """ + + def __init__(self, operator_name: str, operator_parameters: dict): + """ + :param operator_name: str - name of the object operator from bpy.ops.object, e.g. "shade_smooth" or "shape_keys" + :param operator_parameters: dict - contains operator parameters. + """ + self.operator_name = operator_name + self.operator_parameters = operator_parameters + + def __str__(self): + return "Operator: " + self.operator_name + " with parameters: " + str(self.operator_parameters) + + +class DeformModifierSpec: + """ + Holds a list of deform modifier and OperatorSpecObjectMode. + For deform modifiers which have an object operator + """ + + def __init__(self, frame_number: int, modifier_list: list, object_operator_spec: OperatorSpecObjectMode = None): + """ + Constructs a Deform Modifier spec (for user input) + :param frame_number: int - the frame at which animated keyframe is inserted + :param modifier_list: ModifierSpec - contains modifiers + :param object_operator_spec: OperatorSpecObjectMode - contains object operators + """ + self.frame_number = frame_number + self.modifier_list = modifier_list + self.object_operator_spec = object_operator_spec + + def __str__(self): + return "Modifier: " + str(self.modifier_list) + " with object operator " + str(self.object_operator_spec) + + class MeshTest: """ A mesh testing class targeted at testing modifiers and operators on a single object. @@ -129,33 +169,45 @@ class MeshTest: """ def __init__( - self, - test_object_name: str, - expected_object_name: str, - operations_stack=None, - apply_modifiers=False, - threshold=None, + self, + test_name: str, + test_object_name: str, + expected_object_name: str, + operations_stack=None, + apply_modifiers=False, + do_compare=False, + threshold=None ): """ Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name or test_object_name don't exist. - :param test_object: str - Name of object of mesh type to run the operations on. - :param expected_object: str - Name of object of mesh type that has the expected + :param test_name: str - unique test name identifier. + :param test_object_name: str - Name of object of mesh type to run the operations on. + :param expected_object_name: str - Name of object of mesh type that has the expected geometry after running the operations. :param operations_stack: list - stack holding operations to perform on the test_object. - :param apply_modifier: bool - True if we want to apply the modifiers right after adding them to the object. - This affects operations of type ModifierSpec only. + :param apply_modifiers: bool - True if we want to apply the modifiers right after adding them to the object. + - True if we want to apply the modifier to a list of modifiers, after some operation. + This affects operations of type ModifierSpec and DeformModifierSpec. + :param do_compare: bool - True if we want to compare the test and expected objects, False otherwise. + :param threshold : exponent: To allow variations and accept difference to a certain degree. + """ if operations_stack is None: operations_stack = [] for operation in operations_stack: - if not (isinstance(operation, ModifierSpec) or isinstance(operation, OperatorSpec)): - raise ValueError("Expected operation of type {} or {}. Got {}". - format(type(ModifierSpec), type(OperatorSpec), + if not (isinstance(operation, ModifierSpec) or isinstance(operation, OperatorSpecEditMode) + or isinstance(operation, OperatorSpecObjectMode) or isinstance(operation, DeformModifierSpec) + or isinstance(operation, ParticleSystemSpec)): + raise ValueError("Expected operation of type {} or {} or {} or {}. Got {}". + format(type(ModifierSpec), type(OperatorSpecEditMode), + type(DeformModifierSpec), type(ParticleSystemSpec), type(operation))) self.operations_stack = operations_stack self.apply_modifier = apply_modifiers + self.do_compare = do_compare self.threshold = threshold + self.test_name = test_name self.verbose = os.environ.get("BLENDER_VERBOSE") is not None self.update = os.getenv('BLENDER_TEST_UPDATE') is not None @@ -187,22 +239,6 @@ class MeshTest: objects = bpy.data.objects self.expected_object = objects[expected_object_name] - def add_modifier(self, modifier_spec: ModifierSpec): - """ - Add a modifier to the operations stack. - :param modifier_spec: modifier to add to the operations stack - """ - self.operations_stack.append(modifier_spec) - if self.verbose: - print("Added modififier {}".format(modifier_spec)) - - def add_operator(self, operator_spec: OperatorSpec): - """ - Adds an operator to the operations stack. - :param operator_spec: OperatorSpec - operator to add to the operations stack. - """ - self.operations_stack.append(operator_spec) - def _on_failed_test(self, compare_result, validation_success, evaluated_test_object): if self.update and validation_success: if self.verbose: @@ -239,83 +275,164 @@ class MeshTest: """ return self._test_updated - def _apply_modifier(self, test_object, modifier_spec: ModifierSpec): + def _set_parameters_impl(self, modifier, modifier_parameters, nested_settings_path, modifier_name): """ - Add modifier to object and apply (if modifier_spec.apply_modifier is True) + Doing a depth first traversal of the modifier parameters and setting their values. + :param: modifier: Of type modifier, its altered to become a setting in recursion. + :param: modifier_parameters : dict or sequence, a simple/nested dictionary of modifier parameters. + :param: nested_settings_path : list(stack): helps in tracing path to each node. + """ + if not isinstance(modifier_parameters, dict): + param_setting = None + for i, setting in enumerate(nested_settings_path): + + # We want to set the attribute only when we have reached the last setting. + # Applying of intermediate settings is meaningless. + if i == len(nested_settings_path) - 1: + setattr(modifier, setting, modifier_parameters) + + elif hasattr(modifier, setting): + param_setting = getattr(modifier, setting) + # getattr doesn't accept canvas_surfaces["Surface"], but we need to pass it to setattr. + if setting == "canvas_surfaces": + modifier = param_setting.active + else: + modifier = param_setting + else: + # Clean up first + bpy.ops.object.delete() + raise Exception("Modifier '{}' has no parameter named '{}'". + format(modifier_name, setting)) + + # It pops the current node before moving on to its sibling. + nested_settings_path.pop() + return + + for key in modifier_parameters: + nested_settings_path.append(key) + self._set_parameters_impl(modifier, modifier_parameters[key], nested_settings_path, modifier_name) + + if nested_settings_path: + nested_settings_path.pop() + + def set_parameters(self, modifier, modifier_parameters): + """ + Wrapper for _set_parameters_util + """ + settings = [] + modifier_name = modifier.name + self._set_parameters_impl(modifier, modifier_parameters, settings, modifier_name) + + def _add_modifier(self, test_object, modifier_spec: ModifierSpec): + """ + Add modifier to object. :param test_object: bpy.types.Object - Blender object to apply modifier on. :param modifier_spec: ModifierSpec - ModifierSpec object with parameters """ + bakers_list = ['CLOTH', 'SOFT_BODY', 'DYNAMIC_PAINT', 'FLUID'] + scene = bpy.context.scene + scene.frame_set(1) modifier = test_object.modifiers.new(modifier_spec.modifier_name, modifier_spec.modifier_type) + + if modifier is None: + raise Exception("This modifier type is already added on the Test Object, please remove it and try again.") + if self.verbose: print("Created modifier '{}' of type '{}'.". format(modifier_spec.modifier_name, modifier_spec.modifier_type)) - for param_name in modifier_spec.modifier_parameters: - try: - setattr(modifier, param_name, modifier_spec.modifier_parameters[param_name]) - if self.verbose: - print("\t set parameter '{}' with value '{}'". - format(param_name, modifier_spec.modifier_parameters[param_name])) - except AttributeError: - # Clean up first - bpy.ops.object.delete() - raise AttributeError("Modifier '{}' has no parameter named '{}'". - format(modifier_spec.modifier_type, param_name)) + # Special case for Dynamic Paint, need to toggle Canvas on. + if modifier.type == "DYNAMIC_PAINT": + bpy.ops.dpaint.type_toggle(type='CANVAS') - if self.apply_modifier: - bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name) + self.set_parameters(modifier, modifier_spec.modifier_parameters) + + if modifier.type in bakers_list: + self._bake_current_simulation(test_object, modifier.name, modifier_spec.frame_end) + + scene.frame_set(modifier_spec.frame_end) + + def _apply_modifier(self, test_object, modifier_name): + # Modifier automatically gets applied when converting from Curve to Mesh. + if test_object.type == 'CURVE': + bpy.ops.object.convert(target='MESH') + elif test_object.type == 'MESH': + bpy.ops.object.modifier_apply(modifier=modifier_name) + else: + raise Exception("This object type is not yet supported!") + + def _bake_current_simulation(self, test_object, test_modifier_name, frame_end): + """ + FLUID: Bakes the simulation + SOFT BODY, CLOTH, DYNAMIC PAINT: Overrides the point_cache context and then bakes. + """ - def _bake_current_simulation(self, obj, test_mod_type, test_mod_name, frame_end): for scene in bpy.data.scenes: - for modifier in obj.modifiers: - if modifier.type == test_mod_type: - obj.modifiers[test_mod_name].point_cache.frame_end = frame_end - override = {'scene': scene, 'active_object': obj, 'point_cache': modifier.point_cache} + for modifier in test_object.modifiers: + if modifier.type == 'FLUID': + bpy.ops.fluid.bake_all() + break + + elif modifier.type == 'CLOTH' or modifier.type == 'SOFT_BODY': + test_object.modifiers[test_modifier_name].point_cache.frame_end = frame_end + override_setting = modifier.point_cache + override = {'scene': scene, 'active_object': test_object, 'point_cache': override_setting} + bpy.ops.ptcache.bake(override, bake=True) + break + + elif modifier.type == 'DYNAMIC_PAINT': + dynamic_paint_setting = modifier.canvas_settings.canvas_surfaces.active + override_setting = dynamic_paint_setting.point_cache + override = {'scene': scene, 'active_object': test_object, 'point_cache': override_setting} bpy.ops.ptcache.bake(override, bake=True) break - def _apply_physics_settings(self, test_object, physics_spec: PhysicsSpec): + def _apply_particle_system(self, test_object, particle_sys_spec: ParticleSystemSpec): """ - Apply Physics settings to test objects. + Applies Particle System settings to test objects """ - scene = bpy.context.scene - scene.frame_set(1) - modifier = test_object.modifiers.new(physics_spec.modifier_name, - physics_spec.modifier_type) - physics_setting = modifier.settings + bpy.context.scene.frame_set(1) + bpy.ops.object.select_all(action='DESELECT') + + test_object.modifiers.new(particle_sys_spec.modifier_name, particle_sys_spec.modifier_type) + + settings_name = test_object.particle_systems.active.settings.name + particle_setting = bpy.data.particles[settings_name] if self.verbose: print("Created modifier '{}' of type '{}'.". - format(physics_spec.modifier_name, physics_spec.modifier_type)) + format(particle_sys_spec.modifier_name, particle_sys_spec.modifier_type)) - for param_name in physics_spec.modifier_parameters: + for param_name in particle_sys_spec.modifier_parameters: try: - setattr(physics_setting, param_name, physics_spec.modifier_parameters[param_name]) + if param_name == "seed": + system_setting = test_object.particle_systems[particle_sys_spec.modifier_name] + setattr(system_setting, param_name, particle_sys_spec.modifier_parameters[param_name]) + else: + setattr(particle_setting, param_name, particle_sys_spec.modifier_parameters[param_name]) + if self.verbose: print("\t set parameter '{}' with value '{}'". - format(param_name, physics_spec.modifier_parameters[param_name])) + format(param_name, particle_sys_spec.modifier_parameters[param_name])) except AttributeError: # Clean up first bpy.ops.object.delete() raise AttributeError("Modifier '{}' has no parameter named '{}'". - format(physics_spec.modifier_type, param_name)) - - scene.frame_set(physics_spec.frame_end + 1) + format(particle_sys_spec.modifier_type, param_name)) - self._bake_current_simulation( - test_object, - physics_spec.modifier_type, - physics_spec.modifier_name, - physics_spec.frame_end, - ) + bpy.context.scene.frame_set(particle_sys_spec.frame_end) + test_object.select_set(True) + bpy.ops.object.duplicates_make_real() + test_object.select_set(True) + bpy.ops.object.join() if self.apply_modifier: - bpy.ops.object.modifier_apply(modifier=physics_spec.modifier_name) + self._apply_modifier(test_object, particle_sys_spec.modifier_name) - def _apply_operator(self, test_object, operator: OperatorSpec): + def _apply_operator_edit_mode(self, test_object, operator: OperatorSpecEditMode): """ Apply operator on test object. :param test_object: bpy.types.Object - Blender object to apply operator on. - :param operator: OperatorSpec - OperatorSpec object with parameters. + :param operator: OperatorSpecEditMode - OperatorSpecEditMode object with parameters. """ mesh = test_object.data bpy.ops.object.mode_set(mode='EDIT') @@ -340,15 +457,64 @@ class MeshTest: bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_mode(type=operator.select_mode) mesh_operator = getattr(bpy.ops.mesh, operator.operator_name) - if not mesh_operator: - raise AttributeError("No mesh operator {}".format(operator.operator_name)) - retval = mesh_operator(**operator.operator_parameters) + + try: + retval = mesh_operator(**operator.operator_parameters) + except AttributeError: + raise AttributeError("bpy.ops.mesh has no attribute {}".format(operator.operator_name)) + except TypeError as ex: + raise TypeError("Incorrect operator parameters {!r} raised {!r}".format(operator.operator_parameters, ex)) + + if retval != {'FINISHED'}: + raise RuntimeError("Unexpected operator return value: {}".format(retval)) + if self.verbose: + print("Applied {}".format(operator)) + + bpy.ops.object.mode_set(mode='OBJECT') + + def _apply_operator_object_mode(self, operator: OperatorSpecObjectMode): + """ + Applies the object operator. + """ + bpy.ops.object.mode_set(mode='OBJECT') + object_operator = getattr(bpy.ops.object, operator.operator_name) + + try: + retval = object_operator(**operator.operator_parameters) + except AttributeError: + raise AttributeError("bpy.ops.mesh has no attribute {}".format(operator.operator_name)) + except TypeError as ex: + raise TypeError("Incorrect operator parameters {!r} raised {!r}".format(operator.operator_parameters, ex)) + if retval != {'FINISHED'}: raise RuntimeError("Unexpected operator return value: {}".format(retval)) if self.verbose: print("Applied operator {}".format(operator)) + def _apply_deform_modifier(self, test_object, operation: list): + """ + param: operation: list: List of modifiers or combination of modifier and object operator. + """ + + scene = bpy.context.scene + scene.frame_set(1) bpy.ops.object.mode_set(mode='OBJECT') + modifier_operations_list = operation.modifier_list + modifier_names = [] + object_operations = operation.object_operator_spec + for modifier_operations in modifier_operations_list: + if isinstance(modifier_operations, ModifierSpec): + self._add_modifier(test_object, modifier_operations) + modifier_names.append(modifier_operations.modifier_name) + + if isinstance(object_operations, OperatorSpecObjectMode): + self._apply_operator_object_mode(object_operations) + + scene.frame_set(operation.frame_number) + + if self.apply_modifier: + for mod_name in modifier_names: + self._apply_modifier(test_object, mod_name) def run_test(self): """ @@ -369,24 +535,40 @@ class MeshTest: evaluated_test_object = bpy.context.active_object evaluated_test_object.name = "evaluated_object" if self.verbose: + print() print(evaluated_test_object.name, "is set to active") # Add modifiers and operators. for operation in self.operations_stack: if isinstance(operation, ModifierSpec): - self._apply_modifier(evaluated_test_object, operation) + self._add_modifier(evaluated_test_object, operation) + if self.apply_modifier: + self._apply_modifier(evaluated_test_object, operation.modifier_name) + + elif isinstance(operation, OperatorSpecEditMode): + self._apply_operator_edit_mode(evaluated_test_object, operation) + + elif isinstance(operation, OperatorSpecObjectMode): + self._apply_operator_object_mode(operation) - elif isinstance(operation, OperatorSpec): - self._apply_operator(evaluated_test_object, operation) + elif isinstance(operation, DeformModifierSpec): + self._apply_deform_modifier(evaluated_test_object, operation) + + elif isinstance(operation, ParticleSystemSpec): + self._apply_particle_system(evaluated_test_object, operation) - elif isinstance(operation, PhysicsSpec): - self._apply_physics_settings(evaluated_test_object, operation) else: - raise ValueError("Expected operation of type {} or {} or {}. Got {}". - format(type(ModifierSpec), type(OperatorSpec), type(PhysicsSpec), - type(operation))) + raise ValueError("Expected operation of type {} or {} or {} or {}. Got {}". + format(type(ModifierSpec), type(OperatorSpecEditMode), + type(OperatorSpecObjectMode), type(ParticleSystemSpec), type(operation))) # Compare resulting mesh with expected one. + # Compare only when self.do_compare is set to True, it is set to False for run-test and returns. + if not self.do_compare: + print("Meshes/objects are not compared, compare evaluated and expected object in Blender for " + "visualization only.") + return False + if self.verbose: print("Comparing expected mesh with resulting mesh...") evaluated_test_mesh = evaluated_test_object.data @@ -415,75 +597,80 @@ class MeshTest: return self._on_failed_test(compare_result, validation_success, evaluated_test_object) -class OperatorTest: +class RunTest: """ - Helper class that stores and executes operator tests. + Helper class that stores and executes modifier tests. Example usage: + >>> modifier_list = [ + >>> ModifierSpec("firstSUBSURF", "SUBSURF", {"quality": 5}), + >>> ModifierSpec("firstSOLIDIFY", "SOLIDIFY", {"thickness_clamp": 0.9, "thickness": 1}) + >>> ] + >>> operator_list = [ + >>> OperatorSpecEditMode("delete_edgeloop", {}, "EDGE", MONKEY_LOOP_EDGE), + >>> ] >>> tests = [ - >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION'}], - >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT'}], + >>> MeshTest("Test1", "testCube", "expectedCube", modifier_list), + >>> MeshTest("Test2", "testCube_2", "expectedCube_2", modifier_list), + >>> MeshTest("MonkeyDeleteEdge", "testMonkey","expectedMonkey", operator_list) >>> ] - >>> operator_test = OperatorTest(tests) - >>> operator_test.run_all_tests() + >>> modifiers_test = RunTest(tests) + >>> modifiers_test.run_all_tests() """ - def __init__(self, operator_tests): + def __init__(self, tests, apply_modifiers=False, do_compare=False): """ - Constructs an operator test. - :param operator_tests: list - list of operator test cases. Each element in the list must contain the following + Construct a modifier test. + :param tests: list - list of modifier or operator test cases. Each element in the list must contain the + following in the correct order: - 1) select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE' - 2) selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10]. - 3) test_object_name: bpy.Types.Object - test object - 4) expected_object_name: bpy.Types.Object - expected object - 5) operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill" - 6) operator_parameters: dict - {name : val} dictionary containing operator parameters. - """ - self.operator_tests = operator_tests + 0) test_name: str - unique test name + 1) test_object_name: bpy.Types.Object - test object + 2) expected_object_name: bpy.Types.Object - expected object + 3) modifiers or operators: list - list of mesh_test.ModifierSpec objects or + mesh_test.OperatorSpecEditMode objects + """ + self.tests = tests + self._ensure_unique_test_name_or_raise_error() + self.apply_modifiers = apply_modifiers + self.do_compare = do_compare self.verbose = os.environ.get("BLENDER_VERBOSE") is not None self._failed_tests_list = [] - def run_test(self, index: int): + def _ensure_unique_test_name_or_raise_error(self): """ - Run a single test from operator_tests list - :param index: int - index of test - :return: bool - True if test is successful. False otherwise. + Check if the test name is unique else raise an error. """ - case = self.operator_tests[index] - if len(case) != 6: - raise ValueError("Expected exactly 6 parameters for each test case, got {}".format(len(case))) - select_mode = case[0] - selection = case[1] - test_object_name = case[2] - expected_object_name = case[3] - operator_name = case[4] - operator_parameters = case[5] - - operator_spec = OperatorSpec(operator_name, operator_parameters, select_mode, selection) + all_test_names = [] + for each_test in self.tests: + test_name = each_test.test_name + all_test_names.append(test_name) - test = MeshTest(test_object_name, expected_object_name) - test.add_operator(operator_spec) - - success = test.run_test() - if test.is_test_updated(): - # Run the test again if the blend file has been updated. - success = test.run_test() - return success + seen_name = set() + for ele in all_test_names: + if ele in seen_name: + raise ValueError("{} is a duplicate, write a new unique name.".format(ele)) + else: + seen_name.add(ele) def run_all_tests(self): - for index, _ in enumerate(self.operator_tests): + """ + Run all tests in self.tests list. Raises an exception if one the tests fails. + """ + for test_number, each_test in enumerate(self.tests): + test_name = each_test.test_name if self.verbose: print() - print("Running test {}...".format(index)) - success = self.run_test(index) + print("Running test {}...".format(test_number)) + print("Test name {}\n".format(test_name)) + success = self.run_test(test_name) if not success: - self._failed_tests_list.append(index) + self._failed_tests_list.append(test_name) if len(self._failed_tests_list) != 0: - print("Following tests failed: {}".format(self._failed_tests_list)) + print("\nFollowing tests failed: {}".format(self._failed_tests_list)) blender_path = bpy.app.binary_path blend_path = bpy.data.filepath @@ -493,63 +680,31 @@ class OperatorTest: print("Run following command to open Blender and run the failing test:") print("{} {} --python {} -- {} {}" - .format(blender_path, blend_path, python_path, "--run-test", "")) + .format(blender_path, blend_path, python_path, "--run-test", "")) raise Exception("Tests {} failed".format(self._failed_tests_list)) - -class ModifierTest: - """ - Helper class that stores and executes modifier tests. - - Example usage: - - >>> modifier_list = [ - >>> ModifierSpec("firstSUBSURF", "SUBSURF", {"quality": 5}), - >>> ModifierSpec("firstSOLIDIFY", "SOLIDIFY", {"thickness_clamp": 0.9, "thickness": 1}) - >>> ] - >>> tests = [ - >>> ["testCube", "expectedCube", modifier_list], - >>> ["testCube_2", "expectedCube_2", modifier_list] - >>> ] - >>> modifiers_test = ModifierTest(tests) - >>> modifiers_test.run_all_tests() - """ - - def __init__(self, modifier_tests: list, apply_modifiers=False, threshold=None): + def run_test(self, test_name: str): """ - Construct a modifier test. - :param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following - in the correct order: - 1) test_object_name: bpy.Types.Object - test object - 2) expected_object_name: bpy.Types.Object - expected object - 3) modifiers: list - list of mesh_test.ModifierSpec objects. - """ - self.modifier_tests = modifier_tests - self.apply_modifiers = apply_modifiers - self.threshold = threshold - self.verbose = os.environ.get("BLENDER_VERBOSE") is not None - self._failed_tests_list = [] - - def run_test(self, index: int): - """ - Run a single test from self.modifier_tests list - :param index: int - index of test + Run a single test from self.tests list + :param test_name: int - name of test :return: bool - True if test passed, False otherwise. """ - case = self.modifier_tests[index] - if len(case) != 3: - raise ValueError("Expected exactly 3 parameters for each test case, got {}".format(len(case))) - test_object_name = case[0] - expected_object_name = case[1] - spec_list = case[2] + case = None + for index, each_test in enumerate(self.tests): + if test_name == each_test.test_name: + case = self.tests[index] + break + + if case is None: + raise Exception('No test called {} found!'.format(test_name)) - test = MeshTest(test_object_name, expected_object_name, threshold=self.threshold) + test = case if self.apply_modifiers: test.apply_modifier = True - for modifier_spec in spec_list: - test.add_modifier(modifier_spec) + if self.do_compare: + test.do_compare = True success = test.run_test() if test.is_test_updated(): @@ -557,31 +712,3 @@ class ModifierTest: success = test.run_test() return success - - def run_all_tests(self): - """ - Run all tests in self.modifiers_tests list. Raises an exception if one the tests fails. - """ - for index, _ in enumerate(self.modifier_tests): - if self.verbose: - print() - print("Running test {}...\n".format(index)) - success = self.run_test(index) - - if not success: - self._failed_tests_list.append(index) - - if len(self._failed_tests_list) != 0: - print("Following tests failed: {}".format(self._failed_tests_list)) - - blender_path = bpy.app.binary_path - blend_path = bpy.data.filepath - frame = inspect.stack()[1] - module = inspect.getmodule(frame[0]) - python_path = module.__file__ - - print("Run following command to open Blender and run the failing test:") - print("{} {} --python {} -- {} {}" - .format(blender_path, blend_path, python_path, "--run-test", "")) - - raise Exception("Tests {} failed".format(self._failed_tests_list)) diff --git a/tests/python/operators.py b/tests/python/operators.py index 901820c7b2d..93cdfebab7b 100644 --- a/tests/python/operators.py +++ b/tests/python/operators.py @@ -26,7 +26,7 @@ from random import shuffle, seed seed(0) sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import OperatorTest, OperatorSpec +from modules.mesh_test import MeshTest, OperatorSpecEditMode, RunTest # Central vertical loop of Suzanne MONKEY_LOOP_VERT = {68, 69, 71, 73, 74, 75, 76, 77, 90, 129, 136, 175, 188, 189, 198, 207, @@ -39,126 +39,181 @@ def main(): tests = [ #### 0 # bisect - ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBisect", "expectedCubeBisect", "bisect", - {"plane_co": (0, 0, 0), "plane_no": (0, 1, 1), "clear_inner": True, "use_fill": True}], + MeshTest("CubeBisect", "testCubeBisect", "expectedCubeBisect", + [OperatorSpecEditMode("bisect", + {"plane_co": (0, 0, 0), "plane_no": (0, 1, 1), "clear_inner": True, + "use_fill": True}, 'FACE', {0, 1, 2, 3, 4, 5}, )]), # blend from shape - ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBlendFromShape", "expectedCubeBlendFromShape", "blend_from_shape", - {"shape": "Key 1"}], + MeshTest("CubeBlendFromShape", "testCubeBlendFromShape", "expectedCubeBlendFromShape", + [OperatorSpecEditMode("blend_from_shape", {"shape": "Key 1"}, 'FACE', {0, 1, 2, 3, 4, 5})]), # bridge edge loops - ["FACE", {0, 1}, "testCubeBrigeEdgeLoop", "expectedCubeBridgeEdgeLoop", "bridge_edge_loops", {}], + MeshTest("CubeBridgeEdgeLoop", "testCubeBrigeEdgeLoop", "expectedCubeBridgeEdgeLoop", + [OperatorSpecEditMode("bridge_edge_loops", {}, "FACE", {0, 1})]), # decimate - ["FACE", {i for i in range(500)}, "testMonkeyDecimate", "expectedMonkeyDecimate", "decimate", {"ratio": 0.1}], + MeshTest("MonkeyDecimate", "testMonkeyDecimate", "expectedMonkeyDecimate", + [OperatorSpecEditMode("decimate", + {"ratio": 0.1}, "FACE", {i for i in range(500)})]), ### 4 # delete - ["VERT", {3}, "testCubeDeleteVertices", "expectedCubeDeleteVertices", "delete", {}], - ["FACE", {0}, "testCubeDeleteFaces", "expectedCubeDeleteFaces", "delete", {}], - ["EDGE", {0, 1, 2, 3}, "testCubeDeleteEdges", "expectedCubeDeleteEdges", "delete", {}], + MeshTest("CubeDeleteVertices", "testCubeDeleteVertices", "expectedCubeDeleteVertices", + [OperatorSpecEditMode("delete", {}, "VERT", {3})]), + MeshTest("CubeDeleteFaces", "testCubeDeleteFaces", "expectedCubeDeleteFaces", + [OperatorSpecEditMode("delete", {}, "FACE", {0})]), + MeshTest("CubeDeleteEdges", "testCubeDeleteEdges", "expectedCubeDeleteEdges", + [OperatorSpecEditMode("delete", {}, "EDGE", {0, 1, 2, 3})]), # delete edge loop - ["VERT", MONKEY_LOOP_VERT, "testMokneyDeleteEdgeLoopVertices", "expectedMonkeyDeleteEdgeLoopVertices", - "delete_edgeloop", {}], - ["EDGE", MONKEY_LOOP_EDGE, "testMokneyDeleteEdgeLoopEdges", "expectedMonkeyDeleteEdgeLoopEdges", - "delete_edgeloop", {}], + MeshTest("MonkeyDeleteEdgeLoopVertices", "testMokneyDeleteEdgeLoopVertices", + "expectedMonkeyDeleteEdgeLoopVertices", + [OperatorSpecEditMode("delete_edgeloop", {}, "VERT", MONKEY_LOOP_VERT)]), + + MeshTest("MonkeyDeleteEdgeLoopEdges", "testMokneyDeleteEdgeLoopEdges", + "expectedMonkeyDeleteEdgeLoopEdges", + [OperatorSpecEditMode("delete_edgeloop", {}, "EDGE", MONKEY_LOOP_EDGE)]), ### 9 # delete loose - ["VERT", {i for i in range(12)}, "testCubeDeleteLooseVertices", "expectedCubeDeleteLooseVertices", - "delete_loose", {"use_verts": True, "use_edges": False, "use_faces": False}], - ["EDGE", {i for i in range(14)}, "testCubeDeleteLooseEdges", "expectedCubeDeleteLooseEdges", - "delete_loose", {"use_verts": False, "use_edges": True, "use_faces": False}], - ["FACE", {i for i in range(7)}, "testCubeDeleteLooseFaces", "expectedCubeDeleteLooseFaces", - "delete_loose", {"use_verts": False, "use_edges": False, "use_faces": True}], + MeshTest("CubeDeleteLooseVertices", "testCubeDeleteLooseVertices", + "expectedCubeDeleteLooseVertices", + [OperatorSpecEditMode("delete_loose", {"use_verts": True, "use_edges": False, "use_faces": False}, + "VERT", + {i for i in range(12)})]), + MeshTest("CubeDeleteLooseEdges", "testCubeDeleteLooseEdges", + "expectedCubeDeleteLooseEdges", + [OperatorSpecEditMode("delete_loose", {"use_verts": False, "use_edges": True, "use_faces": False}, + "EDGE", + {i for i in range(14)})]), + MeshTest("CubeDeleteLooseFaces", "testCubeDeleteLooseFaces", + "expectedCubeDeleteLooseFaces", + [OperatorSpecEditMode("delete_loose", {"use_verts": False, "use_edges": False, "use_faces": True}, + "FACE", + {i for i in range(7)})]), # dissolve degenerate - ["VERT", {i for i in range(8)}, "testCubeDissolveDegenerate", "expectedCubeDissolveDegenerate", - "dissolve_degenerate", {}], + MeshTest("CubeDissolveDegenerate", "testCubeDissolveDegenerate", + "expectedCubeDissolveDegenerate", + [OperatorSpecEditMode("dissolve_degenerate", {}, "VERT", {i for i in range(8)})]), ### 13 # dissolve edges - ["EDGE", {0, 5, 6, 9}, "testCylinderDissolveEdges", "expectedCylinderDissolveEdges", - "dissolve_edges", {}], + MeshTest("CylinderDissolveEdges", "testCylinderDissolveEdges", "expectedCylinderDissolveEdges", + [OperatorSpecEditMode("dissolve_edges", {}, "EDGE", {0, 5, 6, 9})]), # dissolve faces - ["VERT", {5, 34, 47, 49, 83, 91, 95}, "testCubeDissolveFaces", "expectedCubeDissolveFaces", "dissolve_faces", - {}], + MeshTest("CubeDissolveFaces", "testCubeDissolveFaces", "expectedCubeDissolveFaces", + [OperatorSpecEditMode("dissolve_faces", {}, "VERT", {5, 34, 47, 49, 83, 91, 95})]), ### 15 # dissolve verts - ["VERT", {16, 20, 22, 23, 25}, "testCubeDissolveVerts", "expectedCubeDissolveVerts", "dissolve_verts", {}], + MeshTest("CubeDissolveVerts", "testCubeDissolveVerts", "expectedCubeDissolveVerts", + [OperatorSpecEditMode("dissolve_verts", {}, "VERT", {16, 20, 22, 23, 25})]), # duplicate - ["VERT", {i for i in range(33)} - {23}, "testConeDuplicateVertices", "expectedConeDuplicateVertices", - "duplicate", {}], - ["VERT", {23}, "testConeDuplicateOneVertex", "expectedConeDuplicateOneVertex", "duplicate", {}], - ["FACE", {6, 9}, "testConeDuplicateFaces", "expectedConeDuplicateFaces", "duplicate", {}], - ["EDGE", {i for i in range(64)}, "testConeDuplicateEdges", "expectedConeDuplicateEdges", "duplicate", {}], + MeshTest("ConeDuplicateVertices", "testConeDuplicateVertices", + "expectedConeDuplicateVertices", + [OperatorSpecEditMode("duplicate", {}, "VERT", {i for i in range(33)} - {23})]), + + MeshTest("ConeDuplicateOneVertex", "testConeDuplicateOneVertex", "expectedConeDuplicateOneVertex", + [OperatorSpecEditMode("duplicate", {}, "VERT", {23})]), + MeshTest("ConeDuplicateFaces", "testConeDuplicateFaces", "expectedConeDuplicateFaces", + [OperatorSpecEditMode("duplicate", {}, "FACE", {6, 9})]), + MeshTest("ConeDuplicateEdges", "testConeDuplicateEdges", "expectedConeDuplicateEdges", + [OperatorSpecEditMode("duplicate", {}, "EDGE", {i for i in range(64)})]), ### 20 # edge collapse - ["EDGE", {1, 9, 4}, "testCylinderEdgeCollapse", "expectedCylinderEdgeCollapse", "edge_collapse", {}], + MeshTest("CylinderEdgeCollapse", "testCylinderEdgeCollapse", "expectedCylinderEdgeCollapse", + [OperatorSpecEditMode("edge_collapse", {}, "EDGE", {1, 9, 4})]), # edge face add - ["VERT", {1, 3, 4, 5, 7}, "testCubeEdgeFaceAddFace", "expectedCubeEdgeFaceAddFace", "edge_face_add", {}], - ["VERT", {4, 5}, "testCubeEdgeFaceAddEdge", "expectedCubeEdgeFaceAddEdge", "edge_face_add", {}], + MeshTest("CubeEdgeFaceAddFace", "testCubeEdgeFaceAddFace", "expectedCubeEdgeFaceAddFace", + [OperatorSpecEditMode("edge_face_add", {}, "VERT", {1, 3, 4, 5, 7})]), + MeshTest("CubeEdgeFaceAddEdge", "testCubeEdgeFaceAddEdge", "expectedCubeEdgeFaceAddEdge", + [OperatorSpecEditMode("edge_face_add", {}, "VERT", {4, 5})]), # edge rotate - ["EDGE", {1}, "testCubeEdgeRotate", "expectedCubeEdgeRotate", "edge_rotate", {}], + MeshTest("CubeEdgeRotate", "testCubeEdgeRotate", "expectedCubeEdgeRotate", + [OperatorSpecEditMode("edge_rotate", {}, "EDGE", {1})]), # edge split - ["EDGE", {2, 5, 8, 11, 14, 17, 20, 23}, "testCubeEdgeSplit", "expectedCubeEdgeSplit", "edge_split", {}], + MeshTest("CubeEdgeSplit", "testCubeEdgeSplit", "expectedCubeEdgeSplit", + [OperatorSpecEditMode("edge_split", {}, "EDGE", {2, 5, 8, 11, 14, 17, 20, 23})]), ### 25 # face make planar - ["FACE", {i for i in range(500)}, "testMonkeyFaceMakePlanar", "expectedMonkeyFaceMakePlanar", - "face_make_planar", {}], + MeshTest("MonkeyFaceMakePlanar", "testMonkeyFaceMakePlanar", + "expectedMonkeyFaceMakePlanar", + [OperatorSpecEditMode("face_make_planar", {}, "FACE", {i for i in range(500)})]), # face split by edges - ["VERT", {i for i in range(6)}, "testPlaneFaceSplitByEdges", "expectedPlaneFaceSplitByEdges", - "face_split_by_edges", {}], + MeshTest("PlaneFaceSplitByEdges", "testPlaneFaceSplitByEdges", + "expectedPlaneFaceSplitByEdges", + [OperatorSpecEditMode("face_split_by_edges", {}, "VERT", {i for i in range(6)})]), # fill - ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFill", "expectedIcosphereFill", - "fill", {}], - ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFillUseBeautyFalse", - "expectedIcosphereFillUseBeautyFalse", "fill", {"use_beauty": False}], + MeshTest("IcosphereFill", "testIcosphereFill", "expectedIcosphereFill", + [OperatorSpecEditMode("fill", {}, "EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49})]), + MeshTest("IcosphereFillUseBeautyFalse", + "testIcosphereFillUseBeautyFalse", "expectedIcosphereFillUseBeautyFalse", + [OperatorSpecEditMode("fill", {"use_beauty": False}, "EDGE", + {20, 21, 22, 23, 24, 45, 46, 47, 48, 49})]), # fill grid - ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGrid", "expectedPlaneFillGrid", - "fill_grid", {}], - ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGridSimpleBlending", - "expectedPlaneFillGridSimpleBlending", "fill_grid", {"use_interp_simple": True}], + MeshTest("PlaneFillGrid", "testPlaneFillGrid", + "expectedPlaneFillGrid", + [OperatorSpecEditMode("fill_grid", {}, "EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15})]), + + MeshTest("PlaneFillGridSimpleBlending", + "testPlaneFillGridSimpleBlending", + "expectedPlaneFillGridSimpleBlending", + [OperatorSpecEditMode("fill_grid", {"use_interp_simple": True}, "EDGE", + {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15})]), ### 31 # fill holes - ["VERT", {i for i in range(481)}, "testSphereFillHoles", "expectedSphereFillHoles", "fill_holes", {"sides": 9}], + MeshTest("SphereFillHoles", "testSphereFillHoles", "expectedSphereFillHoles", + [OperatorSpecEditMode("fill_holes", {"sides": 9}, "VERT", {i for i in range(481)})]), # inset faces - ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInset", - "expectedCubeInset", "inset", {"thickness": 0.2}], - ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, - "testCubeInsetEvenOffsetFalse", "expectedCubeInsetEvenOffsetFalse", - "inset", {"thickness": 0.2, "use_even_offset": False}], - ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInsetDepth", - "expectedCubeInsetDepth", "inset", {"thickness": 0.2, "depth": 0.2}], - ["FACE", {35, 36, 37, 45, 46, 47, 55, 56, 57}, "testGridInsetRelativeOffset", "expectedGridInsetRelativeOffset", - "inset", {"thickness": 0.4, "use_relative_offset": True}], + MeshTest("CubeInset", + "testCubeInset", "expectedCubeInset", [OperatorSpecEditMode("inset", {"thickness": 0.2}, "VERT", + {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, + 52, + 59, 61, 62, 65, 83, 91, 95})]), + + MeshTest("CubeInsetEvenOffsetFalse", + "testCubeInsetEvenOffsetFalse", "expectedCubeInsetEvenOffsetFalse", + [OperatorSpecEditMode("inset", {"thickness": 0.2, "use_even_offset": False}, "VERT", + {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95})]), + MeshTest("CubeInsetDepth", + "testCubeInsetDepth", + "expectedCubeInsetDepth", [OperatorSpecEditMode("inset", {"thickness": 0.2, "depth": 0.2}, "VERT", + {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, + 62, + 65, 83, 91, 95})]), + MeshTest("GridInsetRelativeOffset", "testGridInsetRelativeOffset", + "expectedGridInsetRelativeOffset", + [OperatorSpecEditMode("inset", {"thickness": 0.4, + "use_relative_offset": True}, "FACE", + {35, 36, 37, 45, 46, 47, 55, 56, 57})]), ] - operators_test = OperatorTest(tests) + operators_test = RunTest(tests) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": + operators_test.do_compare = True operators_test.run_all_tests() break elif cmd == "--run-test": - operators_test.apply_modifiers = False - index = int(command[i + 1]) - operators_test.run_test(index) + operators_test.do_compare = False + name = command[i + 1] + operators_test.run_test(name) break diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py index 5b9151ea089..b88b4d63f9d 100644 --- a/tests/python/physics_cloth.py +++ b/tests/python/physics_cloth.py @@ -24,26 +24,42 @@ import sys import bpy sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import ModifierTest, PhysicsSpec +from modules.mesh_test import RunTest, ModifierSpec, MeshTest def main(): test = [ - ["testCloth", "expectedCloth", - [PhysicsSpec('Cloth', 'CLOTH', {'quality': 5}, 35)]], + + MeshTest("ClothSimple", "testClothPlane", "expectedClothPlane", + [ModifierSpec('Cloth', 'CLOTH', {'settings': {'quality': 5}}, 15)], threshold=1e-3), + + # Not reproducible + # MeshTest("ClothPressure", "testObjClothPressure", "expObjClothPressure", + # [ModifierSpec('Cloth2', 'CLOTH', {'settings': {'use_pressure': True, + # 'uniform_pressure_force': 1}}, 16)]), + + # Not reproducible + # MeshTest("ClothSelfCollision", "testClothCollision", "expClothCollision", + # [ModifierSpec('Cloth', 'CLOTH', {'collision_settings': {'use_self_collision': True}}, 67)]), + + MeshTest("ClothSpring", "testTorusClothSpring", "expTorusClothSpring", + [ModifierSpec('Cloth2', 'CLOTH', {'settings': {'use_internal_springs': True}}, 10)], threshold=1e-3), + ] - cloth_test = ModifierTest(test, threshold=1e-3) + cloth_test = RunTest(test) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": cloth_test.apply_modifiers = True + cloth_test.do_compare = True cloth_test.run_all_tests() break elif cmd == "--run-test": cloth_test.apply_modifiers = False - index = int(command[i + 1]) - cloth_test.run_test(index) + cloth_test.do_compare = False + name = command[i + 1] + cloth_test.run_test(name) break diff --git a/tests/python/physics_dynamic_paint.py b/tests/python/physics_dynamic_paint.py new file mode 100644 index 00000000000..b5d09c8cb3a --- /dev/null +++ b/tests/python/physics_dynamic_paint.py @@ -0,0 +1,58 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import RunTest, ModifierSpec, MeshTest + + +def main(): + test = [ + + MeshTest("DynamicPaintSimple", "testObjDynamicPaintPlane", "expObjDynamicPaintPlane", + [ModifierSpec('dynamic_paint', 'DYNAMIC_PAINT', + {'ui_type': 'CANVAS', + 'canvas_settings': {'canvas_surfaces': {'surface_type': 'WAVE', 'frame_end': 15}}}, + 15)]), + + ] + dynamic_paint_test = RunTest(test) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + dynamic_paint_test.apply_modifiers = True + dynamic_paint_test.do_compare = True + dynamic_paint_test.run_all_tests() + break + elif cmd == "--run-test": + dynamic_paint_test.apply_modifiers = False + dynamic_paint_test.do_compare = False + name = command[i + 1] + dynamic_paint_test.run_test(name) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/physics_ocean.py b/tests/python/physics_ocean.py new file mode 100644 index 00000000000..40227d3d8d7 --- /dev/null +++ b/tests/python/physics_ocean.py @@ -0,0 +1,54 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import RunTest, ModifierSpec, MeshTest + + +def main(): + test = [ + # World coordinates of test and expected object should be same. + MeshTest("PlaneOcean", "testObjPlaneOcean", "expObjPlaneOcean", + [ModifierSpec('Ocean', 'OCEAN', {})]), + ] + ocean_test = RunTest(test) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + ocean_test.apply_modifiers = True + ocean_test.do_compare = True + ocean_test.run_all_tests() + break + elif cmd == "--run-test": + ocean_test.apply_modifiers = False + ocean_test.do_compare = False + name = command[i + 1] + ocean_test.run_test(name) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/physics_particle_instance.py b/tests/python/physics_particle_instance.py new file mode 100644 index 00000000000..e12e357e4ce --- /dev/null +++ b/tests/python/physics_particle_instance.py @@ -0,0 +1,56 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import RunTest, ModifierSpec, MeshTest + + +def main(): + test = [ + + MeshTest("ParticleInstanceSimple", "testParticleInstance", "expectedParticleInstance", + [ModifierSpec('ParticleInstance', 'PARTICLE_INSTANCE', {'object': bpy.data.objects['Cube']})], + threshold=1e-3), + + ] + particle_instance_test = RunTest(test) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + particle_instance_test.apply_modifiers = True + particle_instance_test.do_compare = True + particle_instance_test.run_all_tests() + break + elif cmd == "--run-test": + particle_instance_test.apply_modifiers = False + particle_instance_test.do_compare = False + name = command[i + 1] + particle_instance_test.run_test(name) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/physics_particle_system.py b/tests/python/physics_particle_system.py new file mode 100644 index 00000000000..0adc5ab1c54 --- /dev/null +++ b/tests/python/physics_particle_system.py @@ -0,0 +1,55 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import RunTest, ParticleSystemSpec, MeshTest + + +def main(): + test = [ + MeshTest("ParticleSystemTest", "testParticleSystem", "expParticleSystem", + [ParticleSystemSpec('Particles', 'PARTICLE_SYSTEM', {'render_type': "OBJECT", + 'instance_object': bpy.data.objects['Cube']}, 20)], threshold=1e-3), + + ] + particle_test = RunTest(test) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + particle_test.apply_modifiers = True + particle_test.do_compare = True + particle_test.run_all_tests() + break + elif cmd == "--run-test": + particle_test.apply_modifiers = False + particle_test.do_compare = False + name = command[i + 1] + particle_test.run_test(name) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py index 8d431be742c..985b3a29bb4 100644 --- a/tests/python/physics_softbody.py +++ b/tests/python/physics_softbody.py @@ -24,26 +24,31 @@ import sys import bpy sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from modules.mesh_test import ModifierTest, PhysicsSpec +from modules.mesh_test import RunTest, ModifierSpec, MeshTest def main(): test = [ - ["testSoftBody", "expectedSoftBody", - [PhysicsSpec('Softbody', 'SOFT_BODY', {'use_goal': False, 'bend': 8, 'pull': 0.8, 'push': 0.8}, 45)]], + + MeshTest("SoftBodySimple", "testSoftBody", "expectedSoftBody", + [ModifierSpec('Softbody', 'SOFT_BODY', + {'settings': {'use_goal': False, 'bend': 8, 'pull': 0.8, 'push': 0.8}}, + 45)]), ] - softBody_test = ModifierTest(test) + soft_body_test = RunTest(test) command = list(sys.argv) for i, cmd in enumerate(command): if cmd == "--run-all-tests": - softBody_test.apply_modifiers = True - softBody_test.run_all_tests() + soft_body_test.apply_modifiers = True + soft_body_test.do_compare = True + soft_body_test.run_all_tests() break elif cmd == "--run-test": - softBody_test.apply_modifiers = False - index = int(command[i + 1]) - softBody_test.run_test(index) + soft_body_test.apply_modifiers = False + soft_body_test.do_compare = False + name = command[i + 1] + soft_body_test.run_test(name) break -- cgit v1.2.3