From f40d33f24b85a1c1e0e8d8cb0e42146ebcdef5a9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 22 Mar 2011 14:09:07 +0000 Subject: Added CTest to run most operators in background mode under various conditions to see if any crash. used this to find quite a many errors already. --- source/tests/CMakeLists.txt | 5 ++ source/tests/bl_run_operators.py | 186 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 source/tests/bl_run_operators.py (limited to 'source/tests') diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt index e9837dd354f..0430b49181e 100644 --- a/source/tests/CMakeLists.txt +++ b/source/tests/CMakeLists.txt @@ -55,6 +55,11 @@ add_test(script_load_modules ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_py_modules.py ) +# test running operators doesn't segfault under various conditions +add_test(script_run_operators ${TEST_BLENDER_EXE} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_run_operators.py +) + # ------------------------------------------------------------------------------ # IO TESTS diff --git a/source/tests/bl_run_operators.py b/source/tests/bl_run_operators.py new file mode 100644 index 00000000000..703adafad91 --- /dev/null +++ b/source/tests/bl_run_operators.py @@ -0,0 +1,186 @@ +# ##### 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 ##### + +# + +# semi-useful script, runs all operators in a number of different +# contexts, cheap way to find misc small bugs but is in no way a complete test. +# +# only error checked for here is a segfault. + +import bpy +import sys + +op_blacklist = ( + "script.reload", + "script.reload", + "export*.*", + "import*.*", + "*.save_*", + "*.read_*", + "*.open_*", + "*.link_append", + "render.render", + "*.*_export", + "*.*_import", + "wm.url_open", + "wm.doc_view", + "wm.path_open", + "help.operator_cheat_sheet", + ) + + +def filter_op_list(operators): + from fnmatch import fnmatchcase + + def is_op_ok(op): + for op_match in op_blacklist: + if fnmatchcase(op, op_match): + print(" skipping: %s (%s)" % (op, op_match)) + return False + return True + + operators[:] = [op for op in operators if is_op_ok(op[0])] + + +def run_ops(operators, setup_func=None): + print("\ncontext:", setup_func.__name__) + # first invoke + for op_id, op in operators: + if op.poll(): + print(" operator:", op_id) + sys.stdout.flush() # incase of crash + + # disable will get blender in a bad state and crash easy! + bpy.ops.wm.read_factory_settings() + + setup_func() + continue + for mode in ('EXEC_DEFAULT', 'INVOKE_DEFAULT'): + try: + op(mode) + #print(" - pass") + except: + #print(" - fail") + #import traceback + #traceback.print_exc() + pass + + +# contexts +def ctx_clear_scene(): # copied from batch_import.py + unique_obs = set() + for scene in bpy.data.scenes: + for obj in scene.objects[:]: + scene.objects.unlink(obj) + unique_obs.add(obj) + + # remove obdata, for now only worry about the startup scene + for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras): + for id_data in bpy_data_iter: + bpy_data_iter.remove(id_data) + + +def ctx_editmode_mesh(): + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.object.vertex_group_add() + + +def ctx_editmode_curves(): + bpy.ops.curve.primitive_nurbs_circle_add() + bpy.ops.object.mode_set(mode='EDIT') + + +def ctx_editmode_surface(): + bpy.ops.surface.primitive_nurbs_surface_torus_add() + bpy.ops.object.mode_set(mode='EDIT') + + +def ctx_editmode_mball(): + bpy.ops.object.metaball_add() + bpy.ops.object.mode_set(mode='EDIT') + + +def ctx_editmode_mball(): + bpy.ops.object.metaball_add() + bpy.ops.object.mode_set(mode='EDIT') + + +def ctx_editmode_text(): + bpy.ops.object.text_add() + bpy.ops.object.mode_set(mode='EDIT') + + +def ctx_editmode_armature(): + bpy.ops.object.armature_add() + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.armature.select_all(action='TOGGLE') + bpy.ops.armature.delete() + + +def ctx_editmode_lattice(): + bpy.ops.object.add(type='LATTICE') + bpy.ops.object.mode_set(mode='EDIT') + # bpy.ops.object.vertex_group_add() + + +def ctx_object_empty(): + bpy.ops.object.add(type='EMPTY') + + +def ctx_weightpaint(): + bpy.ops.object.mode_set(mode='WEIGHT_PAINT') + + +def main(): + # bpy.ops.wm.read_factory_settings() + import bpy + operators = [] + for mod_name in dir(bpy.ops): + mod = getattr(bpy.ops, mod_name) + for submod_name in dir(mod): + op = getattr(mod, submod_name) + operators.append(("%s.%s" % (mod_name, submod_name), op)) + + operators.sort(key=lambda op: op[0]) + + filter_op_list(operators) + + # for testing, mix the list up. + #operators.reverse() + + #import random + #random.shuffle(operators) + + # Run the operator tests in different contexts + run_ops(operators, setup_func=lambda: None) + run_ops(operators, setup_func=ctx_editmode_surface) + run_ops(operators, setup_func=ctx_object_empty) + run_ops(operators, setup_func=ctx_editmode_armature) + run_ops(operators, setup_func=ctx_editmode_mesh) + run_ops(operators, setup_func=ctx_clear_scene) + run_ops(operators, setup_func=ctx_editmode_curves) + run_ops(operators, setup_func=ctx_editmode_mball) + run_ops(operators, setup_func=ctx_editmode_text) + run_ops(operators, setup_func=ctx_weightpaint) + run_ops(operators, setup_func=ctx_editmode_lattice) + + print("finished") + +if __name__ == "__main__": + main() -- cgit v1.2.3