From eb8afc39f858ca397e53fc8cd36b3ebc0024476e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 12 Oct 2021 17:57:41 +1100 Subject: Tests: remove noisy output from bl_pyapi_idprop_datablock As part of expected behavior this printed an exception, making it seem as if there was an error in the test. Now the exception is suppressed from the output, ensuring it matches an the expected output. --- tests/python/bl_pyapi_idprop_datablock.py | 121 +++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 37 deletions(-) (limited to 'tests') diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py index 6cc99154cfe..d4253dc4665 100644 --- a/tests/python/bl_pyapi_idprop_datablock.py +++ b/tests/python/bl_pyapi_idprop_datablock.py @@ -18,13 +18,17 @@ # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_idprop_datablock.py -- --verbose -import bpy -import sys +import contextlib +import inspect +import io import os +import re +import sys import tempfile -import inspect -from bpy.types import UIList +import bpy + +from bpy.types import UIList arr_len = 100 ob_cp_count = 100 @@ -49,13 +53,40 @@ def print_fail_msg_and_exit(msg): os._exit(1) -def abort_if_false(expr, msg=None): +def expect_false_or_abort(expr, msg=None): if not expr: if not msg: msg = "test failed" print_fail_msg_and_exit(msg) +def expect_exception_or_abort(*, fn, ex): + try: + fn() + exception = False + except ex: + exception = True + if exception: + return # OK + print_fail_msg_and_exit("test failed") + + +def expect_ouput_or_abort(*, fn, match_stderr=None, match_stdout=None): + + stdout, stderr = io.StringIO(), io.StringIO() + + with (contextlib.redirect_stderr(stderr), contextlib.redirect_stdout(stdout)): + fn() + + for (handle, match) in ((stdout, match_stdout), (stderr, match_stderr)): + if not match: + continue + handle.seek(0) + output = handle.read() + if not re.match(match, output): + print_fail_msg_and_exit("%r not found in %r" % (match, output)) + + class TestClass(bpy.types.PropertyGroup): test_prop: bpy.props.PointerProperty(type=bpy.types.Object) name: bpy.props.StringProperty() @@ -71,14 +102,6 @@ def get_scene(lib_name, sce_name): return s -def check_crash(fnc, args=None): - try: - fnc(args) if args else fnc() - except: - return - print_fail_msg_and_exit("test failed") - - def init(): bpy.utils.register_class(TestClass) bpy.types.Object.prop_array = bpy.props.CollectionProperty( @@ -122,12 +145,13 @@ def make_lib(): def check_lib(): # check pointer - abort_if_false(bpy.data.objects["Cube"].prop == bpy.data.objects['Camera']) + expect_false_or_abort(bpy.data.objects["Cube"].prop == bpy.data.objects['Camera']) # check array of pointers in duplicated object for i in range(0, arr_len): - abort_if_false(bpy.data.objects["Cube.001"].prop_array[i].test_prop == - bpy.data.objects['Light']) + expect_false_or_abort( + bpy.data.objects["Cube.001"].prop_array[i].test_prop == + bpy.data.objects['Light']) def check_lib_linking(): @@ -140,9 +164,9 @@ def check_lib_linking(): o = bpy.data.scenes["Scene_lib"].objects['Unique_Cube'] - abort_if_false(o.prop_array[0].test_prop == bpy.data.scenes["Scene_lib"].objects['Light']) - abort_if_false(o.prop == bpy.data.scenes["Scene_lib"].objects['Camera']) - abort_if_false(o.prop.library == o.library) + expect_false_or_abort(o.prop_array[0].test_prop == bpy.data.scenes["Scene_lib"].objects['Light']) + expect_false_or_abort(o.prop == bpy.data.scenes["Scene_lib"].objects['Camera']) + expect_false_or_abort(o.prop.library == o.library) bpy.ops.wm.save_as_mainfile(filepath=test_path) @@ -162,9 +186,10 @@ def check_linked_scene_copying(): # check node's props # must point to own scene camera - abort_if_false(intern_sce.node_tree.nodes['Render Layers']["prop"] and - not (intern_sce.node_tree.nodes['Render Layers']["prop"] == - extern_sce.node_tree.nodes['Render Layers']["prop"])) + expect_false_or_abort( + intern_sce.node_tree.nodes['Render Layers']["prop"] and + not (intern_sce.node_tree.nodes['Render Layers']["prop"] == + extern_sce.node_tree.nodes['Render Layers']["prop"])) def check_scene_copying(): @@ -183,8 +208,9 @@ def check_scene_copying(): # check node's props # must point to own scene camera - abort_if_false(not (first_sce.node_tree.nodes['Render Layers']["prop"] == - second_sce.node_tree.nodes['Render Layers']["prop"])) + expect_false_or_abort( + not (first_sce.node_tree.nodes['Render Layers']["prop"] == + second_sce.node_tree.nodes['Render Layers']["prop"])) # count users @@ -194,11 +220,11 @@ def test_users_counting(): n = 1000 for i in range(0, n): bpy.data.objects["Cube"]["a%s" % i] = bpy.data.objects["Light"].data - abort_if_false(bpy.data.objects["Light"].data.users == Light_us + n) + expect_false_or_abort(bpy.data.objects["Light"].data.users == Light_us + n) for i in range(0, int(n / 2)): bpy.data.objects["Cube"]["a%s" % i] = 1 - abort_if_false(bpy.data.objects["Light"].data.users == Light_us + int(n / 2)) + expect_false_or_abort(bpy.data.objects["Light"].data.users == Light_us + int(n / 2)) # linking @@ -240,16 +266,22 @@ def test_restrictions1(): self.layout.template_ID(context.scene, "prop1") self.layout.prop_search(context.scene, "prop2", bpy.data, "node_groups") - op = self.layout.operator("scene.test_op") + op = self.layout.operator(TEST_Op.bl_idname) op.str_prop = "test string" - def test_fnc(op): + def test_fn(op): op["ob"] = bpy.data.objects['Unique_Cube'] - check_crash(test_fnc, op) - abort_if_false(not hasattr(op, "id_prop")) + expect_exception_or_abort( + fn=lambda: test_fn(op), + ex=ImportError, + ) + expect_false_or_abort(not hasattr(op, "id_prop")) bpy.utils.register_class(TEST_PT_DatablockProp) - bpy.utils.register_class(TEST_Op) + expect_ouput_or_abort( + fn=lambda: bpy.utils.register_class(TEST_Op), + match_stderr="^ValueError: bpy_struct \"SCENE_OT_test_op\" registration error:", + ) def poll(self, value): return value.name in bpy.data.scenes["Scene_lib"].objects @@ -270,12 +302,18 @@ def test_restrictions1(): # NodeTree id_prop bpy.context.scene.prop2 = bpy.data.objects["Light.001"] - check_crash(sub_test) + expect_exception_or_abort( + fn=sub_test, + ex=TypeError, + ) bpy.context.scene.prop2 = bpy.data.node_groups.new("Shader", "ShaderNodeTree") - print("Please, test GUI performance manually on the Render tab, '%s' panel" % - TEST_PT_DatablockProp.bl_label, file=sys.stderr) + # NOTE: keep since the author thought this useful information. + # print( + # "Please, test GUI performance manually on the Render tab, '%s' panel" % + # TEST_PT_DatablockProp.bl_label, file=sys.stderr, + # ) sys.stderr.flush() @@ -318,8 +356,14 @@ def test_restrictions2(): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): layout.prop(item, "name", text="", emboss=False, icon_value=icon) - check_crash(bpy.utils.register_class, TestPrefs) - check_crash(bpy.utils.register_class, TEST_UL_list) + expect_exception_or_abort( + fn=lambda: bpy.utils.register_class(TestPrefs), + ex=ValueError, + ) + expect_exception_or_abort( + fn=lambda: bpy.utils.register_class(TEST_UL_list), + ex=ValueError, + ) bpy.utils.unregister_class(TestClassCollection) @@ -335,7 +379,10 @@ def main(): test_users_counting() test_linking() test_restrictions1() - check_crash(test_regressions) + expect_exception_or_abort( + fn=test_regressions, + ex=AttributeError, + ) test_restrictions2() -- cgit v1.2.3