Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/blender_as_python_module/CMakeLists.txt33
-rw-r--r--tests/blender_as_python_module/import_bpy.py19
-rw-r--r--tests/python/CMakeLists.txt27
-rw-r--r--tests/python/bl_blendfile_library_overrides.py103
-rw-r--r--tests/python/compositor_render_tests.py64
-rw-r--r--tests/python/operators.py90
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)