diff options
Diffstat (limited to 'tests/python')
25 files changed, 363 insertions, 144 deletions
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index db5d5dcf73b..a3df01fdbe2 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -48,18 +48,14 @@ endfunction() # Run Python script outside Blender. function(add_python_test testname testscript) - if(MSVC) - add_test( - NAME ${testname} - COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN} - ) - else() - add_test( - NAME ${testname} - COMMAND ${testscript} ${ARGN} - ) + if(NOT TEST_PYTHON_EXE) + message(FATAL_ERROR "No Python configured for running tests, set TEST_PYTHON_EXE.") endif() + add_test( + NAME ${testname} + COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN} + ) set_tests_properties(${testname} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0) endfunction() @@ -189,6 +185,22 @@ add_blender_test( ) add_blender_test( + physics_cloth + ${TEST_SRC_DIR}/physics/cloth_test.blend + --python ${TEST_PYTHON_DIR}/physics_cloth.py + -- + --run-all-tests +) + +add_blender_test( + physics_softbody + ${TEST_SRC_DIR}/physics/softbody_test.blend + --python ${TEST_PYTHON_DIR}/physics_softbody.py + -- + --run-all-tests +) + +add_blender_test( constraints --python ${CMAKE_CURRENT_LIST_DIR}/bl_constraints.py -- diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py index 9de1bc06d84..2d477c5a6f0 100755..100644 --- a/tests/python/alembic_tests.py +++ b/tests/python/alembic_tests.py @@ -76,7 +76,7 @@ class AbstractAlembicTest(AbstractBlenderRunnerTest): output = output.replace('\r\n', '\n').replace('\r', '\n') if proc.returncode: - raise AbcPropError('Error %d running abcls:\n%s' % (proc.returncode, output)) + raise AbcPropError('Error %d running %s:\n%s' % (proc.returncode, ' '.join(command), output)) # Mapping from value type to callable that can convert a string to Python values. converters = { @@ -84,6 +84,7 @@ class AbstractAlembicTest(AbstractBlenderRunnerTest): 'uint8_t': int, 'int16_t': int, 'int32_t': int, + 'uint32_t': int, 'uint64_t': int, 'float64_t': float, 'float32_t': float, @@ -325,6 +326,60 @@ class HairParticlesExportTest(AbstractAlembicTest): self.assertIn('.faceIndices', abcprop) +class UVMapExportTest(AbstractAlembicTest): + @with_tempdir + def test_uvmap_export(self, tempdir: pathlib.Path): + """Minimal test for exporting multiple UV maps on an animated mesh. + + This covers the issue reported in T77021. + """ + basename = 'T77021-multiple-uvmaps-animated-mesh' + abc = tempdir / f'{basename}.abc' + script = f"import bpy; bpy.ops.wm.alembic_export(filepath='{abc.as_posix()}', start=1, end=1, " \ + f"renderable_only=True, visible_objects_only=True, flatten=False)" + self.run_blender(f'{basename}.blend', script) + + self.maxDiff = 1000 + + # The main UV map should be written to .geom + abcprop = self.abcprop(abc, '/Cube/CubeShape/.geom/uv') + self.assertEqual(abcprop['.vals'], [ + [0.625, 0.75], + [0.875, 0.75], + [0.875, 0.5], + [0.625, 0.5], + [0.375, 1.0], + [0.625, 1.0], + [0.375, 0.75], + [0.375, 0.25], + [0.625, 0.25], + [0.625, 0.0], + [0.375, 0.0], + [0.125, 0.75], + [0.375, 0.5], + [0.125, 0.5], + ]) + + # The second UV map should be written to .arbGeomParams + abcprop = self.abcprop(abc, '/Cube/CubeShape/.geom/.arbGeomParams/Secondary') + self.assertEqual(abcprop['.vals'], [ + [0.75, 0.375], + [0.75, 0.125], + [0.5, 0.125], + [0.5, 0.375], + [1.0, 0.625], + [1.0, 0.375], + [0.75, 0.625], + [0.25, 0.625], + [0.25, 0.375], + [0.0, 0.375], + [0.0, 0.625], + [0.75, 0.875], + [0.5, 0.625], + [0.5, 0.875], + ]) + + class LongNamesExportTest(AbstractAlembicTest): @with_tempdir def test_export_long_names(self, tempdir: pathlib.Path): diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py index 3cdbeb9300b..884bd356b96 100644 --- a/tests/python/bevel_operator.py +++ b/tests/python/bevel_operator.py @@ -176,9 +176,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py index 2786a2db4d7..b9eca3057e7 100644 --- a/tests/python/bl_alembic_io_test.py +++ b/tests/python/bl_alembic_io_test.py @@ -375,12 +375,4 @@ def main(): if __name__ == "__main__": - import traceback - # So a python error exits Blender itself too - try: - main() - except SystemExit: - raise - except: - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_blendfile_io.py b/tests/python/bl_blendfile_io.py index 0b055b9d46a..ab06e313566 100644 --- a/tests/python/bl_blendfile_io.py +++ b/tests/python/bl_blendfile_io.py @@ -77,9 +77,4 @@ def main(): if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py index 7d93d7c8455..d1cc7efc7fd 100644 --- a/tests/python/bl_blendfile_liblink.py +++ b/tests/python/bl_blendfile_liblink.py @@ -75,9 +75,4 @@ def main(): if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_bundled_modules.py b/tests/python/bl_bundled_modules.py index 3ef5040af01..d3fe2861d9e 100644 --- a/tests/python/bl_bundled_modules.py +++ b/tests/python/bl_bundled_modules.py @@ -21,7 +21,7 @@ # Test that modules we ship with our Python installation are available import bz2 -import cffi +import ctypes import lzma import numpy import sqlite3 diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py index 13a431541bc..323dd874ac0 100644 --- a/tests/python/bl_constraints.py +++ b/tests/python/bl_constraints.py @@ -56,21 +56,37 @@ class AbstractConstraintTests(unittest.TestCase): actual, expect, places=places, delta=delta, msg=f'Matrix of object {object_name!r} failed: {actual} != {expect} at element [{row}][{col}]') - def matrix(self, object_name: str) -> Matrix: - """Return the evaluated world matrix.""" + def _get_eval_object(self, object_name: str) -> bpy.types.Object: + """Return the evaluated object.""" depsgraph = bpy.context.view_layer.depsgraph depsgraph.update() ob_orig = bpy.context.scene.objects[object_name] ob_eval = ob_orig.evaluated_get(depsgraph) + return ob_eval + + def matrix(self, object_name: str) -> Matrix: + """Return the evaluated world matrix.""" + ob_eval = self._get_eval_object(object_name) return ob_eval.matrix_world + def bone_matrix(self, object_name: str, bone_name: str) -> Matrix: + """Return the evaluated world matrix of the bone.""" + ob_eval = self._get_eval_object(object_name) + bone = ob_eval.pose.bones[bone_name] + return ob_eval.matrix_world @ bone.matrix + def matrix_test(self, object_name: str, expect: Matrix): """Assert that the object's world matrix is as expected.""" actual = self.matrix(object_name) self.assert_matrix(actual, expect, object_name) + def bone_matrix_test(self, object_name: str, bone_name: str, expect: Matrix): + """Assert that the bone's world matrix is as expected.""" + actual = self.bone_matrix(object_name, bone_name) + self.assert_matrix(actual, expect, object_name) + def constraint_context(self, constraint_name: str, owner_name: str='') -> dict: - """Return a context suitable for calling constraint operators. + """Return a context suitable for calling object constraint operators. Assumes the owner is called "{constraint_name}.owner" if owner_name=''. """ @@ -84,6 +100,30 @@ class AbstractConstraintTests(unittest.TestCase): } return context + def bone_constraint_context(self, constraint_name: str, owner_name: str='', bone_name: str='') -> dict: + """Return a context suitable for calling bone constraint operators. + + Assumes the owner's object is called "{constraint_name}.owner" if owner_name=''. + Assumes the bone is called "{constraint_name}.bone" if bone_name=''. + """ + + owner_name = owner_name or f'{constraint_name}.owner' + bone_name = bone_name or f'{constraint_name}.bone' + + owner = bpy.context.scene.objects[owner_name] + pose_bone = owner.pose.bones[bone_name] + + constraint = pose_bone.constraints[constraint_name] + context = { + **bpy.context.copy(), + 'object': owner, + 'active_object': owner, + 'active_pose_bone': pose_bone, + 'constraint': constraint, + 'owner': pose_bone, + } + return context + class ChildOfTest(AbstractConstraintTests): layer_collection = 'Child Of' @@ -153,7 +193,7 @@ class ChildOfTest(AbstractConstraintTests): )) self.matrix_test('Child Of.object.owner', initial_matrix) - context = self.constraint_context('Child Of', owner_name='Child Of.object.owner') + context = self.constraint_context('Child Of', owner_name='Child Of.object.owner',) bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of') self.matrix_test('Child Of.object.owner', Matrix(( (0.9992386102676392, 0.019843991845846176, -0.03359176218509674, 0.10000000149011612), @@ -188,6 +228,29 @@ class ChildOfTest(AbstractConstraintTests): bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of') self.matrix_test('Child Of.armature.owner', initial_matrix) + def test_bone_owner(self): + """Child Of: bone owns constraint, targeting object.""" + initial_matrix = Matrix(( + (0.9992387890815735, -0.03359174728393555, -0.019843988120555878, -2.999999523162842), + (-0.02588011883199215, -0.1900751143693924, -0.9814283847808838, 2.0), + (0.029196053743362427, 0.9811949133872986, -0.190799742937088, 0.9999999403953552), + (0.0, 0.0, 0.0, 1.0), + )) + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', initial_matrix) + + context = self.bone_constraint_context('Child Of', owner_name='Child Of.bone.owner') + bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of', owner='BONE') + + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', Matrix(( + (0.9659260511398315, 0.2588191032409668, 4.656613428188905e-10, -2.999999761581421), + (-3.725290742551124e-09, 1.4901162970204496e-08, -1.0, 0.9999999403953552), + (-0.2588191032409668, 0.965925931930542, 0.0, 0.9999999403953552), + (0.0, 0.0, 0.0, 1.0), + ))) + + bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of', owner='BONE') + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', initial_matrix) + def test_vertexgroup_simple_parent(self): """Child Of: simple evaluation of vertex group parent.""" initial_matrix = Matrix(( @@ -255,12 +318,4 @@ def main(): if __name__ == "__main__": - import traceback - # So a python error exits Blender itself too - try: - main() - except SystemExit: - raise - except: - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py index f0c2f3f7fdf..01f0b4d72d8 100644 --- a/tests/python/bl_load_addons.py +++ b/tests/python/bl_load_addons.py @@ -144,11 +144,4 @@ def main(): if __name__ == "__main__": - - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py index 5d1a5dd8ee0..c6ad53b1f74 100644 --- a/tests/python/bl_load_py_modules.py +++ b/tests/python/bl_load_py_modules.py @@ -234,10 +234,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py index 80f810ffad8..746e7a183a3 100644 --- a/tests/python/bl_mesh_modifiers.py +++ b/tests/python/bl_mesh_modifiers.py @@ -842,17 +842,7 @@ if __name__ == "__main__": print("Load Handler:", bpy.data.filepath) if load_handler.first is False: bpy.app.handlers.scene_update_post.remove(load_handler) - try: - main() - import sys - sys.exit(0) - except: - import traceback - traceback.print_exc() - - # import sys - # sys.exit(1) # comment to debug - + main() else: load_handler.first = False diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py index 47a5e5efe47..8c5d914f92a 100644 --- a/tests/python/bl_mesh_validate.py +++ b/tests/python/bl_mesh_validate.py @@ -152,10 +152,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py index 648b63d1637..44fec6a9043 100644 --- a/tests/python/bl_pyapi_idprop_datablock.py +++ b/tests/python/bl_pyapi_idprop_datablock.py @@ -20,7 +20,6 @@ import bpy import sys import os import tempfile -import traceback import inspect from bpy.types import UIList @@ -331,11 +330,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - - traceback.print_exc() - sys.stderr.flush() - os._exit(1) + main() diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py index 173d575a912..6315ffbfa9d 100644 --- a/tests/python/bl_test.py +++ b/tests/python/bl_test.py @@ -136,12 +136,7 @@ def main(): print(" Running: '%s'" % run) print(" MD5: '%s'!" % md5) - try: - result = eval(run) - except: - import traceback - traceback.print_exc() - sys.exit(1) + result = eval(run) if write_blend is not None: print(" Writing Blend: %s" % write_blend) @@ -188,10 +183,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py index b05e60eea6c..5a674c35a47 100644 --- a/tests/python/boolean_operator.py +++ b/tests/python/boolean_operator.py @@ -60,9 +60,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 79ba11fdd44..79ba11fdd44 100755..100644 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py index a7130136d0a..a7130136d0a 100755..100644 --- a/tests/python/eevee_render_tests.py +++ b/tests/python/eevee_render_tests.py diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py index 92734b5bc7d..92734b5bc7d 100755..100644 --- a/tests/python/ffmpeg_tests.py +++ b/tests/python/ffmpeg_tests.py diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py index 697cddc9ba2..5e032f658af 100644 --- a/tests/python/modifiers.py +++ b/tests/python/modifiers.py @@ -255,9 +255,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py index 9fb487bcef9..af0e78257d5 100644 --- a/tests/python/modules/mesh_test.py +++ b/tests/python/modules/mesh_test.py @@ -41,8 +41,15 @@ import bpy -import os +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... +print = functools.partial(print, flush=True) class ModifierSpec: @@ -66,6 +73,28 @@ class ModifierSpec: " with parameters: " + str(self.modifier_parameters) +class PhysicsSpec: + """ + Holds one Physics 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 + """ + self.modifier_name = modifier_name + self.modifier_type = modifier_type + self.modifier_parameters = modifier_parameters + self.frame_end = frame_end + + def __str__(self): + return "Physics Modifier: " + self.modifier_name + " of type " + self.modifier_type + \ + " with parameters: " + str(self.modifier_parameters) + " with frame end: " + str(self.frame_end) + class OperatorSpec: """ Holds one operator and its parameters. @@ -98,7 +127,7 @@ class MeshTest: the public method run_test(). """ - def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False): + def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False, threshold=None): """ Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name or test_object_name don't exist. @@ -118,6 +147,7 @@ class MeshTest: type(operation))) self.operations_stack = operations_stack self.apply_modifier = apply_modifiers + self.threshold = threshold self.verbose = os.environ.get("BLENDER_VERBOSE") is not None self.update = os.getenv('BLENDER_TEST_UPDATE') is not None @@ -165,8 +195,8 @@ class MeshTest: """ self.operations_stack.append(operator_spec) - def _on_failed_test(self, compare, evaluated_test_object): - if self.update: + def _on_failed_test(self, compare_result, validation_success, evaluated_test_object): + if self.update and validation_success: if self.verbose: print("Test failed expectantly. Updating expected mesh...") @@ -178,8 +208,7 @@ class MeshTest: evaluated_test_object.name = expected_object_name # Save file - blend_file = bpy.data.filepath - bpy.ops.wm.save_as_mainfile(filepath=blend_file) + bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath) self._test_updated = True @@ -188,10 +217,10 @@ class MeshTest: return True else: - blender_file = bpy.data.filepath - print("Test failed with error: {}. Resulting object mesh '{}' did not match expected object '{}' " - "from file blender file {}". - format(compare, evaluated_test_object.name, self.expected_object.name, blender_file)) + print("Test comparison result: {}".format(compare_result)) + print("Test validation result: {}".format(validation_success)) + print("Resulting object mesh '{}' did not match expected object '{}' from file {}". + format(evaluated_test_object.name, self.expected_object.name, bpy.data.filepath)) return False @@ -229,6 +258,49 @@ class MeshTest: if self.apply_modifier: bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name) + + 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} + bpy.ops.ptcache.bake(override, bake=True) + break + + def _apply_physics_settings(self, test_object, physics_spec: PhysicsSpec): + """ + Apply Physics 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 + if self.verbose: + print("Created modifier '{}' of type '{}'.". + format(physics_spec.modifier_name, physics_spec.modifier_type)) + + + for param_name in physics_spec.modifier_parameters: + try: + setattr(physics_setting, param_name, physics_spec.modifier_parameters[param_name]) + if self.verbose: + print("\t set parameter '{}' with value '{}'". + format(param_name, physics_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) + + self._bake_current_simulation(test_object, physics_spec.modifier_type, physics_spec.modifier_name, physics_spec.frame_end) + if self.apply_modifier: + bpy.ops.object.modifier_apply(modifier=physics_spec.modifier_name) + + def _apply_operator(self, test_object, operator: OperatorSpec): """ Apply operator on test object. @@ -296,9 +368,12 @@ class MeshTest: elif isinstance(operation, OperatorSpec): self._apply_operator(evaluated_test_object, operation) + + elif isinstance(operation, PhysicsSpec): + self._apply_physics_settings(evaluated_test_object, operation) else: - raise ValueError("Expected operation of type {} or {}. Got {}". - format(type(ModifierSpec), type(OperatorSpec), + raise ValueError("Expected operation of type {} or {} or {}. Got {}". + format(type(ModifierSpec), type(OperatorSpec), type(PhysicsSpec), type(operation))) # Compare resulting mesh with expected one. @@ -306,10 +381,16 @@ class MeshTest: print("Comparing expected mesh with resulting mesh...") evaluated_test_mesh = evaluated_test_object.data expected_mesh = self.expected_object.data - compare = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) - success = (compare == 'Same') + if self.threshold: + compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh, threshold=self.threshold) + else: + compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) + compare_success = (compare_result == 'Same') - if success: + # Also check if invalid geometry (which is never expected) had to be corrected... + validation_success = evaluated_test_mesh.validate(verbose=True) == False + + if compare_success and validation_success: if self.verbose: print("Success!") @@ -321,7 +402,7 @@ class MeshTest: return True else: - return self._on_failed_test(compare, evaluated_test_object) + return self._on_failed_test(compare_result, validation_success, evaluated_test_object) class OperatorTest: @@ -425,7 +506,7 @@ class ModifierTest: >>> modifiers_test.run_all_tests() """ - def __init__(self, modifier_tests: list, apply_modifiers=False): + def __init__(self, modifier_tests: list, apply_modifiers=False, threshold=None): """ Construct a modifier test. :param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following @@ -436,6 +517,7 @@ class ModifierTest: """ 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 = [] @@ -452,7 +534,7 @@ class ModifierTest: expected_object_name = case[1] spec_list = case[2] - test = MeshTest(test_object_name, expected_object_name) + test = MeshTest(test_object_name, expected_object_name, threshold=self.threshold) if self.apply_modifiers: test.apply_modifier = True diff --git a/tests/python/opengl_draw_tests.py b/tests/python/opengl_draw_tests.py index ab4df63afd9..ab4df63afd9 100755..100644 --- a/tests/python/opengl_draw_tests.py +++ b/tests/python/opengl_draw_tests.py diff --git a/tests/python/operators.py b/tests/python/operators.py index c5b3ac745c6..626aaedc724 100644 --- a/tests/python/operators.py +++ b/tests/python/operators.py @@ -163,10 +163,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py new file mode 100644 index 00000000000..5b9151ea089 --- /dev/null +++ b/tests/python/physics_cloth.py @@ -0,0 +1,51 @@ +# ##### 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 ##### + +# <pep8 compliant> + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import ModifierTest, PhysicsSpec + + +def main(): + test = [ + ["testCloth", "expectedCloth", + [PhysicsSpec('Cloth', 'CLOTH', {'quality': 5}, 35)]], + ] + cloth_test = ModifierTest(test, threshold=1e-3) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + cloth_test.apply_modifiers = 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) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py new file mode 100644 index 00000000000..8d431be742c --- /dev/null +++ b/tests/python/physics_softbody.py @@ -0,0 +1,51 @@ +# ##### 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 ##### + +# <pep8 compliant> + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import ModifierTest, PhysicsSpec + + +def main(): + test = [ + ["testSoftBody", "expectedSoftBody", + [PhysicsSpec('Softbody', 'SOFT_BODY', {'use_goal': False, 'bend': 8, 'pull': 0.8, 'push': 0.8}, 45)]], + ] + softBody_test = ModifierTest(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() + break + elif cmd == "--run-test": + softBody_test.apply_modifiers = False + index = int(command[i + 1]) + softBody_test.run_test(index) + break + + +if __name__ == "__main__": + main() diff --git a/tests/python/workbench_render_tests.py b/tests/python/workbench_render_tests.py index 155b54098a8..155b54098a8 100755..100644 --- a/tests/python/workbench_render_tests.py +++ b/tests/python/workbench_render_tests.py |