diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 7 | ||||
-rw-r--r-- | tests/blender_as_python_module/CMakeLists.txt | 33 | ||||
-rw-r--r-- | tests/blender_as_python_module/import_bpy.py | 19 | ||||
-rw-r--r-- | tests/python/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tests/python/bl_blendfile_library_overrides.py | 103 | ||||
-rw-r--r-- | tests/python/compositor_render_tests.py | 64 | ||||
-rw-r--r-- | tests/python/operators.py | 90 |
7 files changed, 335 insertions, 8 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8941cc671dd..3d9201bec04 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,9 +47,14 @@ unset(_default_test_python_exe) set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --debug-exit-on-error --python-exit-code 1) # Python CTests -if(WITH_BLENDER AND WITH_PYTHON) +if(WITH_BLENDER AND WITH_PYTHON AND NOT WITH_PYTHON_MODULE) add_subdirectory(python) endif() +# Blender as python module tests. +if(WITH_PYTHON_MODULE) + add_subdirectory(blender_as_python_module) +endif() + # GTest add_subdirectory(gtests) diff --git a/tests/blender_as_python_module/CMakeLists.txt b/tests/blender_as_python_module/CMakeLists.txt new file mode 100644 index 00000000000..98e081672e9 --- /dev/null +++ b/tests/blender_as_python_module/CMakeLists.txt @@ -0,0 +1,33 @@ +# ***** 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. +# +# The Original Code is Copyright (C) 2021, Blender Foundation +# All rights reserved. +# +# ***** END GPL LICENSE BLOCK ***** + +function(add_blender_as_python_module_test testname testscript) + 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} + ) +endfunction() + +add_blender_as_python_module_test(import_bpy ${CMAKE_CURRENT_LIST_DIR}/import_bpy.py) diff --git a/tests/blender_as_python_module/import_bpy.py b/tests/blender_as_python_module/import_bpy.py new file mode 100644 index 00000000000..bdc0277cfec --- /dev/null +++ b/tests/blender_as_python_module/import_bpy.py @@ -0,0 +1,19 @@ +# ***** 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 ***** + +# Just import bpy and see if there are any dynamic loader errors. +import bpy diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 969b748e973..92cebb7d274 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -713,6 +713,33 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS) endif() endif() +if(WITH_COMPOSITOR) + set(compositor_tests + color + converter + distort + filter + input + matte + output + vector + + multiple_node_setups + ) + + foreach(comp_test ${compositor_tests}) + add_python_test( + compositor_${comp_test}_test + ${CMAKE_CURRENT_LIST_DIR}/compositor_render_tests.py + -blender "${TEST_BLENDER_EXE}" + -testdir "${TEST_SRC_DIR}/compositor/${comp_test}" + -idiff "${OPENIMAGEIO_IDIFF}" + -outdir "${TEST_OUT_DIR}/compositor" + ) + endforeach() + +endif() + if(WITH_OPENGL_DRAW_TESTS) if(NOT OPENIMAGEIO_IDIFF) MESSAGE(STATUS "Disabling OpenGL draw tests because OIIO idiff does not exist") diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py index ab75a410590..e2c6432b380 100644 --- a/tests/python/bl_blendfile_library_overrides.py +++ b/tests/python/bl_blendfile_library_overrides.py @@ -1,6 +1,6 @@ # Apache License, Version 2.0 -# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py +# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py -- --output-dir=/tmp/ import pathlib import bpy import sys @@ -16,6 +16,8 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): OBJECT_LIBRARY_PARENT = "LibMeshParent" MESH_LIBRARY_CHILD = "LibMeshChild" OBJECT_LIBRARY_CHILD = "LibMeshChild" + MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive" + OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive" def __init__(self, args): self.args = args @@ -33,6 +35,14 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): obj_child = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_CHILD, object_data=mesh_child) obj_child.parent = obj bpy.context.collection.objects.link(obj_child) + + mesh = bpy.data.meshes.new(TestLibraryOverrides.MESH_LIBRARY_PERMISSIVE) + obj = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh) + bpy.context.collection.objects.link(obj) + obj.override_template_create() + prop = obj.override_library.properties.add(rna_path='scale') + prop.operations.add(operation='NOOP') + bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False) def __ensure_override_library_updated(self): @@ -47,29 +57,109 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PARENT) obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PARENT] - assert(obj.override_library is None) + self.assertIsNone(obj.override_library) local_id = obj.override_create() - assert(local_id.override_library) - assert(local_id.data.override_library is None) + self.assertIsNotNone(local_id.override_library) + self.assertIsNone(local_id.data.override_library) assert(len(local_id.override_library.properties) == 0) local_id.location.y = 1.0 self.__ensure_override_library_updated() - assert (len(local_id.override_library.properties) == 1) assert(len(local_id.override_library.properties) == 1) override_prop = local_id.override_library.properties[0] assert(override_prop.rna_path == "location"); assert(len(override_prop.operations) == 1) override_operation = override_prop.operations[0] - assert (override_operation.operation == 'REPLACE') + assert(override_operation.operation == 'REPLACE') # Setting location.y overridded all elements in the location array. -1 is a wildcard. assert(override_operation.subitem_local_index == -1) + def test_link_permissive(self): + """ + Linked assets with a permissive template. + + - Checks if the NOOP is properly handled. + - Checks if the correct properties and operations are created/updated. + """ + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + bpy.data.orphans_purge() + + link_dir = self.output_path / "Object" + bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE) + + obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE] + self.assertIsNotNone(obj.override_library) + local_id = obj.override_create() + self.assertIsNotNone(local_id.override_library) + self.assertIsNone(local_id.data.override_library) + assert(len(local_id.override_library.properties) == 1) + override_prop = local_id.override_library.properties[0] + assert(override_prop.rna_path == "scale"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'NOOP') + assert(override_operation.subitem_local_index == -1) + + local_id.location.y = 1.0 + local_id.scale.x = 0.5 + # `scale.x` will apply, but will be reverted when the library overrides + # are updated. This is by design so python scripts can still alter the + # properties locally what is a typical usecase in productions. + assert(local_id.scale.x == 0.5) + assert(local_id.location.y == 1.0) + + self.__ensure_override_library_updated() + assert(local_id.scale.x == 1.0) + assert(local_id.location.y == 1.0) + + assert(len(local_id.override_library.properties) == 2) + override_prop = local_id.override_library.properties[0] + assert(override_prop.rna_path == "scale"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'NOOP') + assert(override_operation.subitem_local_index == -1) + + override_prop = local_id.override_library.properties[1] + assert(override_prop.rna_path == "location"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'REPLACE') + assert (override_operation.subitem_local_index == -1) + + +class TestLibraryTemplate(TestHelper, unittest.TestCase): + MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive" + OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive" + + def __init__(self, args): + pass + + def test_permissive_template(self): + """ + Test setting up a permissive template. + """ + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + mesh = bpy.data.meshes.new(TestLibraryTemplate.MESH_LIBRARY_PERMISSIVE) + obj = bpy.data.objects.new(TestLibraryTemplate.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh) + bpy.context.collection.objects.link(obj) + assert(obj.override_library is None) + obj.override_template_create() + assert(obj.override_library is not None) + assert(len(obj.override_library.properties) == 0) + prop = obj.override_library.properties.add(rna_path='scale') + assert(len(obj.override_library.properties) == 1) + assert(len(prop.operations) == 0) + operation = prop.operations.add(operation='NOOP') + assert(len(prop.operations) == 1) + assert(operation.operation == 'NOOP') + TESTS = ( TestLibraryOverrides, + TestLibraryTemplate, ) @@ -95,6 +185,7 @@ def main(): # Don't write thumbnails into the home directory. bpy.context.preferences.filepaths.use_save_preview_images = False + bpy.context.preferences.experimental.use_override_templates = True for Test in TESTS: Test(args).run_all_tests() diff --git a/tests/python/compositor_render_tests.py b/tests/python/compositor_render_tests.py new file mode 100644 index 00000000000..6a026ae88d2 --- /dev/null +++ b/tests/python/compositor_render_tests.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# Apache License, Version 2.0 + +import argparse +import os +import shlex +import shutil +import subprocess +import sys + + +# When run from inside Blender, render and exit. +try: + import bpy + inside_blender = True +except ImportError: + inside_blender = False + +def get_arguments(filepath, output_filepath): + return [ + "--background", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + "--debug-memory", + "--debug-exit-on-error", + filepath, + "-P", + os.path.realpath(__file__), + "-o", output_filepath, + "-F", "PNG", + "-f", "1"] + + +def create_argparse(): + parser = argparse.ArgumentParser() + parser.add_argument("-blender", nargs="+") + parser.add_argument("-testdir", nargs=1) + parser.add_argument("-outdir", nargs=1) + parser.add_argument("-idiff", nargs=1) + return parser + + +def main(): + parser = create_argparse() + args = parser.parse_args() + + blender = args.blender[0] + test_dir = args.testdir[0] + idiff = args.idiff[0] + output_dir = args.outdir[0] + + from modules import render_report + report = render_report.Report("Compositor", output_dir, idiff) + report.set_pixelated(True) + report.set_reference_dir("compositor_renders") + ok = report.run(test_dir, blender, get_arguments, batch=True) + + sys.exit(not ok) + + +if not inside_blender and __name__ == "__main__": + main() + diff --git a/tests/python/operators.py b/tests/python/operators.py index 461880ec214..309a872ac67 100644 --- a/tests/python/operators.py +++ b/tests/python/operators.py @@ -137,7 +137,6 @@ def main(): MeshTest("CubeEdgeSplit", "testCubeEdgeSplit", "expectedCubeEdgeSplit", [OperatorSpecEditMode("edge_split", {}, "EDGE", {2, 5, 8, 11, 14, 17, 20, 23})]), - ### 25 # edge ring select - Cannot be tested. Need user input. # MeshTest("CubeEdgeRingSelect", "testCubeEdgeRingSelect", "expectedCubeEdgeRingSelect", # [OperatorSpecEditMode("edgering_select", {}, "EDGE", {5, 20, 25, 26})]), @@ -146,6 +145,16 @@ def main(): # MeshTest("EmptyMeshEdgeRingSelect", "testEmptyMeshdgeRingSelect", "expectedEmptyMeshEdgeRingSelect", # [OperatorSpecEditMode("edgering_select", {}, "VERT", {})]), + # edges select sharp + MeshTest("CubeEdgesSelectSharp", "testCubeEdgeSelectSharp", "expectedCubeEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {}, "EDGE", {20})]), + MeshTest("SphereEdgesSelectSharp", "testSphereEdgesSelectSharp", "expectedSphereEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {"sharpness": 0.25}, "EDGE", {288})]), + MeshTest("HoledSphereEdgesSelectSharp", "testHoledSphereEdgesSelectSharp", "expectedHoledSphereEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {"sharpness": 0.18}, "VERT", {})]), + MeshTest("EmptyMeshEdgesSelectSharp", "testEmptyMeshEdgeSelectSharp", "expectedEmptyMeshEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {}, "VERT", {})]), + # face make planar MeshTest("MonkeyFaceMakePlanar", "testMonkeyFaceMakePlanar", "expectedMonkeyFaceMakePlanar", @@ -208,6 +217,85 @@ def main(): [OperatorSpecEditMode("inset", {"thickness": 0.4, "use_relative_offset": True}, "FACE", {35, 36, 37, 45, 46, 47, 55, 56, 57})]), + + # loop multi select + MeshTest("MokeyLoopMultiSelect", "testMonkeyLoopMultiSelect", "expectedMonkeyLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {355, 359, 73, 301, 302})]), + MeshTest("HoledGridLoopMultiSelect", "testGridLoopMultiSelect", "expectedGridLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {257, 169, 202, 207, 274, 278, 63})]), + MeshTest("EmptyMeshLoopMultiSelect", "testEmptyMeshLoopMultiSelect", "expectedEmptyMeshLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {})]), + + # select all + MeshTest("CircleSelectAll", "testCircleSelectAll", "expectedCircleSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {1})]), + MeshTest("IsolatedVertsSelectAll", "testIsolatedVertsSelectAll", "expectedIsolatedVertsSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {})]), + MeshTest("EmptyMeshSelectAll", "testEmptyMeshSelectAll", "expectedEmptyMeshSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {})]), + + # select axis - Cannot be tested. Needs active vert selection + # MeshTest("MonkeySelectAxisX", "testMonkeySelectAxisX", "expectedMonkeySelectAxisX", + # [OperatorSpecEditMode("select_axis", {"axis": "X"}, "VERT", {13})]), + # MeshTest("MonkeySelectAxisY", "testMonkeySelectAxisY", "expectedMonkeySelectAxisY", + # [OperatorSpecEditMode("select_axis", {"axis": "Y", "sign": "NEG"}, "FACE", {317})]), + # MeshTest("MonkeySelectAxisXYZ", "testMonkeySelectAxisXYZ", "expectedMonkeySelectAxisXYZ", + # [OperatorSpecEditMode("select_axis", {"axis": "X", "sign": "NEG"}, "FACE", {317}), + # OperatorSpecEditMode("select_axis", {"axis": "Y", "sign": "POS"}, "FACE", {}), + # OperatorSpecEditMode("select_axis", {"axis": "Z", "sign": "NEG"}, "FACE", {})]), + + # select faces by sides + MeshTest("CubeSelectFacesBySide", "testCubeSelectFacesBySide", "expectedCubeSelectFacesBySide", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("CubeSelectFacesBySideGreater", "testCubeSelectFacesBySideGreater", "expectedCubeSelectFacesBySideGreater", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4, "type": "GREATER", "extend": True}, "FACE", {})]), + MeshTest("CubeSelectFacesBySideLess", "testCubeSelectFacesBySideLess", "expectedCubeSelectFacesBySideLess", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4, "type": "GREATER", "extend": True}, "FACE", {})]), + + # select interior faces + MeshTest("CubeSelectInteriorFaces", "testCubeSelectInteriorFaces", "expectedCubeSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("HoledCubeSelectInteriorFaces", "testHoledCubeSelectInteriorFaces", "expectedHoledCubeSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("EmptyMeshSelectInteriorFaces", "testEmptyMeshSelectInteriorFaces", "expectedEmptyMeshSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + + # select less + MeshTest("MonkeySelectLess", "testMonkeySelectLess", "expectedMonkeySelectLess", + [OperatorSpecEditMode("select_less", {}, "VERT", {2, 8, 24, 34, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 68, + 69, 70, 71, 74, 75, 78, 80, 81, 82, 83, 90, 91, 93, 95, 97, 99, + 101, 109, 111, 115, 117, 119, 121, 123, 125, 127, 129, 130, 131, + 132, 133, 134, 135, 136, 138, 141, 143, 145, 147, 149, 151, 153, + 155, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 181, 182, 184, 185, 186, 187, 188, 189, 190, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 206, 207, 208, 210, 216, 217, 218, 219, 220, 221, 222, 229, 230, + 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, + 257, 259, 263, 267, 269, 271, 275, 277, 289, 291, 293, 295, 309, + 310, 311, 312, 316, 317, 318, 319, 320, 323, 325, 327, 329, 331, + 341, 347, 349, 350, 351, 354, 356, 359, 361, 363, 365, 367, 369, + 375, 379, 381, 382, 385, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 423, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 471, 473, 474, 475, 476, 477, 478, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 495, + 496, 497, 498, 499, 502, 505})]), + MeshTest("HoledCubeSelectLess", "testHoledCubeSelectLess", "expectedHoledCubeSelectLess", + [OperatorSpecEditMode("select_face_by_sides", {}, "FACE", {})]), + MeshTest("EmptyMeshSelectLess", "testEmptyMeshSelectLess", "expectedEmptyMeshSelectLess", + [OperatorSpecEditMode("select_face_by_sides", {}, "VERT", {})]), + + # select linked + MeshTest("PlanesSelectLinked", "testPlanesSelectLinked", "expectedPlanesSelectedLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {7})]), + MeshTest("CubesSelectLinked", "testCubesSelectLinked", "expectedCubesSelectLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {11})]), + MeshTest("EmptyMeshSelectLinked", "testEmptyMeshSelectLinked", "expectedEmptyMeshSelectLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {})]), + ] operators_test = RunTest(tests) |