Layers: Unittesting - make them granular

Some tests may break Blender, which makes the entire unittest routine to fail.
They are now I isolate the tests into individual files

Kudos to Sybren Stüvel and Sergey Sharybin for the advice.

Note: at the moment test_link.py is failing (since a41bbfb7)
This commit is contained in:
Dalai Felinto 2017-02-14 18:15:09 +01:00
parent 6906a884ee
commit b9762fed93
14 changed files with 1451 additions and 1046 deletions

View File

@ -426,9 +426,4 @@ if(WITH_CYCLES)
endif()
endif()
# ------------------------------------------------------------------------------
# LAYER SYSTEM TESTS
add_test(render_layer ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/bl_render_layer.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_subdirectory(render_layer)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
# ***** 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.
#
# Contributor(s): Jacques Beaurain.
#
# ***** END GPL LICENSE BLOCK *****
# --env-system-scripts allows to run without the install target.
# Use '--write-blend=/tmp/test.blend' to view output
# Some tests are interesting but take too long to run
# and don't give deterministic results
set(USE_EXPERIMENTAL_TESTS FALSE)
set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
# ugh, any better way to do this on testing only?
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR})
#~ if(NOT IS_DIRECTORY ${TEST_SRC_DIR})
#~ message(FATAL_ERROR "CMake test directory not found!")
#~ endif()
# all calls to blender use this
if(APPLE)
if(${CMAKE_GENERATOR} MATCHES "Xcode")
set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/Debug/blender.app/Contents/MacOS/blender)
else()
set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender.app/Contents/MacOS/blender)
endif()
else()
set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender)
endif()
# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE})
set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
# ------------------------------------------------------------------------------
add_test(render_layer_scene_write_read ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_scene_write_read.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_scene_copy ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_scene_copy.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_syncing ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_syncing.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_layer_linking ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_layer_linking.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_active_collection ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_active_collection.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_object_delete ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_object_delete.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_link ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_link.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_operator_context ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_operator_context.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_object_add ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_object_add.py --
--testdir="${TEST_SRC_DIR}/layers"
)
add_test(render_layer_object_copy ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/test_object_copy.py --
--testdir="${TEST_SRC_DIR}/layers"
)

View File

@ -0,0 +1,245 @@
import unittest
# ############################################################
# Layer Collection Crawler
# ############################################################
def listbase_iter(data, struct, listbase):
element = data.get_pointer((struct, listbase, b'first'))
while element is not None:
yield element
element = element.get_pointer(b'next')
def linkdata_iter(collection, data):
element = collection.get_pointer((data, b'first'))
while element is not None:
yield element
element = element.get_pointer(b'next')
def get_layer_collection(layer_collection):
data = {}
flag = layer_collection.get(b'flag')
data['is_visible'] = (flag & (1 << 0)) != 0;
data['is_selectable'] = (flag & (1 << 1)) != 0;
data['is_folded'] = (flag & (1 << 2)) != 0;
scene_collection = layer_collection.get_pointer(b'scene_collection')
if scene_collection is None:
name = 'Fail!'
else:
name = scene_collection.get(b'name')
data['name'] = name
objects = []
for link in linkdata_iter(layer_collection, b'object_bases'):
ob_base = link.get_pointer(b'data')
ob = ob_base.get_pointer(b'object')
objects.append(ob.get((b'id', b'name'))[2:])
data['objects'] = objects
collections = {}
for nested_layer_collection in linkdata_iter(layer_collection, b'layer_collections'):
subname, subdata = get_layer_collection(nested_layer_collection)
collections[subname] = subdata
data['collections'] = collections
return name, data
def get_layer(layer):
data = {}
name = layer.get(b'name')
data['name'] = name
data['active_object'] = layer.get((b'basact', b'object', b'id', b'name'))[2:]
data['engine'] = layer.get(b'engine')
objects = []
for link in linkdata_iter(layer, b'object_bases'):
ob = link.get_pointer(b'object')
objects.append(ob.get((b'id', b'name'))[2:])
data['objects'] = objects
collections = {}
for layer_collection in linkdata_iter(layer, b'layer_collections'):
subname, subdata = get_layer_collection(layer_collection)
collections[subname] = subdata
data['collections'] = collections
return name, data
def get_layers(scene):
"""Return all the render layers and their data"""
layers = {}
for layer in linkdata_iter(scene, b'render_layers'):
name, data = get_layer(layer)
layers[name] = data
return layers
def get_scene_collection_objects(collection, listbase):
objects = []
for link in linkdata_iter(collection, listbase):
ob = link.get_pointer(b'data')
if ob is None:
name = 'Fail!'
else:
name = ob.get((b'id', b'name'))[2:]
objects.append(name)
return objects
def get_scene_collection(collection):
""""""
data = {}
name = collection.get(b'name')
data['name'] = name
data['filter'] = collection.get(b'filter')
data['objects'] = get_scene_collection_objects(collection, b'objects')
data['filter_objects'] = get_scene_collection_objects(collection, b'filter_objects')
collections = {}
for nested_collection in linkdata_iter(collection, b'scene_collections'):
subname, subdata = get_scene_collection(nested_collection)
collections[subname] = subdata
data['collections'] = collections
return name, data
def get_scene_collections(scene):
"""Return all the scene collections ahd their data"""
master_collection = scene.get_pointer(b'collection')
return get_scene_collection(master_collection)
def query_scene(filepath, name, callbacks):
"""Return the equivalent to bpy.context.scene"""
import blendfile
with blendfile.open_blend(filepath) as blend:
scenes = [block for block in blend.blocks if block.code == b'SC']
for scene in scenes:
if scene.get((b'id', b'name'))[2:] == name:
output = []
for callback in callbacks:
output.append(callback(scene))
return output
# ############################################################
# Utils
# ############################################################
def import_blendfile():
import bpy
import os, sys
path = os.path.join(
bpy.utils.resource_path('LOCAL'),
'scripts',
'addons',
'io_blend_utils',
'blend',
)
if path not in sys.path:
sys.path.append(path)
def dump(data):
import json
return json.dumps(
data,
sort_keys=True,
indent=4,
separators=(',', ': '),
)
# ############################################################
# Tests
# ############################################################
PDB = False
DUMP_DIFF = True
def compare_files(file_a, file_b):
import filecmp
if not filecmp.cmp(
file_a,
file_b):
if DUMP_DIFF:
import subprocess
subprocess.call(["diff", "-u", file_a, file_b])
if PDB:
import pdb
print("Files differ:", file_a, file_b)
pdb.set_trace()
return False
return True
class RenderLayerTesting(unittest.TestCase):
_test_simple = False
_extra_arguments = []
@classmethod
def setUpClass(cls):
"""Runs once"""
cls.pretest_import_blendfile()
cls.pretest_parsing()
@classmethod
def setUp(cls):
"""Runs once per test"""
import bpy
bpy.ops.wm.read_factory_settings()
def path_exists(self, filepath):
import os
self.assertTrue(
os.path.exists(filepath),
"Test file \"{0}\" not found".format(filepath))
@classmethod
def get_root(cls):
"""
return the folder with the test files
"""
arguments = {}
for argument in cls._extra_arguments:
name, value = argument.split('=')
cls.assertTrue(name and name.startswith("--"), "Invalid argument \"{0}\"".format(argument))
cls.assertTrue(value, "Invalid argument \"{0}\"".format(argument))
arguments[name[2:]] = value.strip('"')
return arguments.get('testdir')
@classmethod
def pretest_parsing(cls):
"""
Test if the arguments are properly set, and store ROOT
name has extra _ because we need this test to run first
"""
root = cls.get_root()
cls.assertTrue(root, "Testdir not set")
@staticmethod
def pretest_import_blendfile():
"""
Make sure blendfile imports with no problems
name has extra _ because we need this test to run first
"""
import_blendfile()
import blendfile

View File

@ -0,0 +1,76 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_active_collection.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def test_active_collection(self):
"""
See if active collection index is working
layer.collections.active_index works recursively
"""
import bpy
import os
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
layer = scene.render_layers.new('Fresh new Layer')
layer.collections.link(subzero)
lookup = [
'Master Collection',
'1',
'sub-zero',
'scorpion',
'2',
'3',
'4',
'5',
'sub-zero',
'scorpion']
for i, name in enumerate(lookup):
layer.collections.active_index = i
self.assertEqual(name, layer.collections.active.name,
"Collection index mismatch: [{0}] : {1} != {2}".format(
i, name, layer.collections.active.name))
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,116 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_layer_linking.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_layer_linking(self, filepath_json, link_mode):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
# test linking sync
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
# test unlinking sync
layer = scene.render_layers.new('Fresh new Layer')
if link_mode in {'COLLECTION_LINK', 'COLLECTION_UNLINK'}:
layer.collections.link(subzero)
if link_mode == 'COLLECTION_UNLINK':
initial_collection = layer.collections['Master Collection']
layer.collections.unlink(initial_collection)
# save file
filepath_nested = os.path.join(dirpath, 'nested.blend')
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_nested)
# get the generated json
datas = query_scene(filepath_nested, 'Main', (get_scene_collections, get_layers))
self.assertTrue(datas, "Data is not valid")
filepath_nested_json = os.path.join(dirpath, "nested.json")
with open(filepath_nested_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_nested_json,
filepath_json,
),
"Scene dump files differ")
def test_syncing_layer_new(self):
"""
See if the creation of new layers is going well
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_new_layer.json')
self.do_layer_linking(filepath_json, 'LAYER_NEW')
def test_syncing_layer_collection_link(self):
"""
See if the creation of new layers is going well
And linking a new scene collection in the layer works
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_layer_collection_link.json')
self.do_layer_linking(filepath_json, 'COLLECTION_LINK')
def test_syncing_layer_collection_unlink(self):
"""
See if the creation of new layers is going well
And unlinking the origin scene collection works
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_layer_collection_unlink.json')
self.do_layer_linking(filepath_json, 'COLLECTION_UNLINK')
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,55 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_link.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_link(self, master_collection):
import bpy
self.assertEqual(master_collection.name, "Master Collection")
self.assertEqual(master_collection, bpy.context.scene.master_collection)
master_collection.objects.link(bpy.data.objects.new('object', None))
def test_link_scene(self):
"""
See if we can link objects
"""
import bpy
master_collection = bpy.context.scene.master_collection
self.do_link(master_collection)
def test_link_context(self):
"""
See if we can link objects via bpy.context.scene_collection
"""
import bpy
bpy.context.scene.render_layers.active_index = len(bpy.context.scene.render_layers) - 1
master_collection = bpy.context.scene_collection
self.do_link(master_collection)
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,125 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_scene_copy.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_object_add(self, filepath_json, add_mode):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
layer = scene.render_layers.new('Fresh new Layer')
layer.collections.link(subzero)
# change active collection
layer.collections.active_index = 3
self.assertEqual(layer.collections.active.name, 'scorpion', "Run: test_syncing_object_add")
# change active layer
override = bpy.context.copy()
override["render_layer"] = layer
override["scene_collection"] = layer.collections.active.collection
# add new objects
if add_mode == 'EMPTY':
bpy.ops.object.add(override) # 'Empty'
elif add_mode == 'CYLINDER':
bpy.ops.mesh.primitive_cylinder_add(override) # 'Cylinder'
elif add_mode == 'TORUS':
bpy.ops.mesh.primitive_torus_add(override) # 'Torus'
# save file
filepath_objects = os.path.join(dirpath, 'objects.blend')
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_objects)
# get the generated json
datas = query_scene(filepath_objects, 'Main', (get_scene_collections, get_layers))
self.assertTrue(datas, "Data is not valid")
filepath_objects_json = os.path.join(dirpath, "objects.json")
with open(filepath_objects_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_objects_json,
filepath_json,
),
"Scene dump files differ")
def test_syncing_object_add_empty(self):
"""
See if new objects are added to the correct collection
bpy.ops.object.add()
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_object_add_empty.json')
self.do_object_add(filepath_json, 'EMPTY')
def test_syncing_object_add_cylinder(self):
"""
See if new objects are added to the correct collection
bpy.ops.mesh.primitive_cylinder_add()
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_object_add_cylinder.json')
self.do_object_add(filepath_json, 'CYLINDER')
def test_syncing_object_add_torus(self):
"""
See if new objects are added to the correct collection
bpy.ops.mesh.primitive_torus_add()
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_object_add_torus.json')
self.do_object_add(filepath_json, 'TORUS')
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,100 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_object_copy.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_object_copy(self, mode):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_json = os.path.join(ROOT, 'layers_object_copy_duplicate.json')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
layer = scene.render_layers.new('Fresh new Layer')
layer.collections.link(subzero)
scene.render_layers.active_index = len(scene.render_layers) - 1
if mode == 'DUPLICATE':
# assuming the latest layer is the active layer
bpy.ops.object.select_all(action='DESELECT')
three_c.select_set(action='SELECT')
bpy.ops.object.duplicate()
elif mode == 'NAMED':
bpy.ops.object.add_named(name=three_c.name)
# save file
filepath_objects = os.path.join(dirpath, 'objects.blend')
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_objects)
# get the generated json
datas = query_scene(filepath_objects, 'Main', (get_scene_collections, get_layers))
self.assertTrue(datas, "Data is not valid")
filepath_objects_json = os.path.join(dirpath, "objects.json")
with open(filepath_objects_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_objects_json,
filepath_json,
),
"Scene dump files differ")
def test_copy_object(self):
"""
OBJECT_OT_duplicate
"""
self.do_object_copy('DUPLICATE')
def test_copy_object_named(self):
"""
OBJECT_OT_add_named
"""
self.do_object_copy('NAMED')
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,104 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_scene_copy.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_object_delete(self, del_mode):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_reference_json = os.path.join(ROOT, 'layers_object_delete.json')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_d = bpy.data.objects.get('T.3d')
scene = bpy.context.scene
# mangle the file a bit with some objects linked across collections
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
subzero.objects.link(three_d)
scorpion.objects.link(three_b)
scorpion.objects.link(three_d)
# object to delete
ob = three_d
# delete object
if del_mode == 'DATA':
bpy.data.objects.remove(ob, do_unlink=True)
elif del_mode == 'OPERATOR':
bpy.ops.object.select_all(action='DESELECT')
ob.select_set(action='SELECT')
bpy.ops.object.delete()
# save file
filepath_generated = os.path.join(dirpath, 'generated.blend')
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_generated)
# get the generated json
datas = query_scene(filepath_generated, 'Main', (get_scene_collections, get_layers))
self.assertTrue(datas, "Data is not valid")
filepath_generated_json = os.path.join(dirpath, "generated.json")
with open(filepath_generated_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_generated_json,
filepath_reference_json,
),
"Scene dump files differ")
def test_object_delete_data(self):
"""
See if objects are removed correctly from all related collections
bpy.data.objects.remove()
"""
self.do_object_delete('DATA')
def test_object_delete_operator(self):
"""
See if new objects are added to the correct collection
bpy.ops.object.del()
"""
self.do_object_delete('OPERATOR')
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,133 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_scene_copy.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def test_operator_context(self):
"""
See if render layer context is properly set/get with operators overrides
when we set render_layer in context, the collection should change as well
"""
import bpy
import os
class SampleOperator(bpy.types.Operator):
bl_idname = "testing.sample"
bl_label = "Sample Operator"
render_layer = bpy.props.StringProperty(
default="Not Set",
options={'SKIP_SAVE'},
)
scene_collection = bpy.props.StringProperty(
default="",
options={'SKIP_SAVE'},
)
use_verbose = bpy.props.BoolProperty(
default=False,
options={'SKIP_SAVE'},
)
def execute(self, context):
render_layer = context.render_layer
ret = {'FINISHED'}
# this is simply playing safe
if render_layer.name != self.render_layer:
if self.use_verbose:
print('ERROR: Render Layer mismatch: "{0}" != "{1}"'.format(
render_layer.name, self.render_layer))
ret = {'CANCELLED'}
scene_collection_name = None
if self.scene_collection:
scene_collection_name = self.scene_collection
else:
scene_collection_name = render_layer.collections.active.name
# while this is the real test
if context.scene_collection.name != scene_collection_name:
if self.use_verbose:
print('ERROR: Scene Collection mismatch: "{0}" != "{1}"'.format(
context.scene_collection.name, scene_collection_name))
ret = {'CANCELLED'}
return ret
bpy.utils.register_class(SampleOperator)
# open sample file
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# change the file
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = subzero.collections.new('scorpion')
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
layer = scene.render_layers.new('Fresh new Layer')
layer.collections.unlink(layer.collections.active)
layer.collections.link(subzero)
layer.collections.active_index = 3
self.assertEqual(layer.collections.active.name, 'scorpion')
scene = bpy.context.scene
scene.render_layers.active_index = len(scene.render_layers) - 2
self.assertEqual(scene.render_layers.active.name, "Render Layer")
# old layer
self.assertEqual(bpy.ops.testing.sample(render_layer='Render Layer', use_verbose=True), {'FINISHED'})
# expected to fail
self.assertTrue(bpy.ops.testing.sample(render_layer=layer.name), {'CANCELLED'})
# set render layer and scene collection
override = bpy.context.copy()
override["render_layer"] = layer
override["scene_collection"] = subzero
self.assertEqual(bpy.ops.testing.sample(override,
render_layer=layer.name,
scene_collection=subzero.name, # 'sub-zero'
use_verbose=True), {'FINISHED'})
# set only render layer
override = bpy.context.copy()
override["render_layer"] = layer
self.assertEqual(bpy.ops.testing.sample(override,
render_layer=layer.name,
scene_collection=layer.collections.active.name, # 'scorpion'
use_verbose=True), {'FINISHED'})
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,120 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_scene_copy.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_scene_copy(self, filepath_json_reference, copy_mode, data_callbacks):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
(self.path_exists(f) for f in (
filepath_layers,
filepath_json_reference,
))
filepath_saved = os.path.join(dirpath, '{0}.blend'.format(copy_mode))
filepath_json = os.path.join(dirpath, "{0}.json".format(copy_mode))
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
bpy.ops.scene.new(type=copy_mode)
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_saved)
datas = query_scene(filepath_saved, 'Main.001', data_callbacks)
self.assertTrue(datas, "Data is not valid")
with open(filepath_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_json,
filepath_json_reference,
),
"Scene copy \"{0}\" test failed".format(copy_mode.title()))
def test_scene_collections_copy_full(self):
"""
See if scene copying 'FULL_COPY' is working for scene collections
"""
import os
ROOT = self.get_root()
filepath_layers_json_copy = os.path.join(ROOT, 'layers_copy_full_simple.json')
self.do_scene_copy(
filepath_layers_json_copy,
'FULL_COPY',
(get_scene_collections,))
def test_scene_collections_link(self):
"""
See if scene copying 'LINK_OBJECTS' is working for scene collections
"""
import os
ROOT = self.get_root()
# note: nothing should change, so using `layers_simple.json`
filepath_layers_json_copy = os.path.join(ROOT, 'layers_simple.json')
self.do_scene_copy(
filepath_layers_json_copy,
'LINK_OBJECTS',
(get_scene_collections,))
def test_scene_layers_copy(self):
"""
See if scene copying 'FULL_COPY' is working for scene layers
"""
import os
ROOT = self.get_root()
filepath_layers_json_copy = os.path.join(ROOT, 'layers_copy_full.json')
self.do_scene_copy(
filepath_layers_json_copy,
'FULL_COPY',
(get_scene_collections, get_layers))
def test_scene_layers_link(self):
"""
See if scene copying 'FULL_COPY' is working for scene layers
"""
import os
ROOT = self.get_root()
filepath_layers_json_copy = os.path.join(ROOT, 'layers_copy_link.json')
self.do_scene_copy(
filepath_layers_json_copy,
'LINK_OBJECTS',
(get_scene_collections, get_layers))
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,150 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_scene_write_read.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_scene_write_read(self, filepath_layers, filepath_layers_json, data_callbacks, do_read):
"""
See if write/read is working for scene collections and layers
"""
import bpy
import os
import tempfile
import filecmp
with tempfile.TemporaryDirectory() as dirpath:
(self.path_exists(f) for f in (filepath_layers, filepath_layers_json))
filepath_doversion = os.path.join(dirpath, 'doversion.blend')
filepath_saved = os.path.join(dirpath, 'doversion_saved.blend')
filepath_read_json = os.path.join(dirpath, "read.json")
# doversion + write test
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_doversion)
datas = query_scene(filepath_doversion, 'Main', data_callbacks)
self.assertTrue(datas, "Data is not valid")
filepath_doversion_json = os.path.join(dirpath, "doversion.json")
with open(filepath_doversion_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_doversion_json,
filepath_layers_json,
),
"Run: test_scene_write_layers")
if do_read:
# read test, simply open and save the file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_doversion)
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_saved)
datas = query_scene(filepath_saved, 'Main', data_callbacks)
self.assertTrue(datas, "Data is not valid")
with open(filepath_read_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_read_json,
filepath_layers_json,
),
"Scene dump files differ")
def test_scene_write_collections(self):
"""
See if the doversion and writing are working for scene collections
"""
import os
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_layers_json = os.path.join(ROOT, 'layers_simple.json')
self.do_scene_write_read(
filepath_layers,
filepath_layers_json,
(get_scene_collections,),
False)
def test_scene_write_layers(self):
"""
See if the doversion and writing are working for collections and layers
"""
import os
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_layers_json = os.path.join(ROOT, 'layers.json')
self.do_scene_write_read(
filepath_layers,
filepath_layers_json,
(get_scene_collections, get_layers),
False)
def test_scene_read_collections(self):
"""
See if read is working for scene collections
(run `test_scene_write_colections` first)
"""
import os
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_layers_json = os.path.join(ROOT, 'layers_simple.json')
self.do_scene_write_read(
filepath_layers,
filepath_layers_json,
(get_scene_collections,),
True)
def test_scene_read_layers(self):
"""
See if read is working for scene layers
(run `test_scene_write_layers` first)
"""
import os
ROOT = self.get_root()
filepath_layers = os.path.join(ROOT, 'layers.blend')
filepath_layers_json = os.path.join(ROOT, 'layers.json')
self.do_scene_write_read(
filepath_layers,
filepath_layers_json,
(get_scene_collections, get_layers),
True)
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()

View File

@ -0,0 +1,120 @@
# ./blender.bin --background -noaudio --python tests/python/render_layer/test_syncing.py -- --testdir="/data/lib/tests/"
# ############################################################
# Importing - Same For All Render Layer Tests
# ############################################################
import unittest
import os, sys
sys.path.append(os.path.dirname(__file__))
from render_layer_common import *
# ############################################################
# Testing
# ############################################################
class UnitTesting(RenderLayerTesting):
def do_syncing(self, filepath_json, unlink_mode):
import bpy
import os
import tempfile
import filecmp
ROOT = self.get_root()
with tempfile.TemporaryDirectory() as dirpath:
filepath_layers = os.path.join(ROOT, 'layers.blend')
# open file
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath_layers)
# create sub-collections
three_b = bpy.data.objects.get('T.3b')
three_c = bpy.data.objects.get('T.3c')
three_d = bpy.data.objects.get('T.3d')
scene = bpy.context.scene
subzero = scene.master_collection.collections['1'].collections.new('sub-zero')
scorpion = scene.master_collection.collections['1'].collections.new('scorpion')
# test linking sync
subzero.objects.link(three_b)
scorpion.objects.link(three_c)
# test unlinking sync
if unlink_mode in {'OBJECT', 'COLLECTION'}:
scorpion.objects.link(three_d)
scorpion.objects.unlink(three_d)
if unlink_mode == 'COLLECTION':
scorpion.objects.link(three_d)
scene.master_collection.collections['1'].collections.remove(subzero)
scene.master_collection.collections['1'].collections.remove(scorpion)
# save file
filepath_nested = os.path.join(dirpath, 'nested.blend')
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath_nested)
# get the generated json
datas = query_scene(filepath_nested, 'Main', (get_scene_collections, get_layers))
self.assertTrue(datas, "Data is not valid")
filepath_nested_json = os.path.join(dirpath, "nested.json")
with open(filepath_nested_json, "w") as f:
for data in datas:
f.write(dump(data))
self.assertTrue(compare_files(
filepath_nested_json,
filepath_json,
),
"Scene dump files differ")
def test_syncing_link(self):
"""
See if scene collections and layer collections are in sync
when we create new subcollections and link new objects
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_nested.json')
self.do_syncing(filepath_json, 'NONE')
def test_syncing_unlink_object(self):
"""
See if scene collections and layer collections are in sync
when we create new subcollections, link new objects and unlink
some.
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers_nested.json')
self.do_syncing(filepath_json, 'OBJECT')
def test_syncing_unlink_collection(self):
"""
See if scene collections and layer collections are in sync
when we create new subcollections, link new objects and unlink full collections
some.
"""
import os
ROOT = self.get_root()
filepath_json = os.path.join(ROOT, 'layers.json')
self.do_syncing(filepath_json, 'COLLECTION')
# ############################################################
# Main - Same For All Render Layer Tests
# ############################################################
if __name__ == '__main__':
import sys
extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else [])
UnitTesting._extra_arguments = extra_arguments
unittest.main()