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/gtests/alembic/CMakeLists.txt4
-rw-r--r--tests/gtests/alembic/abc_export_test.cc26
-rw-r--r--tests/gtests/alembic/abc_matrix_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_edgehash_test.cc405
-rw-r--r--tests/gtests/blenlib/BLI_expr_pylike_eval_test.cc310
-rw-r--r--tests/gtests/blenlib/BLI_heap_simple_test.cc118
-rw-r--r--tests/gtests/blenlib/BLI_heap_test.cc1
-rw-r--r--tests/gtests/blenlib/BLI_kdopbvh_test.cc24
-rw-r--r--tests/gtests/blenlib/BLI_math_base_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_memiter_test.cc206
-rw-r--r--tests/gtests/blenlib/BLI_string_utf8_test.cc4
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt7
-rw-r--r--tests/gtests/bmesh/CMakeLists.txt3
-rw-r--r--tests/gtests/guardedalloc/CMakeLists.txt3
-rw-r--r--tests/gtests/testing/CMakeLists.txt3
-rw-r--r--tests/python/CMakeLists.txt70
-rwxr-xr-xtests/python/alembic_tests.py10
-rw-r--r--tests/python/batch_import.py2
-rw-r--r--tests/python/bl_alembic_import_test.py28
-rw-r--r--tests/python/bl_keymap_completeness.py19
-rw-r--r--tests/python/bl_load_addons.py8
-rw-r--r--tests/python/bl_load_py_modules.py4
-rw-r--r--tests/python/bl_mesh_modifiers.py14
-rw-r--r--tests/python/bl_mesh_validate.py2
-rw-r--r--tests/python/bl_pyapi_idprop.py5
-rw-r--r--tests/python/bl_pyapi_idprop_datablock.py22
-rw-r--r--tests/python/bl_pyapi_mathutils.py102
-rw-r--r--tests/python/bl_rna_defaults.py4
-rw-r--r--tests/python/bl_rst_completeness.py19
-rw-r--r--tests/python/bl_run_operators.py5
-rw-r--r--tests/python/collada/CMakeLists.txt3
-rwxr-xr-xtests/python/cycles_render_tests.py4
-rwxr-xr-xtests/python/eevee_render_tests.py135
-rwxr-xr-xtests/python/ffmpeg_tests.py33
-rwxr-xr-xtests/python/modules/render_report.py76
-rwxr-xr-xtests/python/modules/test_utils.py3
-rwxr-xr-xtests/python/opengl_draw_tests.py2
-rw-r--r--tests/python/pep8.py4
-rw-r--r--tests/python/rna_info_dump.py4
-rw-r--r--tests/python/view_layer/CMakeLists.txt185
-rw-r--r--tests/python/view_layer/test_active_collection.py70
-rw-r--r--tests/python/view_layer/test_background_set.py64
-rw-r--r--tests/python/view_layer/test_collection_new_sync.py47
-rw-r--r--tests/python/view_layer/test_collection_rename_a.py91
-rw-r--r--tests/python/view_layer/test_collection_rename_b.py58
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_a.py34
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_b.py35
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_c.py34
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_d.py34
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_e.py35
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_f.py36
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_g.py36
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_h.py36
-rw-r--r--tests/python/view_layer/test_evaluation_render_settings_i.py36
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_a.py53
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_b.py55
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_c.py53
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_d.py56
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_e.py55
-rw-r--r--tests/python/view_layer/test_evaluation_selectability_f.py44
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_a.py53
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_b.py53
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_c.py53
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_d.py50
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_e.py54
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_f.py54
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_g.py30
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_h.py30
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_i.py30
-rw-r--r--tests/python/view_layer/test_evaluation_visibility_j.py61
-rw-r--r--tests/python/view_layer/test_group_a.py46
-rw-r--r--tests/python/view_layer/test_group_b.py72
-rw-r--r--tests/python/view_layer/test_group_c.py56
-rw-r--r--tests/python/view_layer/test_group_d.py75
-rw-r--r--tests/python/view_layer/test_group_e.py72
-rw-r--r--tests/python/view_layer/test_layer_linking.py109
-rw-r--r--tests/python/view_layer/test_layer_syncing.py113
-rw-r--r--tests/python/view_layer/test_make_single_user.py54
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_a.py48
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_b.py48
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_c.py48
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_d.py48
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_e.py40
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_f.py100
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_g.py81
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_h.py66
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_i.py73
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_j.py63
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_k.py40
-rw-r--r--tests/python/view_layer/test_move_above_below_layer_collection_l.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_a.py80
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_b.py69
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_c.py51
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_d.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_e.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_f.py51
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_g.py44
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_h.py84
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_i.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_a.py80
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_b.py69
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_c.py51
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_d.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_e.py60
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_f.py51
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_g.py44
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_h.py84
-rw-r--r--tests/python/view_layer/test_move_above_below_scene_collection_sync_i.py60
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_a.py69
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_b.py40
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_c.py40
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_d.py40
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_e.py40
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_f.py86
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_g.py77
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_h.py76
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_i.py40
-rw-r--r--tests/python/view_layer/test_move_into_layer_collection_j.py41
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_a.py53
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_b.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_c.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_d.py37
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_e.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_f.py51
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_g.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_h.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_i.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_j.py43
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_k.py36
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_l.py36
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_a.py37
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_b.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_c.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_d.py37
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_e.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_f.py51
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_g.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_h.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_i.py52
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_j.py43
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_k.py36
-rw-r--r--tests/python/view_layer/test_move_into_scene_collection_sync_l.py36
-rw-r--r--tests/python/view_layer/test_object_add_cylinder.py34
-rw-r--r--tests/python/view_layer/test_object_add_empty.py34
-rw-r--r--tests/python/view_layer/test_object_add_no_collection_cylinder.py32
-rw-r--r--tests/python/view_layer/test_object_add_no_collection_empty.py31
-rw-r--r--tests/python/view_layer/test_object_add_no_collection_torus.py31
-rw-r--r--tests/python/view_layer/test_object_add_torus.py34
-rw-r--r--tests/python/view_layer/test_object_copy.py93
-rw-r--r--tests/python/view_layer/test_object_delete_a.py31
-rw-r--r--tests/python/view_layer/test_object_delete_b.py31
-rw-r--r--tests/python/view_layer/test_object_link_a.py32
-rw-r--r--tests/python/view_layer/test_object_link_b.py33
-rw-r--r--tests/python/view_layer/test_object_link_c.py35
-rw-r--r--tests/python/view_layer/test_operator_context.py131
-rw-r--r--tests/python/view_layer/test_scene_collection_delete.py49
-rw-r--r--tests/python/view_layer/test_scene_copy_a.py37
-rw-r--r--tests/python/view_layer/test_scene_copy_b.py38
-rw-r--r--tests/python/view_layer/test_scene_copy_c.py37
-rw-r--r--tests/python/view_layer/test_scene_copy_d.py37
-rw-r--r--tests/python/view_layer/test_scene_copy_e.py47
-rw-r--r--tests/python/view_layer/test_scene_copy_f.py89
-rw-r--r--tests/python/view_layer/test_scene_delete.py34
-rw-r--r--tests/python/view_layer/test_scene_objects.py53
-rw-r--r--tests/python/view_layer/test_scene_write_read.py144
-rw-r--r--tests/python/view_layer/test_view_layer_rename.py33
-rw-r--r--tests/python/view_layer/view_layer_common.py821
167 files changed, 9229 insertions, 182 deletions
diff --git a/tests/gtests/alembic/CMakeLists.txt b/tests/gtests/alembic/CMakeLists.txt
index 1511024ee51..bf1577ff33a 100644
--- a/tests/gtests/alembic/CMakeLists.txt
+++ b/tests/gtests/alembic/CMakeLists.txt
@@ -16,9 +16,6 @@
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
-#
-# Contributor(s): Sybren A. Stüvel
-#
# ***** END GPL LICENSE BLOCK *****
set(INC
@@ -28,6 +25,7 @@ set(INC
../../../source/blender/blenkernel
../../../source/blender/alembic
../../../source/blender/makesdna
+ ../../../source/blender/depsgraph
${ALEMBIC_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
${HDF5_INCLUDE_DIRS}
diff --git a/tests/gtests/alembic/abc_export_test.cc b/tests/gtests/alembic/abc_export_test.cc
index a3eb2c412df..ac7760d1541 100644
--- a/tests/gtests/alembic/abc_export_test.cc
+++ b/tests/gtests/alembic/abc_export_test.cc
@@ -1,21 +1,25 @@
#include "testing/testing.h"
-// Keep first since utildefines defines AT which conflicts with fucking STL
+// Keep first since utildefines defines AT which conflicts with STL
#include "intern/abc_util.h"
#include "intern/abc_exporter.h"
extern "C" {
#include "BLI_utildefines.h"
-#include "BKE_library.h"
+#include "BKE_main.h"
#include "BLI_math.h"
#include "DNA_scene_types.h"
}
+#include "DEG_depsgraph.h"
+
class TestableAbcExporter : public AbcExporter {
public:
- TestableAbcExporter(Main *bmain, Scene *scene, const char *filename, ExportSettings &settings)
- : AbcExporter(bmain, scene, filename, settings)
- {}
+ TestableAbcExporter(Main *bmain,
+ const char *filename, ExportSettings &settings)
+ : AbcExporter(bmain, filename, settings)
+ {
+ }
void getShutterSamples(unsigned int nr_of_samples,
bool time_relative,
@@ -28,7 +32,6 @@ public:
std::set<double> &frames) {
AbcExporter::getFrameSet(nr_of_samples, frames);
}
-
};
class AlembicExportTest : public testing::Test
@@ -36,6 +39,7 @@ class AlembicExportTest : public testing::Test
protected:
ExportSettings settings;
Scene scene;
+ Depsgraph *depsgraph;
TestableAbcExporter *exporter;
Main *bmain;
@@ -50,19 +54,27 @@ protected:
bmain = BKE_main_new();
+ /* TODO(sergey): Pass scene layer somehow? */
+ ViewLayer *view_layer = (ViewLayer *)scene.view_layers.first;
+ settings.depsgraph = depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ settings.scene = &scene;
+ settings.view_layer = view_layer;
+
exporter = NULL;
}
virtual void TearDown()
{
BKE_main_free(bmain);
+ DEG_graph_free(depsgraph);
delete exporter;
}
// Call after setting up the settings.
void createExporter()
{
- exporter = new TestableAbcExporter(bmain, &scene, "somefile.abc", settings);
+ exporter = new TestableAbcExporter(bmain, "somefile.abc", settings);
}
};
diff --git a/tests/gtests/alembic/abc_matrix_test.cc b/tests/gtests/alembic/abc_matrix_test.cc
index 08bce1ed50f..49fb662c934 100644
--- a/tests/gtests/alembic/abc_matrix_test.cc
+++ b/tests/gtests/alembic/abc_matrix_test.cc
@@ -1,6 +1,6 @@
#include "testing/testing.h"
-// Keep first since utildefines defines AT which conflicts with fucking STL
+// Keep first since utildefines defines AT which conflicts with STL
#include "intern/abc_util.h"
extern "C" {
diff --git a/tests/gtests/blenlib/BLI_edgehash_test.cc b/tests/gtests/blenlib/BLI_edgehash_test.cc
new file mode 100644
index 00000000000..a9771d50c92
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_edgehash_test.cc
@@ -0,0 +1,405 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+#include <vector>
+#include <algorithm>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_edgehash.h"
+}
+
+#define VALUE_1 POINTER_FROM_INT(1)
+#define VALUE_2 POINTER_FROM_INT(2)
+#define VALUE_3 POINTER_FROM_INT(3)
+
+TEST(edgehash, InsertIncreasesLength)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, ReinsertNewIncreasesLength)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+ BLI_edgehash_reinsert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, ReinsertExistingDoesNotIncreaseLength)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+ BLI_edgehash_reinsert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+ BLI_edgehash_reinsert(eh, 1, 2, VALUE_2);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+ BLI_edgehash_reinsert(eh, 2, 1, VALUE_2);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, ReinsertCanChangeValue)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
+ BLI_edgehash_reinsert(eh, 2, 1, VALUE_2);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
+ BLI_edgehash_reinsert(eh, 1, 2, VALUE_3);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_3);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupNonExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), nullptr);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupNonExistingWithDefault)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_lookup_default(eh, 1, 2, VALUE_1), VALUE_1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupExistingWithDefault)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_lookup_default(eh, 1, 2, VALUE_2), VALUE_1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupPExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ void *value = VALUE_1;
+ BLI_edgehash_insert(eh, 1, 2, value);
+ void **value_p = BLI_edgehash_lookup_p(eh, 1, 2);
+ ASSERT_EQ(*value_p, VALUE_1);
+ *value_p = VALUE_2;
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupPNonExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_EQ(BLI_edgehash_lookup_p(eh, 1, 2), nullptr);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, EnsurePNonExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ void **value_p;
+ bool existed = BLI_edgehash_ensure_p(eh, 1, 2, &value_p);
+ ASSERT_FALSE(existed);
+ *value_p = VALUE_1;
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, EnsurePExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ void **value_p;
+ bool existed = BLI_edgehash_ensure_p(eh, 1, 2, &value_p);
+ ASSERT_TRUE(existed);
+ ASSERT_EQ(*value_p, VALUE_1);
+ *value_p = VALUE_2;
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, RemoveExistingDecreasesLength)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+ bool has_been_removed = BLI_edgehash_remove(eh, 1, 2, nullptr);
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+ ASSERT_TRUE(has_been_removed);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, RemoveNonExistingDoesNotDecreaseLength)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+ bool has_been_removed = BLI_edgehash_remove(eh, 4, 5, nullptr);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+ ASSERT_FALSE(has_been_removed);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, PopKeyTwice)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_popkey(eh, 1, 2), VALUE_1);
+ ASSERT_EQ(BLI_edgehash_popkey(eh, 1, 2), nullptr);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, LookupInvertedIndices)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, HasKeyExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ ASSERT_TRUE(BLI_edgehash_haskey(eh, 1, 2));
+ ASSERT_TRUE(BLI_edgehash_haskey(eh, 2, 1));
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, HasKeyNonExisting)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ ASSERT_FALSE(BLI_edgehash_haskey(eh, 1, 2));
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, ClearSetsLengthToZero)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ BLI_edgehash_insert(eh, 1, 2, VALUE_2);
+ ASSERT_EQ(BLI_edgehash_len(eh), 2);
+ BLI_edgehash_clear(eh, nullptr);
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, IteratorFindsAllValues)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ BLI_edgehash_insert(eh, 1, 3, VALUE_2);
+ BLI_edgehash_insert(eh, 1, 4, VALUE_3);
+
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
+ auto a = BLI_edgehashIterator_getValue(ehi);
+ BLI_edgehashIterator_step(ehi);
+ auto b = BLI_edgehashIterator_getValue(ehi);
+ BLI_edgehashIterator_step(ehi);
+ auto c = BLI_edgehashIterator_getValue(ehi);
+ BLI_edgehashIterator_step(ehi);
+
+ ASSERT_NE(a, b);
+ ASSERT_NE(b, c);
+ ASSERT_NE(a, c);
+ ASSERT_TRUE(ELEM(a, VALUE_1, VALUE_2, VALUE_3));
+ ASSERT_TRUE(ELEM(b, VALUE_1, VALUE_2, VALUE_3));
+ ASSERT_TRUE(ELEM(c, VALUE_1, VALUE_2, VALUE_3));
+
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, IterateIsDone)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ BLI_edgehash_insert(eh, 1, 3, VALUE_2);
+ BLI_edgehash_insert(eh, 1, 4, VALUE_3);
+
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
+ ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
+ BLI_edgehashIterator_step(ehi);
+ ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
+ BLI_edgehashIterator_step(ehi);
+ ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
+ BLI_edgehashIterator_step(ehi);
+ ASSERT_TRUE(BLI_edgehashIterator_isDone(ehi));
+
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgehash, DoubleRemove)
+{
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ BLI_edgehash_insert(eh, 1, 2, VALUE_1);
+ BLI_edgehash_insert(eh, 1, 3, VALUE_2);
+ BLI_edgehash_insert(eh, 1, 4, VALUE_3);
+ ASSERT_EQ(BLI_edgehash_len(eh), 3);
+
+ BLI_edgehash_remove(eh, 1, 2, nullptr);
+ BLI_edgehash_remove(eh, 1, 3, nullptr);
+ ASSERT_EQ(BLI_edgehash_len(eh), 1);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+struct Edge {
+ uint v1, v2;
+};
+
+TEST(edgehash, StressTest)
+{
+ std::srand(0);
+ int amount = 10000;
+
+ std::vector<Edge> edges;
+ for (int i = 0; i < amount; i++) {
+ edges.push_back({(uint)i, amount + (uint)std::rand() % 12345});
+ }
+
+ EdgeHash *eh = BLI_edgehash_new(__func__);
+
+ /* first insert all the edges */
+ for (int i = 0; i < edges.size(); i++) {
+ BLI_edgehash_insert(eh, edges[i].v1, edges[i].v2, POINTER_FROM_INT(i));
+ }
+
+ std::vector<Edge> shuffled = edges;
+ std::random_shuffle(shuffled.begin(), shuffled.end());
+
+ /* then remove half of them */
+ int remove_until = shuffled.size() / 2;
+ for (int i = 0; i < remove_until; i++) {
+ BLI_edgehash_remove(eh, shuffled[i].v2, shuffled[i].v1, nullptr);
+ }
+
+ ASSERT_EQ(BLI_edgehash_len(eh), edges.size() - remove_until);
+
+ /* check if the right ones have been removed */
+ for (int i = 0; i < shuffled.size(); i++) {
+ bool haskey = BLI_edgehash_haskey(eh, shuffled[i].v1, shuffled[i].v2);
+ if (i < remove_until) ASSERT_FALSE(haskey);
+ else ASSERT_TRUE(haskey);
+ }
+
+ /* reinsert all edges */
+ for (int i = 0; i < edges.size(); i++) {
+ BLI_edgehash_reinsert(eh, edges[i].v1, edges[i].v2, POINTER_FROM_INT(i));
+ }
+
+ ASSERT_EQ(BLI_edgehash_len(eh), edges.size());
+
+ /* pop all edges */
+ for (int i = 0; i < edges.size(); i++) {
+ int value = POINTER_AS_INT(BLI_edgehash_popkey(eh, edges[i].v1, edges[i].v2));
+ ASSERT_EQ(i, value);
+ }
+
+ ASSERT_EQ(BLI_edgehash_len(eh), 0);
+
+ BLI_edgehash_free(eh, nullptr);
+}
+
+TEST(edgeset, AddNonExistingIncreasesLength)
+{
+ EdgeSet *es = BLI_edgeset_new(__func__);
+
+ ASSERT_EQ(BLI_edgeset_len(es), 0);
+ BLI_edgeset_add(es, 1, 2);
+ ASSERT_EQ(BLI_edgeset_len(es), 1);
+ BLI_edgeset_add(es, 1, 3);
+ ASSERT_EQ(BLI_edgeset_len(es), 2);
+ BLI_edgeset_add(es, 1, 4);
+ ASSERT_EQ(BLI_edgeset_len(es), 3);
+
+ BLI_edgeset_free(es);
+}
+
+TEST(edgeset, AddExistingDoesNotIncreaseLength)
+{
+ EdgeSet *es = BLI_edgeset_new(__func__);
+
+ ASSERT_EQ(BLI_edgeset_len(es), 0);
+ BLI_edgeset_add(es, 1, 2);
+ ASSERT_EQ(BLI_edgeset_len(es), 1);
+ BLI_edgeset_add(es, 2, 1);
+ ASSERT_EQ(BLI_edgeset_len(es), 1);
+ BLI_edgeset_add(es, 1, 2);
+ ASSERT_EQ(BLI_edgeset_len(es), 1);
+
+ BLI_edgeset_free(es);
+}
+
+TEST(edgeset, HasKeyNonExisting)
+{
+ EdgeSet *es = BLI_edgeset_new(__func__);
+
+ ASSERT_FALSE(BLI_edgeset_haskey(es, 1, 2));
+
+ BLI_edgeset_free(es);
+}
+
+TEST(edgeset, HasKeyExisting)
+{
+ EdgeSet *es = BLI_edgeset_new(__func__);
+
+ BLI_edgeset_insert(es, 1, 2);
+ ASSERT_TRUE(BLI_edgeset_haskey(es, 1, 2));
+
+ BLI_edgeset_free(es);
+}
diff --git a/tests/gtests/blenlib/BLI_expr_pylike_eval_test.cc b/tests/gtests/blenlib/BLI_expr_pylike_eval_test.cc
new file mode 100644
index 00000000000..51e5b02232b
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_expr_pylike_eval_test.cc
@@ -0,0 +1,310 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include <string.h>
+
+extern "C" {
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_math.h"
+};
+
+#define TRUE_VAL 1.0
+#define FALSE_VAL 0.0
+
+static void expr_pylike_parse_fail_test(const char *str)
+{
+ ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, NULL, 0);
+
+ EXPECT_FALSE(BLI_expr_pylike_is_valid(expr));
+
+ BLI_expr_pylike_free(expr);
+}
+
+static void expr_pylike_const_test(const char *str, double value, bool force_const)
+{
+ ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, NULL, 0);
+
+ if (force_const) {
+ EXPECT_TRUE(BLI_expr_pylike_is_constant(expr));
+ }
+ else {
+ EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
+ EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
+ }
+
+ double result;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, NULL, 0, &result);
+
+ EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
+ EXPECT_EQ(result, value);
+
+ BLI_expr_pylike_free(expr);
+}
+
+static ExprPyLike_Parsed *parse_for_eval(const char *str, bool nonconst)
+{
+ const char *names[1] = {"x"};
+ ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, names, ARRAY_SIZE(names));
+
+ EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
+
+ if (nonconst) {
+ EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
+ }
+
+ return expr;
+}
+
+static void verify_eval_result(ExprPyLike_Parsed *expr, double x, double value)
+{
+ double result;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &x, 1, &result);
+
+ EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
+ EXPECT_EQ(result, value);
+}
+
+static void expr_pylike_eval_test(const char *str, double x, double value)
+{
+ ExprPyLike_Parsed *expr = parse_for_eval(str, true);
+ verify_eval_result(expr, x, value);
+ BLI_expr_pylike_free(expr);
+}
+
+static void expr_pylike_error_test(const char *str, double x, eExprPyLike_EvalStatus error)
+{
+ ExprPyLike_Parsed *expr = parse_for_eval(str, false);
+
+ double result;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &x, 1, &result);
+
+ EXPECT_EQ(status, error);
+
+ BLI_expr_pylike_free(expr);
+}
+
+#define TEST_PARSE_FAIL(name, str) \
+ TEST(expr_pylike, ParseFail_##name) { expr_pylike_parse_fail_test(str); }
+
+TEST_PARSE_FAIL(Empty, "")
+TEST_PARSE_FAIL(ConstHex, "0x0")
+TEST_PARSE_FAIL(ConstOctal, "01")
+TEST_PARSE_FAIL(Tail, "0 0")
+TEST_PARSE_FAIL(ConstFloatExp, "0.5e+")
+TEST_PARSE_FAIL(BadId, "Pi")
+TEST_PARSE_FAIL(BadArgCount0, "sqrt")
+TEST_PARSE_FAIL(BadArgCount1, "sqrt()")
+TEST_PARSE_FAIL(BadArgCount2, "sqrt(1,2)")
+TEST_PARSE_FAIL(BadArgCount3, "pi()")
+TEST_PARSE_FAIL(BadArgCount4, "max()")
+TEST_PARSE_FAIL(BadArgCount5, "min()")
+
+TEST_PARSE_FAIL(Truncated1, "(1+2")
+TEST_PARSE_FAIL(Truncated2, "1 if 2")
+TEST_PARSE_FAIL(Truncated3, "1 if 2 else")
+TEST_PARSE_FAIL(Truncated4, "1 < 2 <")
+TEST_PARSE_FAIL(Truncated5, "1 +")
+TEST_PARSE_FAIL(Truncated6, "1 *")
+TEST_PARSE_FAIL(Truncated7, "1 and")
+TEST_PARSE_FAIL(Truncated8, "1 or")
+TEST_PARSE_FAIL(Truncated9, "sqrt(1")
+TEST_PARSE_FAIL(Truncated10, "fmod(1,")
+
+/* Constant expression with working constant folding */
+#define TEST_CONST(name, str, value) \
+ TEST(expr_pylike, Const_##name) { expr_pylike_const_test(str, value, true); }
+
+/* Constant expression but constant folding is not supported */
+#define TEST_RESULT(name, str, value) \
+ TEST(expr_pylike, Result_##name) { expr_pylike_const_test(str, value, false); }
+
+/* Expression with an argument */
+#define TEST_EVAL(name, str, x, value) \
+ TEST(expr_pylike, Eval_##name) { expr_pylike_eval_test(str, x, value); }
+
+TEST_CONST(Zero, "0", 0.0)
+TEST_CONST(Zero2, "00", 0.0)
+TEST_CONST(One, "1", 1.0)
+TEST_CONST(OneF, "1.0", 1.0)
+TEST_CONST(OneF2, "1.", 1.0)
+TEST_CONST(OneE, "1e0", 1.0)
+TEST_CONST(TenE, "1.e+1", 10.0)
+TEST_CONST(Half, ".5", 0.5)
+
+TEST_CONST(Pi, "pi", M_PI)
+TEST_CONST(True, "True", TRUE_VAL)
+TEST_CONST(False, "False", FALSE_VAL)
+
+TEST_CONST(Sqrt, "sqrt(4)", 2.0)
+TEST_EVAL(Sqrt, "sqrt(x)", 4.0, 2.0)
+
+TEST_CONST(FMod, "fmod(3.5, 2)", 1.5)
+TEST_EVAL(FMod, "fmod(x, 2)", 3.5, 1.5)
+
+TEST_CONST(Pow, "pow(4, 0.5)", 2.0)
+TEST_EVAL(Pow, "pow(4, x)", 0.5, 2.0)
+
+TEST_RESULT(Min1, "min(3,1,2)", 1.0)
+TEST_RESULT(Max1, "max(3,1,2)", 3.0)
+TEST_RESULT(Min2, "min(1,2,3)", 1.0)
+TEST_RESULT(Max2, "max(1,2,3)", 3.0)
+TEST_RESULT(Min3, "min(2,3,1)", 1.0)
+TEST_RESULT(Max3, "max(2,3,1)", 3.0)
+
+TEST_CONST(UnaryPlus, "+1", 1.0)
+
+TEST_CONST(UnaryMinus, "-1", -1.0)
+TEST_EVAL(UnaryMinus, "-x", 1.0, -1.0)
+
+TEST_CONST(BinaryPlus, "1+2", 3.0)
+TEST_EVAL(BinaryPlus, "x+2", 1, 3.0)
+
+TEST_CONST(BinaryMinus, "1-2", -1.0)
+TEST_EVAL(BinaryMinus, "1-x", 2, -1.0)
+
+TEST_CONST(BinaryMul, "2*3", 6.0)
+TEST_EVAL(BinaryMul, "x*3", 2, 6.0)
+
+TEST_CONST(BinaryDiv, "3/2", 1.5)
+TEST_EVAL(BinaryDiv, "3/x", 2, 1.5)
+
+TEST_CONST(Arith1, "1 + -2 * 3", -5.0)
+TEST_CONST(Arith2, "(1 + -2) * 3", -3.0)
+TEST_CONST(Arith3, "-1 + 2 * 3", 5.0)
+TEST_CONST(Arith4, "3 * (-2 + 1)", -3.0)
+
+TEST_EVAL(Arith1, "1 + -x * 3", 2, -5.0)
+
+TEST_CONST(Eq1, "1 == 1.0", TRUE_VAL)
+TEST_CONST(Eq2, "1 == 2.0", FALSE_VAL)
+TEST_CONST(Eq3, "True == 1", TRUE_VAL)
+TEST_CONST(Eq4, "False == 0", TRUE_VAL)
+
+TEST_EVAL(Eq1, "1 == x", 1.0, TRUE_VAL)
+TEST_EVAL(Eq2, "1 == x", 2.0, FALSE_VAL)
+
+TEST_CONST(NEq1, "1 != 1.0", FALSE_VAL)
+TEST_CONST(NEq2, "1 != 2.0", TRUE_VAL)
+
+TEST_EVAL(NEq1, "1 != x", 1.0, FALSE_VAL)
+TEST_EVAL(NEq2, "1 != x", 2.0, TRUE_VAL)
+
+TEST_CONST(Lt1, "1 < 1", FALSE_VAL)
+TEST_CONST(Lt2, "1 < 2", TRUE_VAL)
+TEST_CONST(Lt3, "2 < 1", FALSE_VAL)
+
+TEST_CONST(Le1, "1 <= 1", TRUE_VAL)
+TEST_CONST(Le2, "1 <= 2", TRUE_VAL)
+TEST_CONST(Le3, "2 <= 1", FALSE_VAL)
+
+TEST_CONST(Gt1, "1 > 1", FALSE_VAL)
+TEST_CONST(Gt2, "1 > 2", FALSE_VAL)
+TEST_CONST(Gt3, "2 > 1", TRUE_VAL)
+
+TEST_CONST(Ge1, "1 >= 1", TRUE_VAL)
+TEST_CONST(Ge2, "1 >= 2", FALSE_VAL)
+TEST_CONST(Ge3, "2 >= 1", TRUE_VAL)
+
+TEST_CONST(Cmp1, "3 == 1 + 2", TRUE_VAL)
+
+TEST_EVAL(Cmp1, "3 == x + 2", 1, TRUE_VAL)
+TEST_EVAL(Cmp1b, "3 == x + 2", 1.5, FALSE_VAL)
+
+TEST_RESULT(CmpChain1, "1 < 2 < 3", TRUE_VAL)
+TEST_RESULT(CmpChain2, "1 < 2 == 2", TRUE_VAL)
+TEST_RESULT(CmpChain3, "1 < 2 > -1", TRUE_VAL)
+TEST_RESULT(CmpChain4, "1 < 2 < 2 < 3", FALSE_VAL)
+TEST_RESULT(CmpChain5, "1 < 2 <= 2 < 3", TRUE_VAL)
+
+TEST_EVAL(CmpChain1a, "1 < x < 3", 2, TRUE_VAL)
+TEST_EVAL(CmpChain1b, "1 < x < 3", 1, FALSE_VAL)
+TEST_EVAL(CmpChain1c, "1 < x < 3", 3, FALSE_VAL)
+
+TEST_CONST(Not1, "not 2", FALSE_VAL)
+TEST_CONST(Not2, "not 0", TRUE_VAL)
+TEST_CONST(Not3, "not not 2", TRUE_VAL)
+
+TEST_EVAL(Not1, "not x", 2, FALSE_VAL)
+TEST_EVAL(Not2, "not x", 0, TRUE_VAL)
+
+TEST_RESULT(And1, "2 and 3", 3.0)
+TEST_RESULT(And2, "0 and 3", 0.0)
+
+TEST_RESULT(Or1, "2 or 3", 2.0)
+TEST_RESULT(Or2, "0 or 3", 3.0)
+
+TEST_RESULT(Bool1, "2 or 3 and 4", 2.0)
+TEST_RESULT(Bool2, "not 2 or 3 and 4", 4.0)
+
+TEST(expr_pylike, Eval_Ternary1)
+{
+ ExprPyLike_Parsed *expr = parse_for_eval("x / 2 if x < 4 else x - 2 if x < 8 else x*2 - 12", true);
+
+ for (int i = 0; i <= 10; i++) {
+ double x = i;
+ double v = (x < 4) ? (x / 2) : (x < 8) ? (x - 2) : (x*2 - 12);
+
+ verify_eval_result(expr, x, v);
+ }
+
+ BLI_expr_pylike_free(expr);
+}
+
+TEST(expr_pylike, MultipleArgs)
+{
+ const char* names[3] = {"x", "y", "x"};
+ double values[3] = {1.0, 2.0, 3.0};
+
+ ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("x*10 + y", names, ARRAY_SIZE(names));
+
+ EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
+
+ double result;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, values, 3, &result);
+
+ EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
+ EXPECT_EQ(result, 32.0);
+
+ BLI_expr_pylike_free(expr);
+}
+
+#define TEST_ERROR(name, str, x, code) \
+ TEST(expr_pylike, Error_##name) { expr_pylike_error_test(str, x, code); }
+
+TEST_ERROR(DivZero1, "0 / 0", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(DivZero2, "1 / 0", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(DivZero3, "1 / x", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(DivZero4, "1 / x", 1.0, EXPR_PYLIKE_SUCCESS)
+
+TEST_ERROR(SqrtDomain1, "sqrt(-1)", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(SqrtDomain2, "sqrt(x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(SqrtDomain3, "sqrt(x)", 0.0, EXPR_PYLIKE_SUCCESS)
+
+TEST_ERROR(PowDomain1, "pow(-1, 0.5)", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(PowDomain2, "pow(-1, x)", 0.5, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(PowDomain3, "pow(-1, x)", 2.0, EXPR_PYLIKE_SUCCESS)
+
+TEST_ERROR(Mixed1, "sqrt(x) + 1 / max(0, x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(Mixed2, "sqrt(x) + 1 / max(0, x)", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(Mixed3, "sqrt(x) + 1 / max(0, x)", 1.0, EXPR_PYLIKE_SUCCESS)
+
+TEST(expr_pylike, Error_Invalid)
+{
+ ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("", NULL, 0);
+ double result;
+
+ EXPECT_EQ(BLI_expr_pylike_eval(expr, NULL, 0, &result), EXPR_PYLIKE_INVALID);
+
+ BLI_expr_pylike_free(expr);
+}
+
+TEST(expr_pylike, Error_ArgumentCount)
+{
+ ExprPyLike_Parsed *expr = parse_for_eval("x", false);
+ double result;
+
+ EXPECT_EQ(BLI_expr_pylike_eval(expr, NULL, 0, &result), EXPR_PYLIKE_FATAL_ERROR);
+
+ BLI_expr_pylike_free(expr);
+}
diff --git a/tests/gtests/blenlib/BLI_heap_simple_test.cc b/tests/gtests/blenlib/BLI_heap_simple_test.cc
new file mode 100644
index 00000000000..9c97163f337
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_heap_simple_test.cc
@@ -0,0 +1,118 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+#include <string.h>
+
+extern "C" {
+#include "BLI_sys_types.h"
+#include "BLI_compiler_attrs.h"
+#include "BLI_heap_simple.h"
+#include "BLI_utildefines.h"
+#include "BLI_rand.h"
+
+#include "MEM_guardedalloc.h"
+};
+
+#define SIZE 1024
+
+
+static void range_fl(float *array_tar, const int size)
+{
+ float *array_pt = array_tar + (size - 1);
+ int i = size;
+ while (i--) {
+ *(array_pt--) = (float)i;
+ }
+}
+
+TEST(heap, SimpleEmpty)
+{
+ HeapSimple *heap;
+
+ heap = BLI_heapsimple_new();
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ EXPECT_EQ(BLI_heapsimple_len(heap), 0);
+ BLI_heapsimple_free(heap, NULL);
+}
+
+TEST(heap, SimpleOne)
+{
+ HeapSimple *heap;
+ const char *in = "test";
+
+ heap = BLI_heapsimple_new();
+
+ BLI_heapsimple_insert(heap, 0.0f, (void *)in);
+ EXPECT_FALSE(BLI_heapsimple_is_empty(heap));
+ EXPECT_EQ(BLI_heapsimple_len(heap), 1);
+ EXPECT_EQ(in, BLI_heapsimple_pop_min(heap));
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ EXPECT_EQ(BLI_heapsimple_len(heap), 0);
+ BLI_heapsimple_free(heap, NULL);
+}
+
+TEST(heap, SimpleRange)
+{
+ const int items_total = SIZE;
+ HeapSimple *heap = BLI_heapsimple_new();
+ for (int in = 0; in < items_total; in++) {
+ BLI_heapsimple_insert(heap, (float)in, POINTER_FROM_INT(in));
+ }
+ for (int out_test = 0; out_test < items_total; out_test++) {
+ EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
+
+ }
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ BLI_heapsimple_free(heap, NULL);
+}
+
+TEST(heap, SimpleRangeReverse)
+{
+ const int items_total = SIZE;
+ HeapSimple *heap = BLI_heapsimple_new();
+ for (int in = 0; in < items_total; in++) {
+ BLI_heapsimple_insert(heap, (float)-in, POINTER_FROM_INT(-in));
+ }
+ for (int out_test = items_total - 1; out_test >= 0; out_test--) {
+ EXPECT_EQ(-out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
+ }
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ BLI_heapsimple_free(heap, NULL);
+}
+
+TEST(heap, SimpleDuplicates)
+{
+ const int items_total = SIZE;
+ HeapSimple *heap = BLI_heapsimple_new();
+ for (int in = 0; in < items_total; in++) {
+ BLI_heapsimple_insert(heap, 1.0f, 0);
+ }
+ for (int out_test = 0; out_test < items_total; out_test++) {
+ EXPECT_EQ(0, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
+ }
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ BLI_heapsimple_free(heap, NULL);
+}
+
+static void random_heapsimple_helper(
+ const int items_total,
+ const int random_seed)
+{
+ HeapSimple *heap = BLI_heapsimple_new();
+ float *values = (float *)MEM_mallocN(sizeof(float) * items_total, __func__);
+ range_fl(values, items_total);
+ BLI_array_randomize(values, sizeof(float), items_total, random_seed);
+ for (int i = 0; i < items_total; i++) {
+ BLI_heapsimple_insert(heap, values[i], POINTER_FROM_INT((int)values[i]));
+ }
+ for (int out_test = 0; out_test < items_total; out_test++) {
+ EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
+ }
+ EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
+ BLI_heapsimple_free(heap, NULL);
+ MEM_freeN(values);
+}
+
+TEST(heap, SimpleRand1) { random_heapsimple_helper(1, 1234); }
+TEST(heap, SimpleRand2) { random_heapsimple_helper(2, 1234); }
+TEST(heap, SimpleRand100) { random_heapsimple_helper(100, 4321); }
diff --git a/tests/gtests/blenlib/BLI_heap_test.cc b/tests/gtests/blenlib/BLI_heap_test.cc
index 69566d8dca6..26f3aa19b9f 100644
--- a/tests/gtests/blenlib/BLI_heap_test.cc
+++ b/tests/gtests/blenlib/BLI_heap_test.cc
@@ -176,6 +176,7 @@ static void random_heap_reinsert_helper(
for (int out_test = 0; out_test < items_total; out_test++) {
HeapNode *node_top = BLI_heap_top(heap);
float out = BLI_heap_node_value(node_top);
+ EXPECT_EQ(out, BLI_heap_top_value(heap));
EXPECT_EQ((float)out_test, out);
BLI_heap_pop_min(heap);
}
diff --git a/tests/gtests/blenlib/BLI_kdopbvh_test.cc b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
index 48f4d7054da..ff4a74b8be8 100644
--- a/tests/gtests/blenlib/BLI_kdopbvh_test.cc
+++ b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
@@ -52,11 +52,23 @@ TEST(kdopbvh, Single)
BLI_bvhtree_free(tree);
}
+void optimal_check_callback(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+{
+ float (*points)[3] = (float (*)[3])userdata;
+
+ /* BVH_NEAREST_OPTIMAL_ORDER should hit the right node on the first try */
+ EXPECT_EQ(nearest->index, -1);
+ EXPECT_EQ_ARRAY(co, points[index], 3);
+
+ nearest->index = index;
+ nearest->dist_sq = len_squared_v3v3(co, points[index]);
+}
+
/**
* Note that a small epsilon is added to the BVH nodes bounds, even if we pass in zero.
* Use rounding to ensure very close nodes don't cause the wrong node to be found as nearest.
*/
-static void find_nearest_points_test(int points_len, float scale, int round, int random_seed)
+static void find_nearest_points_test(int points_len, float scale, int round, int random_seed, bool optimal = false)
{
struct RNG *rng = BLI_rng_new(random_seed);
BVHTree *tree = BLI_bvhtree_new(points_len, 0.0, 8, 8);
@@ -69,9 +81,13 @@ static void find_nearest_points_test(int points_len, float scale, int round, int
BLI_bvhtree_insert(tree, i, points[i], 1);
}
BLI_bvhtree_balance(tree);
+
/* first find each point */
+ BVHTree_NearestPointCallback callback = optimal ? optimal_check_callback : NULL;
+ int flags = optimal ? BVH_NEAREST_OPTIMAL_ORDER : 0;
+
for (int i = 0; i < points_len; i++) {
- const int j = BLI_bvhtree_find_nearest(tree, points[i], NULL, NULL, NULL);
+ const int j = BLI_bvhtree_find_nearest_ex(tree, points[i], NULL, callback, points, flags);
if (j != i) {
#if 0
const float dist = len_v3v3(points[i], points[j]);
@@ -95,3 +111,7 @@ static void find_nearest_points_test(int points_len, float scale, int round, int
TEST(kdopbvh, FindNearest_1) { find_nearest_points_test(1, 1.0, 1000, 1234); }
TEST(kdopbvh, FindNearest_2) { find_nearest_points_test(2, 1.0, 1000, 123); }
TEST(kdopbvh, FindNearest_500) { find_nearest_points_test(500, 1.0, 1000, 12); }
+
+TEST(kdopbvh, OptimalFindNearest_1) { find_nearest_points_test(1, 1.0, 1000, 1234, true); }
+TEST(kdopbvh, OptimalFindNearest_2) { find_nearest_points_test(2, 1.0, 1000, 123, true); }
+TEST(kdopbvh, OptimalFindNearest_500) { find_nearest_points_test(500, 1.0, 1000, 12, true); }
diff --git a/tests/gtests/blenlib/BLI_math_base_test.cc b/tests/gtests/blenlib/BLI_math_base_test.cc
index 0059eb54482..d8c01459179 100644
--- a/tests/gtests/blenlib/BLI_math_base_test.cc
+++ b/tests/gtests/blenlib/BLI_math_base_test.cc
@@ -76,7 +76,7 @@ TEST(math_base, CompareFFRelativeZero)
/* Note: in theory, this should return false, since 0.0f and -0.0f have 0x80000000 diff,
- * but overflow in substraction seems to break something here
+ * but overflow in subtraction seems to break something here
* (abs(*(int *)&fn0 - *(int *)&f0) == 0x80000000 == fn0), probably because int32 cannot hold this abs value.
* this is yet another illustration of why one shall never use (near-)zero floats in pure-ULP comparison. */
// EXPECT_FALSE(compare_ff_relative(fn0, f0, -1.0f, 1024));
diff --git a/tests/gtests/blenlib/BLI_memiter_test.cc b/tests/gtests/blenlib/BLI_memiter_test.cc
new file mode 100644
index 00000000000..601eadea267
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_memiter_test.cc
@@ -0,0 +1,206 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+extern "C" {
+#include "BLI_array_utils.h"
+#include "BLI_memiter.h"
+#include "MEM_guardedalloc.h"
+
+#include "BLI_string.h"
+#include "BLI_ressource_strings.h"
+}
+
+TEST(memiter, Nop)
+{
+ BLI_memiter *mi = BLI_memiter_create(64);
+ BLI_memiter_destroy(mi);
+}
+
+void memiter_empty_test(int num_elems, const int chunk_size)
+{
+ BLI_memiter *mi = BLI_memiter_create(chunk_size);
+ void *data;
+ for (int index = 0; index < num_elems; index++) {
+ data = BLI_memiter_alloc(mi, 0);
+ }
+ int index = 0, total_size = 0;
+ BLI_memiter_handle it;
+ BLI_memiter_iter_init(mi, &it);
+ uint elem_size;
+ while ((data = BLI_memiter_iter_step_size(&it, &elem_size))) {
+ index += 1;
+ total_size += elem_size;
+ }
+ EXPECT_EQ(0, total_size);
+ EXPECT_EQ(num_elems, index);
+
+ BLI_memiter_destroy(mi);
+}
+
+#define MEMITER_NUMBER_TEST_FN(fn, number_type) \
+void fn(int num_elems, const int chunk_size) \
+{ \
+ BLI_memiter *mi = BLI_memiter_create(chunk_size); \
+ number_type *data; \
+ for (int index = 0; index < num_elems; index++) { \
+ data = (number_type *)BLI_memiter_alloc(mi, sizeof(number_type)); \
+ *data = index; \
+ } \
+ BLI_memiter_handle it; \
+ BLI_memiter_iter_init(mi, &it); \
+ uint elem_size; \
+ int index = 0; \
+ while ((data = (number_type *)BLI_memiter_iter_step_size(&it, &elem_size))) { \
+ EXPECT_EQ(sizeof(number_type), elem_size); \
+ EXPECT_EQ(index, *data); \
+ index += 1; \
+ } \
+ BLI_memiter_destroy(mi); \
+}
+
+/* generate number functions */
+MEMITER_NUMBER_TEST_FN(memiter_char_test, char)
+MEMITER_NUMBER_TEST_FN(memiter_short_test, short)
+MEMITER_NUMBER_TEST_FN(memiter_int_test, int)
+MEMITER_NUMBER_TEST_FN(memiter_long_test, int64_t)
+
+void memiter_string_test(const char *strings[], const int chunk_size)
+{
+ BLI_memiter *mi = BLI_memiter_create(chunk_size);
+ char *data;
+ int index = 0;
+ int total_size_expect = 0;
+ while (strings[index]) {
+ const int size = strlen(strings[index]) + 1;
+ BLI_memiter_alloc_from(mi, size, strings[index]);
+ total_size_expect += size;
+ index += 1;
+ }
+ const int strings_len = index;
+ int total_size = 0;
+ BLI_memiter_handle it;
+ BLI_memiter_iter_init(mi, &it);
+ uint elem_size;
+ index = 0;
+ while ((data = (char *)BLI_memiter_iter_step_size(&it, &elem_size))) {
+ EXPECT_EQ(strlen(strings[index]) + 1, elem_size);
+ EXPECT_STREQ(strings[index], data);
+ total_size += elem_size;
+ index += 1;
+ }
+ EXPECT_EQ(total_size_expect, total_size);
+ EXPECT_EQ(strings_len, index);
+
+ BLI_memiter_destroy(mi);
+}
+
+void memiter_words10k_test(const char split_char, const int chunk_size)
+{
+ const int words_len = sizeof(words10k) - 1;
+ char *words = BLI_strdupn(words10k, words_len);
+ BLI_str_replace_char(words, split_char, '\0');
+
+ BLI_memiter *mi = BLI_memiter_create(chunk_size);
+
+ char *data;
+ int index;
+ char *c_end, *c;
+ c_end = words + words_len;
+ c = words;
+ index = 0;
+ while (c < c_end) {
+ int elem_size = strlen(c) + 1;
+ data = (char *)BLI_memiter_alloc(mi, elem_size);
+ memcpy(data, c, elem_size);
+ c += elem_size;
+ index += 1;
+ }
+ const int len_expect = index;
+ c = words;
+ uint size;
+ BLI_memiter_handle it;
+ BLI_memiter_iter_init(mi, &it);
+ index = 0;
+ while ((data = (char *)BLI_memiter_iter_step_size(&it, &size))) {
+ int size_expect = strlen(c) + 1;
+ EXPECT_EQ(size_expect, size);
+ EXPECT_STREQ(c, data);
+ c += size;
+ index += 1;
+ }
+ EXPECT_EQ(len_expect, index);
+ BLI_memiter_destroy(mi);
+ MEM_freeN(words);
+}
+
+
+#define TEST_EMPTY_AT_CHUNK_SIZE(chunk_size) \
+TEST(memiter, Empty0_##chunk_size) { memiter_empty_test(0, chunk_size); } \
+TEST(memiter, Empty1_##chunk_size) { memiter_empty_test(1, chunk_size); } \
+TEST(memiter, Empty2_##chunk_size) { memiter_empty_test(2, chunk_size); } \
+TEST(memiter, Empty3_##chunk_size) { memiter_empty_test(3, chunk_size); } \
+TEST(memiter, Empty13_##chunk_size) { memiter_empty_test(13, chunk_size); } \
+TEST(memiter, Empty256_##chunk_size) { memiter_empty_test(256, chunk_size); } \
+
+TEST_EMPTY_AT_CHUNK_SIZE(1)
+TEST_EMPTY_AT_CHUNK_SIZE(2)
+TEST_EMPTY_AT_CHUNK_SIZE(3)
+TEST_EMPTY_AT_CHUNK_SIZE(13)
+TEST_EMPTY_AT_CHUNK_SIZE(256)
+
+#define TEST_NUMBER_AT_CHUNK_SIZE(chunk_size) \
+TEST(memiter, Char1_##chunk_size) { memiter_char_test(1, chunk_size); } \
+TEST(memiter, Short1_##chunk_size) { memiter_short_test(1, chunk_size); } \
+TEST(memiter, Int1_##chunk_size) { memiter_int_test(1, chunk_size); } \
+TEST(memiter, Long1_##chunk_size) { memiter_long_test(1, chunk_size); } \
+\
+TEST(memiter, Char2_##chunk_size) { memiter_char_test(2, chunk_size); } \
+TEST(memiter, Short2_##chunk_size) { memiter_short_test(2, chunk_size); } \
+TEST(memiter, Int2_##chunk_size) { memiter_int_test(2, chunk_size); } \
+TEST(memiter, Long2_##chunk_size) { memiter_long_test(2, chunk_size); } \
+\
+TEST(memiter, Char3_##chunk_size) { memiter_char_test(3, chunk_size); } \
+TEST(memiter, Short3_##chunk_size) { memiter_short_test(3, chunk_size); } \
+TEST(memiter, Int3_##chunk_size) { memiter_int_test(3, chunk_size); } \
+TEST(memiter, Long3_##chunk_size) { memiter_long_test(3, chunk_size); } \
+\
+TEST(memiter, Char256_##chunk_size) { memiter_char_test(256, chunk_size); } \
+TEST(memiter, Short256_##chunk_size) { memiter_short_test(256, chunk_size); } \
+TEST(memiter, Int256_##chunk_size) { memiter_int_test(256, chunk_size); } \
+TEST(memiter, Long256_##chunk_size) { memiter_long_test(256, chunk_size); } \
+
+TEST_NUMBER_AT_CHUNK_SIZE(1)
+TEST_NUMBER_AT_CHUNK_SIZE(2)
+TEST_NUMBER_AT_CHUNK_SIZE(3)
+TEST_NUMBER_AT_CHUNK_SIZE(13)
+TEST_NUMBER_AT_CHUNK_SIZE(256)
+
+#define STRINGS_TEST(chunk_size, ...) { \
+ const char *data[] = {__VA_ARGS__, NULL}; \
+ memiter_string_test(data, chunk_size); \
+}
+
+#define TEST_STRINGS_AT_CHUNK_SIZE(chunk_size) \
+TEST(memiter, Strings_##chunk_size) { \
+ STRINGS_TEST(chunk_size, ""); \
+ STRINGS_TEST(chunk_size, "test", "me"); \
+ STRINGS_TEST(chunk_size, "more", "test", "data", "to", "follow"); \
+}
+
+TEST_STRINGS_AT_CHUNK_SIZE(1)
+TEST_STRINGS_AT_CHUNK_SIZE(2)
+TEST_STRINGS_AT_CHUNK_SIZE(3)
+TEST_STRINGS_AT_CHUNK_SIZE(13)
+TEST_STRINGS_AT_CHUNK_SIZE(256)
+
+
+#define TEST_WORDS10K_AT_CHUNK_SIZE(chunk_size) \
+TEST(memiter, Words10kSentence_##chunk_size) { memiter_words10k_test('.', chunk_size); } \
+TEST(memiter, Words10kWords_##chunk_size) { memiter_words10k_test(' ', chunk_size); } \
+
+TEST_WORDS10K_AT_CHUNK_SIZE(1)
+TEST_WORDS10K_AT_CHUNK_SIZE(2)
+TEST_WORDS10K_AT_CHUNK_SIZE(3)
+TEST_WORDS10K_AT_CHUNK_SIZE(13)
+TEST_WORDS10K_AT_CHUNK_SIZE(256)
diff --git a/tests/gtests/blenlib/BLI_string_utf8_test.cc b/tests/gtests/blenlib/BLI_string_utf8_test.cc
index 30dbccc97fe..89483d3d440 100644
--- a/tests/gtests/blenlib/BLI_string_utf8_test.cc
+++ b/tests/gtests/blenlib/BLI_string_utf8_test.cc
@@ -271,7 +271,7 @@ const char *utf8_invalid_tests[][3] = {
// (to convert between UTF-16LE and UTF-16BE).
// With such internal use of noncharacters, it may be desirable and safer to block those code points in
// UTF-8 decoders, as they should never occur legitimately in incoming UTF-8 data, and could trigger
-// unsafe behaviour in subsequent processing.
+// unsafe behavior in subsequent processing.
//
// Particularly problematic noncharacters in 16-bit applications:
{"5.3.1 U+FFFE = ef bf be = \"\xef\xbf\xbe\" |",
@@ -281,7 +281,7 @@ const char *utf8_invalid_tests[][3] = {
/* Fo now, we ignore those, they do not seem to be crucial anyway... */
// 5.3.3 U+FDD0 .. U+FDEF
// 5.3.4 U+nFFFE U+nFFFF (for n = 1..10)
- {NULL, NULL, NULL}
+ {NULL, NULL, NULL},
};
/* BLI_utf8_invalid_strip (and indirectly, BLI_utf8_invalid_byte). */
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 43883e83f6e..e837f703423 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -16,9 +16,6 @@
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
-#
-# Contributor(s): Sergey Sharybin
-#
# ***** END GPL LICENSE BLOCK *****
set(INC
@@ -43,15 +40,19 @@ endif()
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
+BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
+BLENDER_TEST(BLI_edgehash "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_heap "bf_blenlib")
+BLENDER_TEST(BLI_heap_simple "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_linklist_lockfree "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_math_base "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
BLENDER_TEST(BLI_math_geom "bf_blenlib")
+BLENDER_TEST(BLI_memiter "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
diff --git a/tests/gtests/bmesh/CMakeLists.txt b/tests/gtests/bmesh/CMakeLists.txt
index b62141e5984..6bd2be1ad83 100644
--- a/tests/gtests/bmesh/CMakeLists.txt
+++ b/tests/gtests/bmesh/CMakeLists.txt
@@ -16,9 +16,6 @@
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
-#
-# Contributor(s): Howard Trickey
-#
# ***** END GPL LICENSE BLOCK *****
set(INC
diff --git a/tests/gtests/guardedalloc/CMakeLists.txt b/tests/gtests/guardedalloc/CMakeLists.txt
index 0063d0ed873..812285c3e33 100644
--- a/tests/gtests/guardedalloc/CMakeLists.txt
+++ b/tests/gtests/guardedalloc/CMakeLists.txt
@@ -16,9 +16,6 @@
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
-#
-# Contributor(s): Sergey Sharybin
-#
# ***** END GPL LICENSE BLOCK *****
set(INC
diff --git a/tests/gtests/testing/CMakeLists.txt b/tests/gtests/testing/CMakeLists.txt
index 95ac59e6dce..22d2b960730 100644
--- a/tests/gtests/testing/CMakeLists.txt
+++ b/tests/gtests/testing/CMakeLists.txt
@@ -16,9 +16,6 @@
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
-#
-# Contributor(s): Sergey Sharybin
-#
# ***** END GPL LICENSE BLOCK *****
set(INC
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index d34c9f70f82..b2def0a310f 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -13,9 +13,6 @@
# 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.
@@ -531,9 +528,9 @@ function(add_python_test testname testscript)
endif()
endfunction()
-if(WITH_CYCLES)
- if(OPENIMAGEIO_IDIFF AND EXISTS "${TEST_SRC_DIR}/render/ctests/shader")
- macro(add_cycles_render_test subject)
+if(OPENIMAGEIO_IDIFF AND EXISTS "${TEST_SRC_DIR}/render/ctests/shader")
+ macro(add_cycles_render_test subject)
+ if(WITH_CYCLES)
add_python_test(
cycles_${subject}
${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
@@ -542,32 +539,40 @@ if(WITH_CYCLES)
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/cycles"
)
- endmacro()
- if(WITH_OPENGL_RENDER_TESTS)
- add_cycles_render_test(opengl)
endif()
- add_cycles_render_test(bake)
- add_cycles_render_test(bsdf)
- add_cycles_render_test(denoise)
- add_cycles_render_test(denoise_animation)
- add_cycles_render_test(displacement)
- add_cycles_render_test(hair)
- add_cycles_render_test(image_data_types)
- add_cycles_render_test(image_mapping)
- add_cycles_render_test(image_texture_limit)
- add_cycles_render_test(integrator)
- add_cycles_render_test(light)
- add_cycles_render_test(mesh)
- add_cycles_render_test(motion_blur)
- add_cycles_render_test(render_layer)
- add_cycles_render_test(reports)
- add_cycles_render_test(shader)
- add_cycles_render_test(shadow_catcher)
- add_cycles_render_test(sss)
- add_cycles_render_test(volume)
- else()
- MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
- endif()
+
+ if(WITH_OPENGL_RENDER_TESTS AND (NOT ${subject} MATCHES "bake"))
+ add_python_test(
+ eevee_${subject}_test
+ ${CMAKE_CURRENT_LIST_DIR}/eevee_render_tests.py
+ -blender "$<TARGET_FILE:blender>"
+ -testdir "${TEST_SRC_DIR}/render/ctests/${subject}"
+ -idiff "${OPENIMAGEIO_IDIFF}"
+ -outdir "${TEST_OUT_DIR}/eevee"
+ )
+ endif()
+ endmacro()
+ add_cycles_render_test(bake)
+ add_cycles_render_test(bsdf)
+ add_cycles_render_test(denoise)
+ add_cycles_render_test(denoise_animation)
+ add_cycles_render_test(displacement)
+ add_cycles_render_test(hair)
+ add_cycles_render_test(image_data_types)
+ add_cycles_render_test(image_mapping)
+ add_cycles_render_test(image_texture_limit)
+ add_cycles_render_test(integrator)
+ add_cycles_render_test(light)
+ add_cycles_render_test(mesh)
+ add_cycles_render_test(motion_blur)
+ add_cycles_render_test(render_layer)
+ add_cycles_render_test(reports)
+ add_cycles_render_test(shader)
+ add_cycles_render_test(shadow_catcher)
+ add_cycles_render_test(sss)
+ add_cycles_render_test(volume)
+elseif(WITH_CYCLES)
+ MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
endif()
if(WITH_OPENGL_DRAW_TESTS)
@@ -633,3 +638,6 @@ if(WITH_CODEC_FFMPEG)
endif()
add_subdirectory(collada)
+
+# TODO: disabled for now after collection unification
+# add_subdirectory(view_layer)
diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py
index d872e699cea..09e9b8981e3 100755
--- a/tests/python/alembic_tests.py
+++ b/tests/python/alembic_tests.py
@@ -20,17 +20,15 @@
# <pep8 compliant>
import argparse
-import functools
-import shutil
import pathlib
import subprocess
import sys
-import tempfile
import unittest
-from modules.test_utils import (with_tempdir,
- AbstractBlenderRunnerTest,
- )
+from modules.test_utils import (
+ with_tempdir,
+ AbstractBlenderRunnerTest,
+)
class AbcPropError(Exception):
diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py
index a6e2469349b..20d96a69a79 100644
--- a/tests/python/batch_import.py
+++ b/tests/python/batch_import.py
@@ -157,7 +157,7 @@ def main():
parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
- options, args = parser.parse_args(argv) # In this example we wont use the args
+ options, _args = parser.parse_args(argv) # In this example we wont use the args
if not argv:
parser.print_help()
diff --git a/tests/python/bl_alembic_import_test.py b/tests/python/bl_alembic_import_test.py
index 17754169279..ad7d2fd398a 100644
--- a/tests/python/bl_alembic_import_test.py
+++ b/tests/python/bl_alembic_import_test.py
@@ -61,9 +61,9 @@ class SimpleImportTest(AbstractAlembicTest):
as_background_job=False)
self.assertEqual({'FINISHED'}, res)
- # The objects should be linked to scene_collection in Blender 2.8,
+ # The objects should be linked to scene.collection in Blender 2.8,
# and to scene in Blender 2.7x.
- objects = bpy.context.scene.objects
+ objects = bpy.context.scene.collection.objects
self.assertEqual(13, len(objects))
# Test the hierarchy.
@@ -81,9 +81,9 @@ class SimpleImportTest(AbstractAlembicTest):
as_background_job=False)
self.assertEqual({'FINISHED'}, res)
- # The objects should be linked to scene_collection in Blender 2.8,
+ # The objects should be linked to scene.collection in Blender 2.8,
# and to scene in Blender 2.7x.
- objects = bpy.context.scene.objects
+ objects = bpy.context.scene.collection.objects
# ABC parent is top-level object, which translates to nothing in Blender
self.assertIsNone(objects['locator1'].parent)
@@ -93,6 +93,7 @@ class SimpleImportTest(AbstractAlembicTest):
self.assertIsNone(objects['locator2'].parent)
# Shouldn't have inherited the ABC parent's transform.
+ loc2 = bpy.context.depsgraph.id_eval_get(objects['locator2'])
x, y, z = objects['locator2'].matrix_world.to_translation()
self.assertAlmostEqual(0, x)
self.assertAlmostEqual(0, y)
@@ -102,7 +103,8 @@ class SimpleImportTest(AbstractAlembicTest):
self.assertEqual(objects['locator2'], objects['locatorShape2'].parent)
# Should have inherited its ABC parent's transform.
- x, y, z = objects['locatorShape2'].matrix_world.to_translation()
+ locshp2 = bpy.context.depsgraph.id_eval_get(objects['locatorShape2'])
+ x, y, z = locshp2.matrix_world.to_translation()
self.assertAlmostEqual(0, x)
self.assertAlmostEqual(0, y)
self.assertAlmostEqual(2, z)
@@ -127,7 +129,7 @@ class SimpleImportTest(AbstractAlembicTest):
# All cubes should be selected, but the sphere shouldn't be.
for ob in bpy.data.objects:
- self.assertEqual('Cube' in ob.name, ob.select)
+ self.assertEqual('Cube' in ob.name, ob.select_get())
def test_change_path_constraint(self):
import math
@@ -142,6 +144,7 @@ class SimpleImportTest(AbstractAlembicTest):
# Check that the file loaded ok.
bpy.context.scene.frame_set(10)
+ cube = bpy.context.depsgraph.id_eval_get(cube)
x, y, z = cube.matrix_world.to_euler('XYZ')
self.assertAlmostEqual(x, 0)
self.assertAlmostEqual(y, 0)
@@ -152,6 +155,7 @@ class SimpleImportTest(AbstractAlembicTest):
bpy.data.cache_files[fname].filepath = relpath
bpy.context.scene.frame_set(10)
+ cube = bpy.context.depsgraph.id_eval_get(cube)
x, y, z = cube.matrix_world.to_euler('XYZ')
self.assertAlmostEqual(x, 0)
self.assertAlmostEqual(y, 0)
@@ -164,14 +168,13 @@ class SimpleImportTest(AbstractAlembicTest):
if args.with_legacy_depsgraph:
bpy.context.scene.frame_set(10)
+ cube = bpy.context.depsgraph.id_eval_get(cube)
x, y, z = cube.matrix_world.to_euler('XYZ')
self.assertAlmostEqual(x, math.pi / 2, places=5)
self.assertAlmostEqual(y, 0)
self.assertAlmostEqual(z, 0)
def test_change_path_modifier(self):
- import math
-
fname = 'animated-mesh.abc'
abc = self.testdir / fname
relpath = bpy.path.relpath(str(abc))
@@ -182,17 +185,18 @@ class SimpleImportTest(AbstractAlembicTest):
# Check that the file loaded ok.
bpy.context.scene.frame_set(6)
- mesh = plane.to_mesh(bpy.context.scene, True, 'RENDER')
+ scene = bpy.context.scene
+ mesh = plane.to_mesh(bpy.context.depsgraph, True, True, False)
self.assertAlmostEqual(-1, mesh.vertices[0].co.x)
self.assertAlmostEqual(-1, mesh.vertices[0].co.y)
self.assertAlmostEqual(0.5905638933181763, mesh.vertices[0].co.z)
# Change path from absolute to relative. This should not break the animation.
- bpy.context.scene.frame_set(1)
+ scene.frame_set(1)
bpy.data.cache_files[fname].filepath = relpath
- bpy.context.scene.frame_set(6)
+ scene.frame_set(6)
- mesh = plane.to_mesh(bpy.context.scene, True, 'RENDER')
+ mesh = plane.to_mesh(bpy.context.depsgraph, True, True, False)
self.assertAlmostEqual(1, mesh.vertices[3].co.x)
self.assertAlmostEqual(1, mesh.vertices[3].co.y)
self.assertAlmostEqual(0.5905638933181763, mesh.vertices[3].co.z)
diff --git a/tests/python/bl_keymap_completeness.py b/tests/python/bl_keymap_completeness.py
index 652ed449a3c..19541b355e2 100644
--- a/tests/python/bl_keymap_completeness.py
+++ b/tests/python/bl_keymap_completeness.py
@@ -18,21 +18,26 @@
# <pep8 compliant>
-# simple script to test 'keyconfig_utils' contains correct values.
+# simple script to test 'bl_keymap_utils.keymap_hierarchy' contains correct values.
+# Needed for 'bl_keymap_utils.keymap_hierarchy' which inspects tools.
+import sys
+import os
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, "release", "scripts", "startup"))
+del sys, os
-from bpy_extras import keyconfig_utils
+from bl_keymap_utils import keymap_hierarchy
def check_maps():
maps = {}
- def fill_maps(ls):
- for km_name, km_space_type, km_region_type, km_sub in ls:
+ def fill_maps(seq):
+ for km_name, km_space_type, km_region_type, km_sub in seq:
maps[km_name] = (km_space_type, km_region_type)
fill_maps(km_sub)
- fill_maps(keyconfig_utils.KM_HIERARCHY)
+ fill_maps(keymap_hierarchy.generate())
import bpy
keyconf = bpy.context.window_manager.keyconfigs.active
@@ -43,14 +48,14 @@ def check_maps():
# Check keyconfig contains only maps that exist in blender
test = maps_py - maps_bl
if test:
- print("Keymaps that are in 'keyconfig_utils' but not blender")
+ print("Keymaps that are in 'bl_keymap_utils.keymap_hierarchy' but not blender")
for km_id in sorted(test):
print("\t%s" % km_id)
err = True
test = maps_bl - maps_py
if test:
- print("Keymaps that are in blender but not in 'keyconfig_utils'")
+ print("Keymaps that are in blender but not in 'bl_keymap_utils.keymap_hierarchy'")
for km_id in sorted(test):
km = keyconf.keymaps[km_id]
print(" ('%s', '%s', '%s', [])," % (km_id, km.space_type, km.region_type))
diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py
index 16ddea24756..d54d5c3c45f 100644
--- a/tests/python/bl_load_addons.py
+++ b/tests/python/bl_load_addons.py
@@ -64,7 +64,7 @@ def addon_modules_sorted():
def disable_addons():
# first disable all
- addons = bpy.context.user_preferences.addons
+ addons = bpy.context.preferences.addons
for mod_name in list(addons.keys()):
addon_utils.disable(mod_name, default_set=True)
assert(bool(addons) is False)
@@ -75,7 +75,7 @@ def test_load_addons():
disable_addons()
- addons = bpy.context.user_preferences.addons
+ addons = bpy.context.preferences.addons
addons_fail = []
@@ -97,12 +97,12 @@ def test_load_addons():
def reload_addons(do_reload=True, do_reverse=True):
modules = addon_modules_sorted()
- addons = bpy.context.user_preferences.addons
+ addons = bpy.context.preferences.addons
disable_addons()
# Run twice each time.
- for i in (0, 1):
+ for _ in (0, 1):
for mod in modules:
mod_name = mod.__name__
print("\tenabling:", mod_name)
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 437a425a36d..be7f426d993 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -104,7 +104,7 @@ def source_list(path, filename_check=None):
def load_addons():
modules = addon_modules_sorted()
- addons = bpy.context.user_preferences.addons
+ addons = bpy.context.preferences.addons
# first disable all
for mod_name in list(addons.keys()):
@@ -197,7 +197,7 @@ def load_modules():
assert(os.path.samefile(mod_imp.__file__, submod_full))
modules.append(mod_imp)
- except Exception as e:
+ except Exception:
import traceback
# Module might fail to import, but we don't want whole test to fail here.
# Reasoning:
diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py
index 619fdc77801..74eaaeb7c68 100644
--- a/tests/python/bl_mesh_modifiers.py
+++ b/tests/python/bl_mesh_modifiers.py
@@ -38,12 +38,12 @@ USE_QUICK_RENDER = False
def render_gl(context, filepath, shade):
- def ctx_viewport_shade(context, shade):
+ def ctx_shading_type(context, shade):
for area in context.window.screen.areas:
if area.type == 'VIEW_3D':
space = area.spaces.active
# rv3d = space.region_3d
- space.viewport_shade = shade
+ space.shading.type = shade
import bpy
scene = context.scene
@@ -59,7 +59,7 @@ def render_gl(context, filepath, shade):
render.resolution_x = 512
render.resolution_y = 512
- ctx_viewport_shade(context, shade)
+ ctx_shading_type(context, shade)
# stop to inspect!
# if filepath == "test_cube_shell_solidify_subsurf_wp_wire":
@@ -127,7 +127,7 @@ def ctx_clear_scene(): # copied from batch_import.py
# 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.lights,
bpy.data.cameras,
):
@@ -249,7 +249,7 @@ def mesh_uv_add(obj):
(1.0, 1.0),
(1.0, 0.0))
- uv_lay = obj.data.uv_textures.new()
+ uv_lay = obj.data.uv_layers.new()
# XXX, odd that we need to do this. until UV's and texface
# are separated we will need to keep it
@@ -370,7 +370,7 @@ def modifier_armature_add(scene, obj):
scene.objects.active = obj
# display options
- obj_arm.show_x_ray = True
+ obj_arm.show_in_front = True
arm_data.draw_type = 'STICK'
# apply to modifier
@@ -425,7 +425,7 @@ def modifier_hook_add(scene, obj, use_vgroup=True):
obj_hook = mod.object
obj_hook.rotation_euler = 0, math.radians(45), 0
- obj_hook.show_x_ray = True
+ obj_hook.show_in_front = True
if use_vgroup:
mod.vertex_group = obj.vertex_groups[0].name
diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py
index e1dd097b2e0..47a5e5efe47 100644
--- a/tests/python/bl_mesh_validate.py
+++ b/tests/python/bl_mesh_validate.py
@@ -114,7 +114,7 @@ def test_builtins():
getattr(bpy.ops.mesh, func)(location=(x * 2.5, y * 2.5, 0))
data = bpy.context.active_object.data
try:
- for n in range(BUILTINS_NBRCHANGES):
+ for _ in range(BUILTINS_NBRCHANGES):
rnd = random.randint(1, 3)
if rnd == 1:
# Make fun with some edge.
diff --git a/tests/python/bl_pyapi_idprop.py b/tests/python/bl_pyapi_idprop.py
index 063d68fae20..3d0cbd2a7bb 100644
--- a/tests/python/bl_pyapi_idprop.py
+++ b/tests/python/bl_pyapi_idprop.py
@@ -15,11 +15,12 @@ class TestHelper:
def setUp(self):
self._id = bpy.context.scene
- assert(len(self._id.keys()) == 0)
+ assert(len(self._id.keys()) == 0 or self._id.keys() == ["cycles"])
def tearDown(self):
for key in list(self._id.keys()):
- del self._id[key]
+ if key != "cycles":
+ del self._id[key]
def assertAlmostEqualSeq(self, list1, list2):
self.assertEqual(len(list1), len(list2))
diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py
index 4b46bea7c00..8ff597dda31 100644
--- a/tests/python/bl_pyapi_idprop_datablock.py
+++ b/tests/python/bl_pyapi_idprop_datablock.py
@@ -90,10 +90,10 @@ def make_lib():
# datablock pointer to the Camera object
bpy.data.objects["Cube"].prop = bpy.data.objects['Camera']
- # array of datablock pointers to the Lamp object
+ # array of datablock pointers to the Light object
for i in range(0, arr_len):
a = bpy.data.objects["Cube"].prop_array.add()
- a.test_prop = bpy.data.objects['Lamp']
+ a.test_prop = bpy.data.objects['Light']
a.name = a.test_prop.name
# make unique named copy of the cube
@@ -124,7 +124,7 @@ def check_lib():
# 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['Lamp'])
+ bpy.data.objects['Light'])
def check_lib_linking():
@@ -137,7 +137,7 @@ 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['Lamp'])
+ 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)
@@ -187,15 +187,15 @@ def check_scene_copying():
# count users
def test_users_counting():
bpy.ops.wm.read_factory_settings()
- lamp_us = bpy.data.objects["Lamp"].data.users
+ Light_us = bpy.data.objects["Light"].data.users
n = 1000
for i in range(0, n):
- bpy.data.objects["Cube"]["a%s" % i] = bpy.data.objects["Lamp"].data
- abort_if_false(bpy.data.objects["Lamp"].data.users == lamp_us + 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)
for i in range(0, int(n / 2)):
bpy.data.objects["Cube"]["a%s" % i] = 1
- abort_if_false(bpy.data.objects["Lamp"].data.users == lamp_us + int(n / 2))
+ abort_if_false(bpy.data.objects["Light"].data.users == Light_us + int(n / 2))
# linking
@@ -259,13 +259,13 @@ def test_restrictions1():
bpy.types.Scene.prop2 = bpy.props.PointerProperty(type=bpy.types.NodeTree, poll=poll1)
# check poll effect on UI (poll returns false => red alert)
- bpy.context.scene.prop = bpy.data.objects["Lamp.001"]
- bpy.context.scene.prop1 = bpy.data.objects["Lamp.001"]
+ bpy.context.scene.prop = bpy.data.objects["Light.001"]
+ bpy.context.scene.prop1 = bpy.data.objects["Light.001"]
# check incorrect type assignment
def sub_test():
# NodeTree id_prop
- bpy.context.scene.prop2 = bpy.data.objects["Lamp.001"]
+ bpy.context.scene.prop2 = bpy.data.objects["Light.001"]
check_crash(sub_test)
diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py
index 57bbbc7e73e..5aa95f9a5f7 100644
--- a/tests/python/bl_pyapi_mathutils.py
+++ b/tests/python/bl_pyapi_mathutils.py
@@ -104,7 +104,7 @@ class MatrixTesting(unittest.TestCase):
self.assertEqual(mat[1][3], 2)
self.assertEqual(mat[2][3], 3)
- def test_non_square_mult(self):
+ def test_matrix_non_square_matmul(self):
mat1 = Matrix(((1, 2, 3),
(4, 5, 6)))
mat2 = Matrix(((1, 2),
@@ -117,10 +117,10 @@ class MatrixTesting(unittest.TestCase):
(19, 26, 33),
(29, 40, 51)))
- self.assertEqual(mat1 * mat2, prod_mat1)
- self.assertEqual(mat2 * mat1, prod_mat2)
+ self.assertEqual(mat1 @ mat2, prod_mat1)
+ self.assertEqual(mat2 @ mat1, prod_mat2)
- def test_mat4x4_vec3D_mult(self):
+ def test_mat4x4_vec3D_matmul(self):
mat = Matrix(((1, 0, 2, 0),
(0, 6, 0, 0),
(0, 0, 1, 1),
@@ -131,23 +131,58 @@ class MatrixTesting(unittest.TestCase):
prod_mat_vec = Vector((7, 12, 4))
prod_vec_mat = Vector((1, 12, 5))
- self.assertEqual(mat * vec, prod_mat_vec)
- self.assertEqual(vec * mat, prod_vec_mat)
+ self.assertEqual(mat @ vec, prod_mat_vec)
+ self.assertEqual(vec @ mat, prod_vec_mat)
- def test_mat_vec_mult(self):
+ def test_mat_vec_matmul(self):
mat1 = Matrix()
vec = Vector((1, 2))
- self.assertRaises(ValueError, mat1.__mul__, vec)
- self.assertRaises(ValueError, vec.__mul__, mat1)
+ self.assertRaises(ValueError, mat1.__matmul__, vec)
+ self.assertRaises(ValueError, vec.__matmul__, mat1)
mat2 = Matrix(((1, 2),
(-2, 3)))
prod = Vector((5, 4))
- self.assertEqual(mat2 * vec, prod)
+ self.assertEqual(mat2 @ vec, prod)
+
+ def test_matrix_square_matmul(self):
+ mat1 = Matrix(((1, 0),
+ (1, 2)))
+ mat2 = Matrix(((1, 2),
+ (-2, 3)))
+
+ prod1 = Matrix(((1, 2),
+ (-3, 8)))
+ prod2 = Matrix(((3, 4),
+ (1, 6)))
+
+ self.assertEqual(mat1 @ mat2, prod1)
+ self.assertEqual(mat2 @ mat1, prod2)
+
+ """
+ # tests for element-wise multiplication
+
+ def test_matrix_mul(self):
+ mat1 = Matrix(((1, 0),
+ (1, 2)))
+ mat2 = Matrix(((1, 2),
+ (-2, 3)))
+ mat3 = Matrix(((1, 0, 2, 0),
+ (0, 6, 0, 0),
+ (0, 0, 1, 1),
+ (0, 0, 0, 1)))
+
+ prod = Matrix(((1, 0),
+ (-2, 6)))
+
+ self.assertEqual(mat1 * mat2, prod)
+ self.assertEqual(mat2 * mat1, prod)
+ self.assertRaises(ValueError, mat1.__mul__, mat3)
+ """
def test_matrix_inverse(self):
mat = Matrix(((1, 4, 0, -1),
@@ -185,7 +220,7 @@ class MatrixTesting(unittest.TestCase):
self.assertEqual(mat.inverted_safe(), inv_mat_safe)
- def test_matrix_mult(self):
+ def test_matrix_matmult(self):
mat = Matrix(((1, 4, 0, -1),
(2, -1, 2, -2),
(0, 3, 8, 3),
@@ -196,7 +231,7 @@ class MatrixTesting(unittest.TestCase):
(0, 48, 73, 18),
(16, -14, 26, -13)))
- self.assertEqual(mat * mat, prod_mat)
+ self.assertEqual(mat @ mat, prod_mat)
class VectorTesting(unittest.TestCase):
@@ -209,6 +244,49 @@ class VectorTesting(unittest.TestCase):
if v.length_squared != 0.0:
self.assertAlmostEqual(v.angle(v.orthogonal()), angle_90d)
+ def test_vector_matmul(self):
+ # produces dot product for vectors
+ vec1 = Vector((1, 3, 5))
+ vec2 = Vector((1, 2))
+
+ self.assertRaises(ValueError, vec1.__matmul__, vec2)
+ self.assertEqual(vec1 @ vec1, 35)
+ self.assertEqual(vec2 @ vec2, 5)
+
+ def test_vector_imatmul(self):
+ vec = Vector((1, 3, 5))
+
+ with self.assertRaises(TypeError):
+ vec @= vec
+
+ """
+ # tests for element-wise multiplication
+
+ def test_vector_mul(self):
+ # element-wise multiplication
+ vec1 = Vector((1, 3, 5))
+ vec2 = Vector((1, 2))
+
+ prod1 = Vector((1, 9, 25))
+ prod2 = Vector((2, 6, 10))
+
+ self.assertRaises(ValueError, vec1.__mul__, vec2)
+ self.assertEqual(vec1 * vec1, prod1)
+ self.assertEqual(2 * vec1, prod2)
+
+ def test_vector_imul(self):
+ # inplace element-wise multiplication
+ vec = Vector((1, 3, 5))
+ prod1 = Vector((1, 9, 25))
+ prod2 = Vector((2, 18, 50))
+
+ vec *= vec
+ self.assertEqual(vec, prod1)
+
+ vec *= 2
+ self.assertEqual(vec, prod2)
+ """
+
class QuaternionTesting(unittest.TestCase):
diff --git a/tests/python/bl_rna_defaults.py b/tests/python/bl_rna_defaults.py
index 6038ef34d78..fc895dbddfc 100644
--- a/tests/python/bl_rna_defaults.py
+++ b/tests/python/bl_rna_defaults.py
@@ -125,8 +125,8 @@ test_World = _test_id_gen("worlds")
ns = globals()
for t in bpy.data.curves.bl_rna.functions["new"].parameters["type"].enum_items.keys():
ns["test_Curve_%s" % t] = _test_id_gen("curves", args_create=(DUMMY_NAME, t))
-for t in bpy.data.lamps.bl_rna.functions["new"].parameters["type"].enum_items.keys():
- ns["test_Lamp_%s" % t] = _test_id_gen("lamps", args_create=(DUMMY_NAME, t))
+for t in bpy.data.lights.bl_rna.functions["new"].parameters["type"].enum_items.keys():
+ ns["test_Light_%s" % t] = _test_id_gen("lights", args_create=(DUMMY_NAME, t))
# types are a dynamic enum, have to hard-code.
for t in "ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree":
ns["test_NodeGroup_%s" % t] = _test_id_gen("node_groups", args_create=(DUMMY_NAME, t))
diff --git a/tests/python/bl_rst_completeness.py b/tests/python/bl_rst_completeness.py
index d8dfac66d13..3266621c43b 100644
--- a/tests/python/bl_rst_completeness.py
+++ b/tests/python/bl_rst_completeness.py
@@ -21,8 +21,6 @@
# run this script in the game engine.
# or on the command line with...
# ./blender.bin --background -noaudio --python tests/python/bl_rst_completeness.py
-
-# Paste this into the bge and run on an always actuator.
'''
filepath = "/src/blender/tests/python/bl_rst_completeness.py"
exec(compile(open(filepath).read(), filepath, 'exec'))
@@ -38,20 +36,9 @@ sys.path.append(THIS_DIR)
import rst_to_doctree_mini
-try:
- import bge
-except:
- bge = None
# (file, module)
modules = (
- ("bge.constraints.rst", "bge.constraints", False),
- ("bge.events.rst", "bge.events", False),
- ("bge.logic.rst", "bge.logic", False),
- ("bge.render.rst", "bge.render", False),
- ("bge.texture.rst", "bge.texture", False),
- ("bge.types.rst", "bge.types", False),
-
("bgl.rst", "bgl", True),
("gpu.rst", "gpu", False),
)
@@ -137,13 +124,7 @@ def module_validate(filepath, mod, mod_name, doctree, partial_ok):
def main():
- if bge is None:
- print("Skipping BGE modules!")
-
for filename, modname, partial_ok in modules:
- if bge is None and modname.startswith("bge"):
- continue
-
filepath = os.path.join(RST_DIR, filename)
if not os.path.exists(filepath):
raise Exception("%r not found" % filepath)
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index 9a3f801b04a..5954f7d9381 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -81,7 +81,6 @@ op_blacklist = (
"wm.operator_cheat_sheet",
"wm.interface_theme_*",
"wm.previews_ensure", # slow - but harmless
- "wm.appconfig_*", # just annoying - but harmless
"wm.keyitem_add", # just annoying - but harmless
"wm.keyconfig_activate", # just annoying - but harmless
"wm.keyconfig_preset_add", # just annoying - but harmless
@@ -142,7 +141,7 @@ def reset_blend():
if USE_RANDOM_SCREEN:
import random
- for i in range(random.randint(0, len(bpy.data.screens))):
+ for _ in range(random.randint(0, len(bpy.data.screens))):
bpy.ops.screen.delete()
print("Scree IS", bpy.context.screen)
@@ -238,7 +237,7 @@ if USE_ATTRSET:
seq = getattr(bpy.data, attr)
if seq.__class__.__name__ == 'bpy_prop_collection':
for id_data in seq:
- for val, prop, tp in id_walk(id_data, bpy.data):
+ for val, prop, _tp in id_walk(id_data, bpy.data):
# print(id_data)
for val_rnd in _random_values:
try:
diff --git a/tests/python/collada/CMakeLists.txt b/tests/python/collada/CMakeLists.txt
index 4307eec3791..66d72611b63 100644
--- a/tests/python/collada/CMakeLists.txt
+++ b/tests/python/collada/CMakeLists.txt
@@ -13,9 +13,6 @@
# 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.
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index 1717210663a..381c04d9b7f 100755
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -56,6 +56,7 @@ def render_file(filepath, output_filepath):
shutil.copy(frame_filepath, output_filepath)
os.remove(frame_filepath)
if VERBOSE:
+ print(" ".join(command))
print(output.decode("utf-8"))
return None
except subprocess.CalledProcessError as e:
@@ -63,6 +64,7 @@ def render_file(filepath, output_filepath):
if os.path.exists(frame_filepath):
os.remove(frame_filepath)
if VERBOSE:
+ print(" ".join(command))
print(e.output.decode("utf-8"))
if b"Error: engine not found" in e.output:
return "NO_ENGINE"
@@ -74,6 +76,7 @@ def render_file(filepath, output_filepath):
if os.path.exists(frame_filepath):
os.remove(frame_filepath)
if VERBOSE:
+ print(" ".join(command))
print(e)
return "CRASH"
@@ -103,6 +106,7 @@ def main():
from modules import render_report
report = render_report.Report("Cycles Test Report", output_dir, idiff)
report.set_pixelated(True)
+ report.set_compare_engines('cycles', 'eevee')
ok = report.run(test_dir, render_file)
sys.exit(not ok)
diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py
new file mode 100755
index 00000000000..48751e6bbcb
--- /dev/null
+++ b/tests/python/eevee_render_tests.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# Apache License, Version 2.0
+
+import argparse
+import os
+import shlex
+import shutil
+import subprocess
+import sys
+
+
+def setup():
+ import bpy
+
+ # Enable Eevee features
+ scene = bpy.context.scene
+ eevee = scene.eevee
+
+ eevee.use_sss = True
+ eevee.use_ssr = True
+ eevee.use_ssr_refraction = True
+ eevee.use_gtao = True
+ eevee.use_dof = True
+
+ eevee.use_volumetric = True
+ eevee.use_volumetric_shadows = True
+ eevee.volumetric_tile_size = '2'
+
+ for mat in bpy.data.materials:
+ mat.use_screen_refraction = True
+ mat.use_screen_subsurface = True
+
+
+# When run from inside Blender, render and exit.
+try:
+ import bpy
+ inside_blender = True
+except ImportError:
+ inside_blender = False
+
+if inside_blender:
+ try:
+ setup()
+ except Exception as e:
+ print(e)
+ sys.exit(1)
+
+
+def render_file(filepath, output_filepath):
+ dirname = os.path.dirname(filepath)
+ basedir = os.path.dirname(dirname)
+ subject = os.path.basename(dirname)
+
+ frame_filepath = output_filepath + '0001.png'
+
+ command = [
+ BLENDER,
+ "--background",
+ "-noaudio",
+ "--factory-startup",
+ "--enable-autoexec",
+ filepath,
+ "-E", "BLENDER_EEVEE",
+ "-P",
+ os.path.realpath(__file__),
+ "-o", output_filepath,
+ "-F", "PNG",
+ "-f", "1"]
+
+ try:
+ # Success
+ output = subprocess.check_output(command)
+ if os.path.exists(frame_filepath):
+ shutil.copy(frame_filepath, output_filepath)
+ os.remove(frame_filepath)
+ if VERBOSE:
+ print(" ".join(command))
+ print(output.decode("utf-8"))
+ return None
+ except subprocess.CalledProcessError as e:
+ # Error
+ if os.path.exists(frame_filepath):
+ os.remove(frame_filepath)
+ if VERBOSE:
+ print(" ".join(command))
+ print(e.output.decode("utf-8"))
+ if b"Error: engine not found" in e.output:
+ return "NO_ENGINE"
+ elif b"blender probably wont start" in e.output:
+ return "NO_START"
+ return "CRASH"
+ except BaseException as e:
+ # Crash
+ if os.path.exists(frame_filepath):
+ os.remove(frame_filepath)
+ if VERBOSE:
+ print(" ".join(command))
+ print(e)
+ return "CRASH"
+
+
+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()
+
+ global BLENDER, VERBOSE
+
+ BLENDER = args.blender[0]
+ VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None
+
+ test_dir = args.testdir[0]
+ idiff = args.idiff[0]
+ output_dir = args.outdir[0]
+
+ from modules import render_report
+ report = render_report.Report("Eevee Test Report", output_dir, idiff)
+ report.set_pixelated(True)
+ report.set_reference_dir("eevee_renders")
+ report.set_compare_engines('eevee', 'cycles')
+ ok = report.run(test_dir, render_file)
+
+ sys.exit(not ok)
+
+
+if not inside_blender and __name__ == "__main__":
+ main()
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index 70677677667..d6e7127c35a 100755
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -20,12 +20,8 @@
# <pep8 compliant>
import argparse
-import functools
-import shutil
import pathlib
-import subprocess
import sys
-import tempfile
import unittest
from modules.test_utils import AbstractBlenderRunnerTest
@@ -46,15 +42,29 @@ class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
"bpy.context.scene.sequence_editor_create(); " \
"strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \
"'test_movie', %r, channel=1, frame_start=1); " \
- "print(f'fps:{strip.fps}')" % movie.as_posix()
+ "print(f'fps:{strip.fps}'); " \
+ "print(f'duration:{strip.frame_final_duration}'); " % movie.as_posix()
- def get_movie_file_fps(self, filename: pathlib.Path) -> float:
+ def get_movie_file_field(self, filename: pathlib.Path, field: str) -> str:
script = self.get_script_for_file(filename)
output = self.run_blender('', script)
+ prefix = field + ":"
for line in output.splitlines():
- if line.startswith('fps:'):
- return float(line.split(':')[1])
- return 0.0
+ if line.startswith(prefix):
+ return line.split(':')[1]
+ return ""
+
+ def get_movie_file_field_float(self, filename: pathlib.Path, field: str) -> float:
+ return float(self.get_movie_file_field(filename, field))
+
+ def get_movie_file_field_int(self, filename: pathlib.Path, field: str) -> float:
+ return int(self.get_movie_file_field(filename, field))
+
+ def get_movie_file_fps(self, filename: pathlib.Path) -> float:
+ return self.get_movie_file_field_float(filename, "fps")
+
+ def get_movie_file_duration(self, filename: pathlib.Path) -> float:
+ return self.get_movie_file_field_int(filename, "duration")
class FPSDetectionTest(AbstractFFmpegSequencerTest):
@@ -76,6 +86,11 @@ class FPSDetectionTest(AbstractFFmpegSequencerTest):
1.0,
places=2)
+ def test_T54834(self):
+ self.assertEqual(
+ self.get_movie_file_duration('T54834.ogg'),
+ 50)
+
if __name__ == '__main__':
parser = argparse.ArgumentParser()
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index ed46abb4b63..9cff85f3dfa 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -63,11 +63,11 @@ def test_get_name(filepath):
return os.path.splitext(filename)[0]
-def test_get_images(output_dir, filepath):
+def test_get_images(output_dir, filepath, reference_dir):
testname = test_get_name(filepath)
dirpath = os.path.dirname(filepath)
- old_dirpath = os.path.join(dirpath, "reference_renders")
+ old_dirpath = os.path.join(dirpath, reference_dir)
old_img = os.path.join(old_dirpath, testname + ".png")
ref_dirpath = os.path.join(output_dir, os.path.basename(dirpath), "ref")
@@ -94,18 +94,23 @@ class Report:
__slots__ = (
'title',
'output_dir',
+ 'reference_dir',
'idiff',
'pixelated',
'verbose',
'update',
'failed_tests',
- 'passed_tests'
+ 'passed_tests',
+ 'compare_tests',
+ 'compare_engines'
)
def __init__(self, title, output_dir, idiff):
self.title = title
self.output_dir = output_dir
+ self.reference_dir = 'reference_renders'
self.idiff = idiff
+ self.compare_engines = None
self.pixelated = False
self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
@@ -117,6 +122,7 @@ class Report:
self.failed_tests = ""
self.passed_tests = ""
+ self.compare_tests = ""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
@@ -124,14 +130,23 @@ class Report:
def set_pixelated(self, pixelated):
self.pixelated = pixelated
+ def set_reference_dir(self, reference_dir):
+ self.reference_dir = reference_dir
+
+ def set_compare_engines(self, engine, other_engine):
+ self.compare_engines = (engine, other_engine)
+
def run(self, dirpath, render_cb):
# Run tests and output report.
dirname = os.path.basename(dirpath)
ok = self._run_all_tests(dirname, dirpath, render_cb)
- self._write_html(dirname)
+ self._write_data(dirname)
+ self._write_html()
+ if self.compare_engines:
+ self._write_html(comparison=True)
return ok
- def _write_html(self, dirname):
+ def _write_data(self, dirname):
# Write intermediate data for single test.
outdir = os.path.join(self.output_dir, dirname)
if not os.path.exists(outdir):
@@ -143,9 +158,18 @@ class Report:
filepath = os.path.join(outdir, "passed.data")
pathlib.Path(filepath).write_text(self.passed_tests)
+ if self.compare_engines:
+ filepath = os.path.join(outdir, "compare.data")
+ pathlib.Path(filepath).write_text(self.compare_tests)
+
+ def _write_html(self, comparison=False):
# Gather intermediate data for all tests.
- failed_data = sorted(glob.glob(os.path.join(self.output_dir, "*/failed.data")))
- passed_data = sorted(glob.glob(os.path.join(self.output_dir, "*/passed.data")))
+ if comparison:
+ failed_data = []
+ passed_data = sorted(glob.glob(os.path.join(self.output_dir, "*/compare.data")))
+ else:
+ failed_data = sorted(glob.glob(os.path.join(self.output_dir, "*/failed.data")))
+ passed_data = sorted(glob.glob(os.path.join(self.output_dir, "*/passed.data")))
failed_tests = ""
passed_tests = ""
@@ -170,6 +194,13 @@ class Report:
else:
message = ""
+ if comparison:
+ title = "Render Test Compare"
+ columns_html = "<tr><th>Name</th><th>%s</th><th>%s</th>" % self.compare_engines
+ else:
+ title = self.title
+ columns_html = "<tr><th>Name</th><th>New</th><th>Reference</th><th>Diff</th>"
+
html = """
<html>
<head>
@@ -207,7 +238,7 @@ class Report:
<br/>
<table class="table table-striped">
<thead class="thead-default">
- <tr><th>Name</th><th>New</th><th>Reference</th><th>Diff</th>
+ {columns_html}
</thead>
{tests_html}
</table>
@@ -215,12 +246,14 @@ class Report:
</div>
</body>
</html>
- """ . format(title=self.title,
+ """ . format(title=title,
message=message,
image_rendering=image_rendering,
- tests_html=tests_html)
+ tests_html=tests_html,
+ columns_html=columns_html)
- filepath = os.path.join(self.output_dir, "report.html")
+ filename = "report.html" if not comparison else "compare.html"
+ filepath = os.path.join(self.output_dir, filename)
pathlib.Path(filepath).write_text(html)
print_message("Report saved to: " + pathlib.Path(filepath).as_uri())
@@ -233,7 +266,7 @@ class Report:
name = test_get_name(filepath)
name = name.replace('_', ' ')
- old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath)
+ old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir)
status = error if error else ""
tr_style = """ style="background-color: #f99;" """ if error else ""
@@ -261,8 +294,25 @@ class Report:
else:
self.passed_tests += test_html
+ if self.compare_engines:
+ ref_url = os.path.join("..", self.compare_engines[1], new_url)
+
+ test_html = """
+ <tr{tr_style}>
+ <td><b>{name}</b><br/>{testname}<br/>{status}</td>
+ <td><img src="{new_url}" onmouseover="this.src='{ref_url}';" onmouseout="this.src='{new_url}';" class="render"></td>
+ <td><img src="{ref_url}" onmouseover="this.src='{new_url}';" onmouseout="this.src='{ref_url}';" class="render"></td>
+ </tr>""" . format(tr_style=tr_style,
+ name=name,
+ testname=testname,
+ status=status,
+ new_url=new_url,
+ ref_url=ref_url)
+
+ self.compare_tests += test_html
+
def _diff_output(self, filepath, tmp_filepath):
- old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath)
+ old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir)
# Create reference render directory.
old_dirpath = os.path.dirname(old_img)
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index 47d720684ba..46c1626493f 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -19,13 +19,10 @@
# <pep8 compliant>
-import argparse
import functools
import shutil
import pathlib
-import re
import subprocess
-import sys
import tempfile
import unittest
diff --git a/tests/python/opengl_draw_tests.py b/tests/python/opengl_draw_tests.py
index b6c18e289bc..9913f875689 100755
--- a/tests/python/opengl_draw_tests.py
+++ b/tests/python/opengl_draw_tests.py
@@ -3,8 +3,6 @@
import argparse
import os
-import shlex
-import shutil
import subprocess
import sys
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index ccc2dddbbd9..fde86892782 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -45,7 +45,7 @@ FORCE_PEP8_ALL = False
def file_list_py(path):
- for dirpath, dirnames, filenames in os.walk(path):
+ for dirpath, _dirnames, filenames in os.walk(path):
for filename in filenames:
if filename.endswith((".py", ".cfg")):
yield os.path.join(dirpath, filename)
@@ -62,7 +62,7 @@ def is_pep8(path):
return 1
f = open(path, 'r', encoding="utf8")
- for i in range(PEP8_SEEK_COMMENT):
+ for _ in range(PEP8_SEEK_COMMENT):
line = f.readline()
if line.startswith("# <pep8"):
if line.startswith("# <pep8 compliant>"):
diff --git a/tests/python/rna_info_dump.py b/tests/python/rna_info_dump.py
index da228e52652..01cbe8d290b 100644
--- a/tests/python/rna_info_dump.py
+++ b/tests/python/rna_info_dump.py
@@ -71,7 +71,7 @@ def api_dump(use_properties=True, use_functions=True):
def dump_funcs():
data = []
- for struct_id, v in sorted(struct.items()):
+ for _struct_id, v in sorted(struct.items()):
struct_id_str = struct_full_id(v)
funcs = [(func.identifier, func) for func in v.functions]
@@ -90,7 +90,7 @@ def api_dump(use_properties=True, use_functions=True):
def dump_props():
data = []
- for struct_id, v in sorted(struct.items()):
+ for _struct_id, v in sorted(struct.items()):
struct_id_str = struct_full_id(v)
props = [(prop.identifier, prop) for prop in v.properties]
diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt
new file mode 100644
index 00000000000..54eb29a7454
--- /dev/null
+++ b/tests/python/view_layer/CMakeLists.txt
@@ -0,0 +1,185 @@
+# ***** 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 *****
+
+# --env-system-scripts allows to run without the install target.
+
+# Use '--write-blend=/tmp/test.blend' to view output
+
+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 ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
+
+
+# ------------------------------------------------------------------------------
+
+macro(VIEW_LAYER_TEST test_name)
+ # Adds ${CMAKE_CURRENT_LIST_DIR} to sys.path so that the tests can import
+ # things from view_layer_common.py
+ add_test(view_layer_${test_name} ${TEST_BLENDER_EXE}
+ --python-expr "import sys; sys.path.append('${CMAKE_CURRENT_LIST_DIR}')"
+ --python-exit-code 1
+ --python ${CMAKE_CURRENT_LIST_DIR}/test_${test_name}.py --
+ --testdir="${TEST_SRC_DIR}/layers"
+ )
+endmacro()
+
+VIEW_LAYER_TEST(active_collection)
+VIEW_LAYER_TEST(background_set)
+VIEW_LAYER_TEST(collection_new_sync)
+VIEW_LAYER_TEST(collection_rename_a)
+VIEW_LAYER_TEST(collection_rename_b)
+#VIEW_LAYER_TEST(evaluation_render_settings_a)
+#VIEW_LAYER_TEST(evaluation_render_settings_b)
+#VIEW_LAYER_TEST(evaluation_render_settings_c)
+#VIEW_LAYER_TEST(evaluation_render_settings_d)
+#VIEW_LAYER_TEST(evaluation_render_settings_e)
+#VIEW_LAYER_TEST(evaluation_render_settings_f)
+#VIEW_LAYER_TEST(evaluation_render_settings_g)
+#VIEW_LAYER_TEST(evaluation_render_settings_h)
+#VIEW_LAYER_TEST(evaluation_render_settings_i)
+VIEW_LAYER_TEST(evaluation_visibility_a)
+VIEW_LAYER_TEST(evaluation_visibility_b)
+VIEW_LAYER_TEST(evaluation_visibility_c)
+VIEW_LAYER_TEST(evaluation_visibility_d)
+VIEW_LAYER_TEST(evaluation_visibility_e)
+VIEW_LAYER_TEST(evaluation_visibility_f)
+VIEW_LAYER_TEST(evaluation_visibility_g)
+VIEW_LAYER_TEST(evaluation_visibility_h)
+VIEW_LAYER_TEST(evaluation_visibility_i)
+VIEW_LAYER_TEST(evaluation_visibility_j)
+VIEW_LAYER_TEST(evaluation_selectability_a)
+VIEW_LAYER_TEST(evaluation_selectability_b)
+VIEW_LAYER_TEST(evaluation_selectability_c)
+VIEW_LAYER_TEST(evaluation_selectability_d)
+VIEW_LAYER_TEST(evaluation_selectability_e)
+VIEW_LAYER_TEST(evaluation_selectability_f)
+VIEW_LAYER_TEST(group_a)
+VIEW_LAYER_TEST(group_b)
+VIEW_LAYER_TEST(group_c)
+VIEW_LAYER_TEST(group_d)
+VIEW_LAYER_TEST(group_e)
+VIEW_LAYER_TEST(object_add_cylinder)
+VIEW_LAYER_TEST(object_add_empty)
+VIEW_LAYER_TEST(object_add_torus)
+VIEW_LAYER_TEST(object_add_no_collection_cylinder)
+VIEW_LAYER_TEST(object_add_no_collection_empty)
+VIEW_LAYER_TEST(object_add_no_collection_torus)
+VIEW_LAYER_TEST(object_copy)
+VIEW_LAYER_TEST(object_delete_a)
+VIEW_LAYER_TEST(object_delete_b)
+VIEW_LAYER_TEST(object_link_a)
+VIEW_LAYER_TEST(object_link_b)
+VIEW_LAYER_TEST(object_link_c)
+VIEW_LAYER_TEST(operator_context)
+VIEW_LAYER_TEST(make_single_user)
+VIEW_LAYER_TEST(move_above_below_scene_collection_a)
+VIEW_LAYER_TEST(move_above_below_scene_collection_b)
+VIEW_LAYER_TEST(move_above_below_scene_collection_c)
+VIEW_LAYER_TEST(move_above_below_scene_collection_d)
+VIEW_LAYER_TEST(move_above_below_scene_collection_e)
+VIEW_LAYER_TEST(move_above_below_scene_collection_f)
+VIEW_LAYER_TEST(move_above_below_scene_collection_g)
+VIEW_LAYER_TEST(move_above_below_scene_collection_h)
+VIEW_LAYER_TEST(move_above_below_scene_collection_i)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_a)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_b)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_c)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_d)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_e)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_f)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_g)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_h)
+VIEW_LAYER_TEST(move_above_below_scene_collection_sync_i)
+VIEW_LAYER_TEST(move_into_scene_collection_a)
+VIEW_LAYER_TEST(move_into_scene_collection_b)
+VIEW_LAYER_TEST(move_into_scene_collection_c)
+VIEW_LAYER_TEST(move_into_scene_collection_d)
+VIEW_LAYER_TEST(move_into_scene_collection_e)
+VIEW_LAYER_TEST(move_into_scene_collection_f)
+VIEW_LAYER_TEST(move_into_scene_collection_g)
+VIEW_LAYER_TEST(move_into_scene_collection_h)
+VIEW_LAYER_TEST(move_into_scene_collection_i)
+VIEW_LAYER_TEST(move_into_scene_collection_j)
+VIEW_LAYER_TEST(move_into_scene_collection_k)
+VIEW_LAYER_TEST(move_into_scene_collection_l)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_a)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_b)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_c)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_d)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_e)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_f)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_g)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_h)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_i)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_j)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_k)
+VIEW_LAYER_TEST(move_into_scene_collection_sync_l)
+VIEW_LAYER_TEST(move_above_below_layer_collection_a)
+VIEW_LAYER_TEST(move_above_below_layer_collection_b)
+VIEW_LAYER_TEST(move_above_below_layer_collection_c)
+VIEW_LAYER_TEST(move_above_below_layer_collection_d)
+VIEW_LAYER_TEST(move_above_below_layer_collection_e)
+VIEW_LAYER_TEST(move_above_below_layer_collection_f)
+VIEW_LAYER_TEST(move_above_below_layer_collection_g)
+VIEW_LAYER_TEST(move_above_below_layer_collection_h)
+VIEW_LAYER_TEST(move_above_below_layer_collection_i)
+VIEW_LAYER_TEST(move_above_below_layer_collection_j)
+VIEW_LAYER_TEST(move_above_below_layer_collection_k)
+VIEW_LAYER_TEST(move_above_below_layer_collection_l)
+VIEW_LAYER_TEST(move_into_layer_collection_a)
+VIEW_LAYER_TEST(move_into_layer_collection_b)
+VIEW_LAYER_TEST(move_into_layer_collection_c)
+VIEW_LAYER_TEST(move_into_layer_collection_d)
+VIEW_LAYER_TEST(move_into_layer_collection_e)
+VIEW_LAYER_TEST(move_into_layer_collection_f)
+VIEW_LAYER_TEST(move_into_layer_collection_g)
+VIEW_LAYER_TEST(move_into_layer_collection_h)
+VIEW_LAYER_TEST(move_into_layer_collection_i)
+VIEW_LAYER_TEST(move_into_layer_collection_j)
+VIEW_LAYER_TEST(layer_linking)
+VIEW_LAYER_TEST(layer_syncing)
+VIEW_LAYER_TEST(scene_collection_delete)
+VIEW_LAYER_TEST(scene_copy_a)
+VIEW_LAYER_TEST(scene_copy_b)
+VIEW_LAYER_TEST(scene_copy_c)
+VIEW_LAYER_TEST(scene_copy_d)
+VIEW_LAYER_TEST(scene_copy_e)
+VIEW_LAYER_TEST(scene_copy_f)
+VIEW_LAYER_TEST(scene_delete)
+VIEW_LAYER_TEST(scene_objects)
+VIEW_LAYER_TEST(scene_write_read)
+VIEW_LAYER_TEST(view_layer_rename)
diff --git a/tests/python/view_layer/test_active_collection.py b/tests/python/view_layer/test_active_collection.py
new file mode 100644
index 00000000000..1c6c3cd1983
--- /dev/null
+++ b/tests/python/view_layer/test_active_collection.py
@@ -0,0 +1,70 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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)
+ self.rename_collections()
+
+ # 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.view_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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_background_set.py b/tests/python/view_layer/test_background_set.py
new file mode 100644
index 00000000000..a26229d53a9
--- /dev/null
+++ b/tests/python/view_layer/test_background_set.py
@@ -0,0 +1,64 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_background_set(self):
+ """
+ See if background sets are properly added and removed
+ """
+ import bpy
+
+ background_scene = bpy.data.scenes[0]
+ main_scene = bpy.data.scenes.new('main')
+ bpy.context.window.scene = main_scene
+
+ # Update depsgraph.
+ main_scene.update()
+
+ # Safety check, there should be no objects in thew newly created scene.
+ self.assertEqual(0, len(bpy.context.depsgraph.objects))
+
+ # Now set the background set, and objects relationship.
+ main_scene.background_set = background_scene
+ background_scene.objects[0].parent = background_scene.objects[1]
+
+ # Update depsgraph.
+ main_scene.update()
+
+ # Test if objects were properly added to depsgraph.
+ self.assertEqual(3, len(bpy.context.depsgraph.objects))
+
+ # We now check if the objects are properly flagged as from set
+ # These objects can't be possible nor show their origins or
+ # relationship lines
+ for ob in bpy.context.depsgraph.objects:
+ self.assertTrue(ob.is_from_set)
+
+ # Test if removing is working fine.
+ main_scene.background_set = None
+
+ # Update depsgraph.
+ main_scene.update()
+
+ self.assertEqual(0, len(bpy.context.depsgraph.objects))
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_collection_new_sync.py b/tests/python/view_layer/test_collection_new_sync.py
new file mode 100644
index 00000000000..46b63c64f45
--- /dev/null
+++ b/tests/python/view_layer/test_collection_new_sync.py
@@ -0,0 +1,47 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_view_layer_syncing(self):
+ """
+ See if we can copy view layers.
+ """
+ import bpy
+ scene = bpy.context.scene
+ view_layer = scene.view_layers.new("All")
+
+ self.assertEqual(len(view_layer.collections), 1)
+ self.assertEqual(view_layer.collections[0].collection, scene.master_collection)
+
+ self.assertEqual(
+ {collection.name for collection in view_layer.collections[0].collections},
+ {'Collection 1'})
+
+ self.assertEqual(
+ bpy.ops.outliner.collection_new(),
+ {'FINISHED'})
+
+ self.assertEqual(
+ {collection.name for collection in view_layer.collections[0].collections},
+ {'Collection 1', 'Collection 2'})
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_collection_rename_a.py b/tests/python/view_layer/test_collection_rename_a.py
new file mode 100644
index 00000000000..ea156d7346f
--- /dev/null
+++ b/tests/python/view_layer/test_collection_rename_a.py
@@ -0,0 +1,91 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def setup_family(self):
+ import bpy
+ scene = bpy.context.scene
+
+ # Just add a bunch of collections on which we can do various tests.
+ grandma = scene.master_collection.collections.new('grandma')
+ grandpa = scene.master_collection.collections.new('grandpa')
+ mom = grandma.collections.new('mom')
+ son = mom.collections.new('son')
+ daughter = mom.collections.new('daughter')
+ uncle = grandma.collections.new('uncle')
+ cousin = uncle.collections.new('cousin')
+
+ lookup = {c.name: c for c in (grandma, grandpa, mom, son, daughter, uncle, cousin)}
+ return lookup
+
+ def test_rename_a(self):
+ family = self.setup_family()
+
+ family['mom'].name = family['daughter'].name
+ # Since they are not siblings, we allow them to have the same name.
+ self.assertEqual(family['mom'].name, family['daughter'].name)
+
+ def test_rename_b(self):
+ family = self.setup_family()
+
+ family['grandma'].name = family['grandpa'].name
+ self.assertNotEqual(family['grandma'].name, family['grandpa'].name)
+
+ def test_rename_c(self):
+ family = self.setup_family()
+
+ family['cousin'].name = family['daughter'].name
+ # Since they are not siblings, we allow them to have the same name.
+ self.assertEqual(family['cousin'].name, family['daughter'].name)
+
+ def test_rename_d(self):
+ family = self.setup_family()
+
+ family['son'].name = family['daughter'].name
+ self.assertNotEqual(family['son'].name, family['daughter'].name)
+
+ def test_rename_e(self):
+ family = self.setup_family()
+
+ family['grandma'].name = family['grandpa'].name
+ self.assertNotEqual(family['grandma'].name, family['grandpa'].name)
+
+ def test_add_equal_name_a(self):
+ family = self.setup_family()
+
+ other_daughter = family['mom'].collections.new(family['daughter'].name)
+ self.assertNotEqual(other_daughter.name, family['daughter'].name)
+
+ def test_add_equal_name_b(self):
+ family = self.setup_family()
+
+ other_aunt = family['grandma'].collections.new(family['daughter'].name)
+ # Since they are not siblings, we allow them to have the same name.
+ self.assertEqual(other_aunt.name, family['daughter'].name)
+
+ def test_add_equal_name_c(self):
+ family = self.setup_family()
+
+ other_aunt = family['grandma'].collections.new(family['mom'].name)
+ self.assertNotEqual(other_aunt.name, family['mom'].name)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_collection_rename_b.py b/tests/python/view_layer/test_collection_rename_b.py
new file mode 100644
index 00000000000..3787066e1b9
--- /dev/null
+++ b/tests/python/view_layer/test_collection_rename_b.py
@@ -0,0 +1,58 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def setup_collections(self):
+ import bpy
+ scene = bpy.context.scene
+
+ master = scene.master_collection
+ one = master.collections[0]
+ two = master.collections.new()
+ sub = two.collections.new(one.name)
+
+ self.assertEqual(one.name, sub.name)
+
+ lookup = {
+ 'master': master,
+ 'one': one,
+ 'two': two,
+ 'sub': sub,
+ }
+ return lookup
+
+ def test_move_above(self):
+ collections = self.setup_collections()
+ collections['sub'].move_above(collections['one'])
+ self.assertNotEqual(collections['one'].name, collections['sub'].name)
+
+ def test_move_below(self):
+ collections = self.setup_collections()
+ collections['sub'].move_below(collections['one'])
+ self.assertNotEqual(collections['one'].name, collections['sub'].name)
+
+ def test_move_into(self):
+ collections = self.setup_collections()
+ collections['sub'].move_into(collections['master'])
+ self.assertNotEqual(collections['one'].name, collections['sub'].name)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_a.py b/tests/python/view_layer/test_evaluation_render_settings_a.py
new file mode 100644
index 00000000000..1299737cd2c
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_a.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay()
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+ clay.set('scene', 'matcap_icon', '05')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '05')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_b.py b/tests/python/view_layer/test_evaluation_render_settings_b.py
new file mode 100644
index 00000000000..77e01d85a87
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_b.py
@@ -0,0 +1,35 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay()
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+ clay.set('scene', 'matcap_icon', '05')
+ clay.set('grandma', 'matcap_icon', '03')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '03')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_c.py b/tests/python/view_layer/test_evaluation_render_settings_c.py
new file mode 100644
index 00000000000..033dd7bcb69
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_c.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay()
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+ clay.set('mom', 'matcap_icon', '02')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '02')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_d.py b/tests/python/view_layer/test_evaluation_render_settings_d.py
new file mode 100644
index 00000000000..85808c548b4
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_d.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay()
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+ clay.set('kid', 'matcap_icon', '05')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '05')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_e.py b/tests/python/view_layer/test_evaluation_render_settings_e.py
new file mode 100644
index 00000000000..2375a6e575e
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_e.py
@@ -0,0 +1,35 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay()
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+ clay.set('grandma', 'matcap_icon', '04')
+ clay.set('kid', 'matcap_icon', '05')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '05')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_f.py b/tests/python/view_layer/test_evaluation_render_settings_f.py
new file mode 100644
index 00000000000..f334880b6b4
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_f.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay(extra_kid_layer=True)
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+
+ clay.set('scene', 'matcap_icon', '05')
+ clay.set('extra', 'matcap_icon', '07')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '07')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_g.py b/tests/python/view_layer/test_evaluation_render_settings_g.py
new file mode 100644
index 00000000000..1b4262934fb
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_g.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay(extra_kid_layer=True)
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+
+ clay.set('mom', 'matcap_icon', '02')
+ clay.set('extra', 'matcap_icon', '06')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '06')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_h.py b/tests/python/view_layer/test_evaluation_render_settings_h.py
new file mode 100644
index 00000000000..937fab1521a
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_h.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay(extra_kid_layer=True)
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+
+ clay.set('kid', 'matcap_icon', '02')
+ clay.set('extra', 'matcap_icon', '04')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '04')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_render_settings_i.py b/tests/python/view_layer/test_evaluation_render_settings_i.py
new file mode 100644
index 00000000000..2842f2adb92
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_render_settings_i.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ @unittest.skip("Uses the clay engine, that is removed T55454")
+ def test_render_settings(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ clay = Clay(extra_kid_layer=True)
+ self.assertEqual(clay.get('object', 'matcap_icon'), '01')
+
+ clay.set('mom', 'matcap_icon', '02')
+ self.assertEqual(clay.get('extra', 'matcap_icon'), '01')
+ self.assertEqual(clay.get('object', 'matcap_icon'), '02')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_a.py b/tests/python/view_layer/test_evaluation_selectability_a.py
new file mode 100644
index 00000000000..eaed40869c3
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_a.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Selectability Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = False
+ bpy.context.scene.update() # update depsgraph
+ cube.select_set(True)
+
+ self.assertTrue(cube.visible_get(), "Cube should be visible")
+ self.assertTrue(cube.select_get(), "Cube should be selected")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_b.py b/tests/python/view_layer/test_evaluation_selectability_b.py
new file mode 100644
index 00000000000..584011c672c
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_b.py
@@ -0,0 +1,55 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Selectability Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+ bpy.context.scene.update() # update depsgraph
+ cube.select_set(True)
+
+ layer_collection_mom.collections[layer_collection_kid.name].enabled = False
+ layer_collection_kid.enabled = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertFalse(cube.visible_get(), "Cube should be invisible")
+ self.assertFalse(cube.select_get(), "Cube should be unselected")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_c.py b/tests/python/view_layer/test_evaluation_selectability_c.py
new file mode 100644
index 00000000000..3eecaa06aeb
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_c.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Selectability Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ bpy.context.scene.update() # update depsgraph
+ cube.select_set(True)
+
+ self.assertTrue(cube.visible_get(), "Cube should be visible")
+ self.assertTrue(cube.select_get(), "Cube should be selected")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_d.py b/tests/python/view_layer/test_evaluation_selectability_d.py
new file mode 100644
index 00000000000..c645551c5ed
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_d.py
@@ -0,0 +1,56 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Selectability Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ bpy.context.scene.update() # update depsgraph
+
+ cube.select_set(True)
+ layer_collection_mom.collections[layer_collection_kid.name].selectable = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Cube should be visible")
+ self.assertTrue(cube.select_get(), "Cube should be selected")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_e.py b/tests/python/view_layer/test_evaluation_selectability_e.py
new file mode 100644
index 00000000000..e2f0e911bbe
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_e.py
@@ -0,0 +1,55 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Selectability Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ cube.select_set(True)
+ layer_collection_mom.collections[layer_collection_kid.name].selectable = False
+ layer_collection_kid.enabled = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Cube should be visible")
+ self.assertFalse(cube.select_get(), "Cube should be unselected")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_selectability_f.py b/tests/python/view_layer/test_evaluation_selectability_f.py
new file mode 100644
index 00000000000..a902dd1dada
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_selectability_f.py
@@ -0,0 +1,44 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_selectability(self):
+ import bpy
+ scene = bpy.context.scene
+ view_layer = bpy.context.view_layer
+
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+ scene_collection = scene.master_collection.collections.new('collection')
+ layer_collection = view_layer.collections.link(scene_collection)
+
+ bpy.context.scene.update() # update depsgraph
+
+ scene_collection.objects.link(cube)
+
+ self.assertTrue(layer_collection.enabled)
+ self.assertTrue(layer_collection.selectable)
+
+ bpy.context.scene.update() # update depsgraph
+ cube.select_set(True)
+ self.assertTrue(cube.select_get())
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_a.py b/tests/python/view_layer/test_evaluation_visibility_a.py
new file mode 100644
index 00000000000..666513fa85a
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_a.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene.master_collection.collections.new("Kid")
+
+ scene_collection_mom.objects.link(cube)
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = False
+ layer_collection_kid.enabled = True
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Object should be visible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_b.py b/tests/python/view_layer/test_evaluation_visibility_b.py
new file mode 100644
index 00000000000..c24b7a73dab
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_b.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ layer_collection_mom.collections[layer_collection_kid.name].enabled = False
+ layer_collection_kid.enabled = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertFalse(cube.visible_get(), "Object should be invisible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_c.py b/tests/python/view_layer/test_evaluation_visibility_c.py
new file mode 100644
index 00000000000..5a8c6386265
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_c.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ layer_collection_mom.collections[layer_collection_kid.name].enabled = False
+ layer_collection_kid.enabled = True
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Object should be visible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_d.py b/tests/python/view_layer/test_evaluation_visibility_d.py
new file mode 100644
index 00000000000..6a5f660edde
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_d.py
@@ -0,0 +1,50 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Object should be visible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_e.py b/tests/python/view_layer/test_evaluation_visibility_e.py
new file mode 100644
index 00000000000..16e08cfaba7
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_e.py
@@ -0,0 +1,54 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_mom.objects.link(cube)
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ layer_collection_kid.enabled = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Object should be visible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ # XXX, above statement is not true, why skip the first argument?
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)[1:]
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_f.py b/tests/python/view_layer/test_evaluation_visibility_f.py
new file mode 100644
index 00000000000..cf886786c5e
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_f.py
@@ -0,0 +1,54 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ window = bpy.context.window
+ cube = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+ window.view_layer = layer
+
+ scene_collection_mom = scene.master_collection.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+
+ scene_collection_mom.objects.link(cube)
+ scene_collection_kid.objects.link(cube)
+
+ layer_collection_mom = layer.collections.link(scene_collection_mom)
+ layer_collection_kid = layer.collections.link(scene_collection_kid)
+
+ layer_collection_mom.enabled = True
+ layer_collection_mom.collections[layer_collection_kid.name].enabled = False
+ layer_collection_kid.enabled = False
+
+ bpy.context.scene.update() # update depsgraph
+ self.assertTrue(cube.visible_get(), "Object should be visible")
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_g.py b/tests/python/view_layer/test_evaluation_visibility_g.py
new file mode 100644
index 00000000000..d2dc7f27e87
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_g.py
@@ -0,0 +1,30 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility_empty(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ self.do_visibility_object_add('EMPTY')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_h.py b/tests/python/view_layer/test_evaluation_visibility_h.py
new file mode 100644
index 00000000000..0b1d779c152
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_h.py
@@ -0,0 +1,30 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility_cylinder(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ self.do_visibility_object_add('CYLINDER')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_i.py b/tests/python/view_layer/test_evaluation_visibility_i.py
new file mode 100644
index 00000000000..5a292eadd91
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_i.py
@@ -0,0 +1,30 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility_torus(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ self.do_visibility_object_add('TORUS')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_evaluation_visibility_j.py b/tests/python/view_layer/test_evaluation_visibility_j.py
new file mode 100644
index 00000000000..53810fe5599
--- /dev/null
+++ b/tests/python/view_layer/test_evaluation_visibility_j.py
@@ -0,0 +1,61 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_visibility_nested(self):
+ """
+ See if the depsgraph evaluation is correct
+ """
+ import bpy
+
+ # delete all initial objects
+ while bpy.data.objects:
+ bpy.data.objects.remove(bpy.data.objects[0])
+
+ # delete all initial collections
+ scene = bpy.context.scene
+ master_collection = scene.master_collection
+ while master_collection.collections:
+ master_collection.collections.remove(master_collection.collections[0])
+
+ collection_parent = master_collection.collections.new('parent')
+ collection_nested = collection_parent.collections.new('child linked')
+ ob = bpy.data.objects.new('An Empty', None)
+ collection_nested.objects.link(ob)
+
+ layer_collection = bpy.context.view_layer.collections.link(master_collection)
+ self.assertTrue(layer_collection.enabled)
+
+ # Update depsgraph.
+ scene.update()
+
+ self.assertTrue(ob.visible_get())
+
+ layer_collection.enabled = False
+ self.assertFalse(layer_collection.enabled)
+
+ # Update depsgraph.
+ scene.update()
+
+ self.assertFalse(ob.visible_get())
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_group_a.py b/tests/python/view_layer/test_group_a.py
new file mode 100644
index 00000000000..6e1b83efbe5
--- /dev/null
+++ b/tests/python/view_layer/test_group_a.py
@@ -0,0 +1,46 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_create_basic(self):
+ """
+ See if the creation of new groups is not crashing anything.
+ """
+ import bpy
+ scene = bpy.context.scene
+ layer_collection = bpy.context.layer_collection
+
+ # Cleanup Viewport view layer
+ # technically this shouldn't be needed but
+ # for now we need it because depsgraph build all the view layers
+ # at once.
+
+ while len(scene.view_layers) > 1:
+ scene.view_layers.remove(scene.view_layers[1])
+
+ # create group
+ group = layer_collection.create_group()
+
+ # update depsgraph
+ scene.update()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_group_b.py b/tests/python/view_layer/test_group_b.py
new file mode 100644
index 00000000000..5d3a03b129b
--- /dev/null
+++ b/tests/python/view_layer/test_group_b.py
@@ -0,0 +1,72 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_create_basic(self):
+ """
+ See if the creation of new groups is preserving visibility flags
+ from the original collections.
+ """
+ import bpy
+ scene = bpy.context.scene
+
+ # clean slate
+ self.cleanup_tree()
+
+ master_collection = scene.master_collection
+ grandma = master_collection.collections.new('бабушка')
+ mom = grandma.collections.new('матушка')
+
+ child = bpy.data.objects.new("Child", None)
+ mom.objects.link(child)
+
+ grandma_layer_collection = scene.view_layers[0].collections.link(grandma)
+ mom_layer_collection = grandma_layer_collection.collections[0]
+
+ grandma_layer_collection.enabled = True
+ grandma_layer_collection.enabled = True
+ mom_layer_collection.enabled = False
+ mom_layer_collection.selectable = True
+
+ # update depsgraph
+ scene.update()
+
+ # create group
+ group = grandma_layer_collection.create_group()
+
+ # update depsgraph
+ scene.update()
+
+ # compare
+ self.assertEqual(len(group.view_layer.collections), 1)
+ grandma_group_layer = group.view_layer.collections[0]
+
+ self.assertTrue(grandma_group_layer.enabled, True)
+ self.assertTrue(grandma_group_layer.selectable)
+
+ self.assertEqual(len(grandma_group_layer.collections), 1)
+ mom_group_layer = grandma_group_layer.collections[0]
+
+ self.assertFalse(mom_group_layer.enabled)
+ self.assertTrue(mom_group_layer.selectable)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_group_c.py b/tests/python/view_layer/test_group_c.py
new file mode 100644
index 00000000000..69feab1a56e
--- /dev/null
+++ b/tests/python/view_layer/test_group_c.py
@@ -0,0 +1,56 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_create_basic(self):
+ """
+ More advanced creation of group from a collection not directly linked
+ to the scene layer.
+ """
+ import bpy
+ scene = bpy.context.scene
+
+ # clean slate
+ self.cleanup_tree()
+
+ children = [bpy.data.objects.new("Child", None) for i in range(3)]
+ master_collection = scene.master_collection
+
+ grandma_scene_collection = master_collection.collections.new('Grand-Mother')
+ mom_scene_collection = grandma_scene_collection.collections.new('Mother')
+
+ grandma_scene_collection.objects.link(children[0])
+ mom_scene_collection.objects.link(children[1])
+
+ grandma_layer_collection = scene.view_layers[0].collections.link(grandma_scene_collection)
+ mom_layer_collection = grandma_layer_collection.collections[mom_scene_collection.name]
+
+ # update depsgraph
+ scene.update()
+
+ # create group
+ group = mom_layer_collection.create_group()
+
+ # update depsgraph
+ scene.update()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_group_d.py b/tests/python/view_layer/test_group_d.py
new file mode 100644
index 00000000000..709d27df184
--- /dev/null
+++ b/tests/python/view_layer/test_group_d.py
@@ -0,0 +1,75 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_write_load(self):
+ """
+ See if saving/loading is working for groups
+ """
+ import bpy
+ scene = bpy.context.scene
+ layer_collection = bpy.context.layer_collection
+
+ while len(scene.view_layers) > 1:
+ scene.view_layers.remove(scene.view_layers[1])
+
+ # create group
+ group = layer_collection.create_group()
+
+ self.assertEqual(1, len(bpy.data.groups))
+ self.assertEqual(1, bpy.data.groups[0].users)
+ self.assertEqual(3, len(bpy.data.groups[0].objects))
+
+ import os
+ import tempfile
+ with tempfile.TemporaryDirectory() as dirpath:
+ filepath = os.path.join(dirpath, 'layers.blend')
+
+ for i in range(3):
+ # save and re-open file
+ bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
+ bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
+
+ self.assertEqual(1, len(bpy.data.groups))
+ self.assertEqual(1, bpy.data.groups[0].users)
+ self.assertEqual(3, len(bpy.data.groups[0].objects))
+
+ # empty the group of objects
+ group = bpy.data.groups[0]
+ while group.objects:
+ group.view_layer.collections[0].collection.objects.unlink(group.objects[0])
+
+ # save and re-open file
+ bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
+ bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
+
+ self.assertEqual(1, len(bpy.data.groups))
+ self.assertEqual(0, bpy.data.groups[0].users)
+ self.assertEqual(0, len(bpy.data.groups[0].objects))
+
+ # save and re-open file
+ bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
+ bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
+
+ self.assertEqual(0, len(bpy.data.groups))
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_group_e.py b/tests/python/view_layer/test_group_e.py
new file mode 100644
index 00000000000..7385d94f1f4
--- /dev/null
+++ b/tests/python/view_layer/test_group_e.py
@@ -0,0 +1,72 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_group_delete_object(self):
+ """
+ See if we can safely remove instanced objects
+ """
+ import bpy
+ scene = bpy.context.scene
+ view_layer = bpy.context.view_layer
+ ob = bpy.context.object
+
+ # clean up the scene a bit
+ for o in (o for o in view_layer.objects if o != ob):
+ view_layer.collections[0].collection.objects.unlink(o)
+
+ for v in (v for v in scene.view_layers if v != view_layer):
+ scene.view_layers.remove(v)
+
+ # update depsgraph
+ scene.update()
+
+ # create group
+ group = bpy.data.groups.new("Switch")
+ group.objects.link(ob)
+
+ # update depsgraph
+ scene.update()
+
+ # instance the group
+ empty = bpy.data.objects.new("Empty", None)
+ bpy.context.scene_collection.objects.link(empty)
+ layer_collection = bpy.context.layer_collection
+ empty.instance_type = 'GROUP'
+ empty.instance_collection = group
+
+ # prepare to delete the original object
+ # we could just pass an overridden context
+ # but let's do it the old fashion way
+ view_layer.objects.active = ob
+ ob.select_set(True)
+ self.assertTrue(ob.select_get())
+ empty.select_set(False)
+ self.assertFalse(empty.select_get())
+
+ # update depsgraph
+ scene.update()
+
+ # delete the original object
+ bpy.ops.object.delete()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_layer_linking.py b/tests/python/view_layer/test_layer_linking.py
new file mode 100644
index 00000000000..43c88aa65f9
--- /dev/null
+++ b/tests/python/view_layer/test_layer_linking.py
@@ -0,0 +1,109 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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)
+ self.rename_collections()
+
+ # 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.view_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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_layer_syncing.py b/tests/python/view_layer/test_layer_syncing.py
new file mode 100644
index 00000000000..9baf25f9e9e
--- /dev/null
+++ b/tests/python/view_layer/test_layer_syncing.py
@@ -0,0 +1,113 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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)
+ self.rename_collections()
+
+ # 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_make_single_user.py b/tests/python/view_layer/test_make_single_user.py
new file mode 100644
index 00000000000..973c191f22d
--- /dev/null
+++ b/tests/python/view_layer/test_make_single_user.py
@@ -0,0 +1,54 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_make_single_user(self):
+ """
+ Really basic test, just to check for crashes on basic files.
+ """
+ import bpy
+ scene = bpy.context.scene
+ master_collection = scene.master_collection
+ view_layer = bpy.context.view_layer
+ ob = bpy.context.object
+
+ # clean up the scene a bit
+ for o in (o for o in view_layer.objects if o != ob):
+ view_layer.collections[0].collection.objects.unlink(o)
+
+ for v in (v for v in scene.view_layers if v != view_layer):
+ scene.view_layers.remove(v)
+
+ while master_collection.collections:
+ master_collection.collections.remove(
+ master_collection.collections[0])
+
+ view_layer.collections.link(master_collection)
+ ob.select_set(True)
+
+ # update depsgraph
+ scene.update()
+
+ # test itself
+ bpy.ops.object.make_single_user(object=True)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_a.py b/tests/python/view_layer/test_move_above_below_layer_collection_a.py
new file mode 100644
index 00000000000..7c6c1fccfa9
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_a.py
@@ -0,0 +1,48 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 1.3', 'Layer 1.C'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_above('Layer 1.C', 'Layer 1.3'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_b.py b/tests/python/view_layer/test_move_above_below_layer_collection_b.py
new file mode 100644
index 00000000000..671978a27f3
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_b.py
@@ -0,0 +1,48 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 1.3.cat', 'Layer 1.3.dog'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_above('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_c.py b/tests/python/view_layer/test_move_above_below_layer_collection_c.py
new file mode 100644
index 00000000000..671978a27f3
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_c.py
@@ -0,0 +1,48 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 1.3.cat', 'Layer 1.3.dog'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_above('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_d.py b/tests/python/view_layer/test_move_above_below_layer_collection_d.py
new file mode 100644
index 00000000000..b13e87985ee
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_d.py
@@ -0,0 +1,48 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_above('Layer 2.3.dog', 'Layer 1.C.2'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 1.C.2', 'Layer 2.3.dog'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_e.py b/tests/python/view_layer/test_move_above_below_layer_collection_e.py
new file mode 100644
index 00000000000..a9b0181083e
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_e.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 1.Master Collection', 'Layer 1.C.1'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_f.py b/tests/python/view_layer/test_move_above_below_layer_collection_f.py
new file mode 100644
index 00000000000..036486bf55a
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_f.py
@@ -0,0 +1,100 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def get_reference_layers_tree_map(self):
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ 'C',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_below('Layer 2.3', 'Layer 2.C.1'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_above('Layer 2.3', 'Layer 2.C.2'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 2.3')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # collection that will disappear
+ collection_old = self.parse_move('Layer 2.C.3')
+ collection_old.enabled = False
+ collection_old.selectable = True
+
+ # move
+ self.assertTrue(self.move_below('Layer 2.3', 'Layer 2.C.1'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 2.C.3')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_g.py b/tests/python/view_layer/test_move_above_below_layer_collection_g.py
new file mode 100644
index 00000000000..aca6c5d5ff6
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_g.py
@@ -0,0 +1,81 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['cat', None],
+ ['dog', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_above('Layer 2.C.3.cat', 'Layer 2.3.dog'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 2.C.3.cat')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # collection that will disappear
+ collection_old = self.parse_move('Layer 2.3.cat')
+ collection_old.enabled = False
+ collection_old.selectable = True
+
+ # move
+ self.assertTrue(self.move_above('Layer 2.C.3.cat', 'Layer 2.3.dog'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 2.3.cat')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_h.py b/tests/python/view_layer/test_move_above_below_layer_collection_h.py
new file mode 100644
index 00000000000..4fe2c857e50
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_h.py
@@ -0,0 +1,66 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_below('Layer 2.C.3.cat', 'Layer 2.3.dog'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 2.C.3.cat')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # collection that will disappear
+ collection_old = self.parse_move('Layer 2.3.cat')
+ collection_old.enabled = False
+ collection_old.selectable = True
+
+ # move
+ self.assertTrue(self.move_below('Layer 2.C.3.cat', 'Layer 2.3.dog'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 2.3.cat')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_i.py b/tests/python/view_layer/test_move_above_below_layer_collection_i.py
new file mode 100644
index 00000000000..dada882a412
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_i.py
@@ -0,0 +1,73 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ '3',
+ 'C',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_below('Layer 2.C', 'Layer 2.3'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 2.C')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # move
+ self.assertTrue(self.move_below('Layer 2.C', 'Layer 2.3'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 2.C')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_j.py b/tests/python/view_layer/test_move_above_below_layer_collection_j.py
new file mode 100644
index 00000000000..cb56ca0b963
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_j.py
@@ -0,0 +1,63 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_below('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.assertTrue(self.move_above('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 1.3.dog')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # move
+ self.assertTrue(self.move_below('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.assertTrue(self.move_above('Layer 1.3.dog', 'Layer 1.3.cat'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 1.3.dog')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_k.py b/tests/python/view_layer/test_move_above_below_layer_collection_k.py
new file mode 100644
index 00000000000..f6d442619f5
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_k.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_move(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_below('Layer 2.C.2', 'Layer 2.3'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_layer_collection_l.py b/tests/python/view_layer/test_move_above_below_layer_collection_l.py
new file mode 100644
index 00000000000..a8fad414685
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_layer_collection_l.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ 'C',
+ 'cat',
+ '3',
+ 'dog',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_below('Layer 2.cat', 'Layer 2.C'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_above('Layer 2.cat', 'Layer 2.3'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_a.py b/tests/python/view_layer/test_move_above_below_scene_collection_a.py
new file mode 100644
index 00000000000..f558491527e
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_a.py
@@ -0,0 +1,80 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_above(tree['dog']))
+ self.assertTrue(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['dog'].move_below(tree['cat']))
+ self.assertTrue(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['dog'].move_below(tree['cat']))
+ self.assertTrue(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_above(tree['dog']))
+ self.assertTrue(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_b.py b/tests/python/view_layer/test_move_above_below_scene_collection_b.py
new file mode 100644
index 00000000000..037ee01e205
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_b.py
@@ -0,0 +1,69 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_above(tree['1']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['1'].move_below(tree['3']))
+ self.assertTrue(tree['2'].move_below(tree['1']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_above(tree['2']))
+ self.assertTrue(tree['1'].move_above(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_c.py b/tests/python/view_layer/test_move_above_below_scene_collection_c.py
new file mode 100644
index 00000000000..07b67092d3e
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_c.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_below(tree['ii']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_d.py b/tests/python/view_layer/test_move_above_below_scene_collection_d.py
new file mode 100644
index 00000000000..9923d917abf
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_d.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['B', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_e.py b/tests/python/view_layer/test_move_above_below_scene_collection_e.py
new file mode 100644
index 00000000000..b9076826551
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_e.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['iii', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['iii'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['iii'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_f.py b/tests/python/view_layer/test_move_above_below_scene_collection_f.py
new file mode 100644
index 00000000000..3343d0d774b
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_f.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['A'].move_above(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_g.py b/tests/python/view_layer/test_move_above_below_scene_collection_g.py
new file mode 100644
index 00000000000..39848103ca2
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_g.py
@@ -0,0 +1,44 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_h.py b/tests/python/view_layer/test_move_above_below_scene_collection_h.py
new file mode 100644
index 00000000000..af2f54f3db1
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_h.py
@@ -0,0 +1,84 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_above(collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_below(collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(collection.move_above(master_collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(collection.move_below(master_collection))
+
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_i.py b/tests/python/view_layer/test_move_above_below_scene_collection_i.py
new file mode 100644
index 00000000000..a6b3cb568c9
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_i.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_above(tree['2']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_below(tree['2']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_below(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_a.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_a.py
new file mode 100644
index 00000000000..73c79b0de87
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_a.py
@@ -0,0 +1,80 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_above(tree['dog']))
+ self.assertTrue(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['dog'].move_below(tree['cat']))
+ self.assertTrue(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['dog'].move_below(tree['cat']))
+ self.assertTrue(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_above(tree['dog']))
+ self.assertTrue(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_b.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_b.py
new file mode 100644
index 00000000000..552ca0d5c9b
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_b.py
@@ -0,0 +1,69 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_above(tree['1']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['1'].move_below(tree['3']))
+ self.assertTrue(tree['2'].move_below(tree['1']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_above(tree['2']))
+ self.assertTrue(tree['1'].move_above(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_c.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_c.py
new file mode 100644
index 00000000000..c54115b0d13
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_c.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_below(tree['ii']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_d.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_d.py
new file mode 100644
index 00000000000..bb770f61344
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_d.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['B', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_e.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_e.py
new file mode 100644
index 00000000000..88a77bf8385
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_e.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['iii', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['iii'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['iii'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_f.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_f.py
new file mode 100644
index 00000000000..013165986f4
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_f.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_move(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['A'].move_above(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_g.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_g.py
new file mode 100644
index 00000000000..8c64dd6f32d
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_g.py
@@ -0,0 +1,44 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['dog'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['cat'].move_below(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_h.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_h.py
new file mode 100644
index 00000000000..dd0fcc1f732
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_h.py
@@ -0,0 +1,84 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_above(collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_below(collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(collection.move_above(master_collection))
+
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(collection.move_below(master_collection))
+
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_above_below_scene_collection_sync_i.py b/tests/python/view_layer/test_move_above_below_scene_collection_sync_i.py
new file mode 100644
index 00000000000..cdd43f5b8df
--- /dev/null
+++ b/tests/python/view_layer/test_move_above_below_scene_collection_sync_i.py
@@ -0,0 +1,60 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_move_a(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_above(tree['2']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_b(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_below(tree['2']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_c(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_above(tree['cat']))
+ self.compare_tree_maps()
+
+ def test_scene_collection_move_d(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_below(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_a.py b/tests/python/view_layer/test_move_into_layer_collection_a.py
new file mode 100644
index 00000000000..85e24e53463
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_a.py
@@ -0,0 +1,69 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ 'C',
+ '3',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into("Layer 1.C.2", "Layer 2.3"))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_b.py b/tests/python/view_layer/test_move_into_layer_collection_b.py
new file mode 100644
index 00000000000..77f5d2f2630
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_b.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into('Layer 1.3', 'Layer 1.3.cat'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_c.py b/tests/python/view_layer/test_move_into_layer_collection_c.py
new file mode 100644
index 00000000000..8ce07dd332e
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_c.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into("Layer 2.C", "Layer 2.3"))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_d.py b/tests/python/view_layer/test_move_into_layer_collection_d.py
new file mode 100644
index 00000000000..715ea6de1da
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_d.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into("Layer 2.3.cat", "Layer 2.3"))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_e.py b/tests/python/view_layer/test_move_into_layer_collection_e.py
new file mode 100644
index 00000000000..6be1a27481f
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_e.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into("Layer 1.Master Collection", "Layer 1.C"))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_f.py b/tests/python/view_layer/test_move_into_layer_collection_f.py
new file mode 100644
index 00000000000..7595619f42a
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_f.py
@@ -0,0 +1,86 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def get_reference_layers_tree_map(self):
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ ]],
+ ['Layer 2', [
+ 'C',
+ '3',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_into_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_into("Layer 1.3", "Layer 1.Master Collection.A"))
+ self.compare_tree_maps()
+
+ def test_layer_collection_into_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 1.3')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ self.assertTrue(self.move_into('Layer 1.3', 'Layer 1.Master Collection.A'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 1.Master Collection.A.3')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_g.py b/tests/python/view_layer/test_move_into_layer_collection_g.py
new file mode 100644
index 00000000000..90f6739d249
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_g.py
@@ -0,0 +1,77 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ reference_layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ 'C',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return reference_layers_map
+
+ def test_layer_collection_into_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_into('Layer 2.3', 'Layer 2.C'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_into_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 2.3')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ # collection that will disappear
+ collection_old = self.parse_move('Layer 2.C.3')
+ collection_old.enabled = False
+ collection_old.selectable = True
+
+ # move collection
+ self.assertTrue(self.move_into('Layer 2.3', 'Layer 2.C'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 2.C.3')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_h.py b/tests/python/view_layer/test_move_into_layer_collection_h.py
new file mode 100644
index 00000000000..0e5a86c57ae
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_h.py
@@ -0,0 +1,76 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', [
+ ['dog', None],
+ ]],
+ ['2', None],
+ ['3', [
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into_a(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertTrue(self.move_into('Layer 1.3.dog', 'Layer 1.C.1'))
+ self.compare_tree_maps()
+
+ def test_layer_collection_into_b(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+
+ # collection that will be moved
+ collection_original = self.parse_move('Layer 1.3.dog')
+ collection_original.enabled = True
+ collection_original.selectable = False
+
+ self.assertTrue(self.move_into('Layer 1.3.dog', 'Layer 1.C.1'))
+ self.compare_tree_maps()
+
+ # we expect the settings to be carried along from the
+ # original layer collection
+ collection_new = self.parse_move('Layer 1.C.1.dog')
+ self.assertEqual(collection_new.enabled, True)
+ self.assertEqual(collection_new.selectable, False)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_i.py b/tests/python/view_layer/test_move_into_layer_collection_i.py
new file mode 100644
index 00000000000..23c6e9f997c
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_i.py
@@ -0,0 +1,40 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into('Layer 2.C.3', 'Layer 2.dog'))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_layer_collection_j.py b/tests/python/view_layer/test_move_into_layer_collection_j.py
new file mode 100644
index 00000000000..e3d0f6c7cc8
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_layer_collection_j.py
@@ -0,0 +1,41 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveLayerCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def get_reference_layers_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_layers_tree_map()
+
+ def test_layer_collection_into(self):
+ """
+ Test outliner operations
+ Prevent collection from being dragged into itself
+ """
+ self.setup_tree()
+ self.assertFalse(self.move_into("Layer 2.dog", "Layer 2.3.dog"))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_a.py b/tests/python/view_layer/test_move_into_scene_collection_a.py
new file mode 100644
index 00000000000..ab997ddf9b6
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_a.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_into(tree['2']))
+ self.assertTrue(tree['cat'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_b.py b/tests/python/view_layer/test_move_into_scene_collection_b.py
new file mode 100644
index 00000000000..4254a736b40
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_b.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', [
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_into(tree['B']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_c.py b/tests/python/view_layer/test_move_into_scene_collection_c.py
new file mode 100644
index 00000000000..1c9aa295f72
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_c.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['cat', None],
+ ]],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_d.py b/tests/python/view_layer/test_move_into_scene_collection_d.py
new file mode 100644
index 00000000000..c8346c43e05
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_d.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ # can't move into a collection if already the last item of the collection
+ self.assertFalse(tree['cat'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_e.py b/tests/python/view_layer/test_move_into_scene_collection_e.py
new file mode 100644
index 00000000000..f8d37eb769d
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_e.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', [
+ ['B', None],
+ ]],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_into(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_f.py b/tests/python/view_layer/test_move_into_scene_collection_f.py
new file mode 100644
index 00000000000..a89c7dd81e9
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_f.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ['B', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_g.py b/tests/python/view_layer/test_move_into_scene_collection_g.py
new file mode 100644
index 00000000000..04919ca720b
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_g.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ]],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['A'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_h.py b/tests/python/view_layer/test_move_into_scene_collection_h.py
new file mode 100644
index 00000000000..57b15c4ef44
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_h.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', [
+ ['ii', None],
+ ]],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['ii'].move_into(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_i.py b/tests/python/view_layer/test_move_into_scene_collection_i.py
new file mode 100644
index 00000000000..7b4076f3fd9
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_i.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['ii', None],
+ ]],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['ii'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_j.py b/tests/python/view_layer/test_move_into_scene_collection_j.py
new file mode 100644
index 00000000000..1625b6c517e
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_j.py
@@ -0,0 +1,43 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_into(collection))
+
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_k.py b/tests/python/view_layer/test_move_into_scene_collection_k.py
new file mode 100644
index 00000000000..2d4d5b51e29
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_k.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_into(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_l.py b/tests/python/view_layer/test_move_into_scene_collection_l.py
new file mode 100644
index 00000000000..f2d52b38fe5
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_l.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_into(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_a.py b/tests/python/view_layer/test_move_into_scene_collection_sync_a.py
new file mode 100644
index 00000000000..60001b9b049
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_a.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_into(tree['2']))
+ self.assertTrue(tree['cat'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_b.py b/tests/python/view_layer/test_move_into_scene_collection_sync_b.py
new file mode 100644
index 00000000000..a485d7160d6
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_b.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', [
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['3'].move_into(tree['B']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_c.py b/tests/python/view_layer/test_move_into_scene_collection_sync_c.py
new file mode 100644
index 00000000000..e68e1d04a56
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_c.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['cat', None],
+ ]],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['cat'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_d.py b/tests/python/view_layer/test_move_into_scene_collection_sync_d.py
new file mode 100644
index 00000000000..87234efef20
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_d.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ # can't move into a collection if already the last item of the collection
+ self.assertFalse(tree['cat'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_e.py b/tests/python/view_layer/test_move_into_scene_collection_sync_e.py
new file mode 100644
index 00000000000..fac8d46e471
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_e.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', [
+ ['B', None],
+ ]],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_into(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_f.py b/tests/python/view_layer/test_move_into_scene_collection_sync_f.py
new file mode 100644
index 00000000000..bce9e45a764
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_f.py
@@ -0,0 +1,51 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ['B', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['B'].move_into(tree['3']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_g.py b/tests/python/view_layer/test_move_into_scene_collection_sync_g.py
new file mode 100644
index 00000000000..8b08eb9f210
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_g.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ]],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['A'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_h.py b/tests/python/view_layer/test_move_into_scene_collection_sync_h.py
new file mode 100644
index 00000000000..f7eeb00b150
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_h.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', [
+ ['ii', None],
+ ]],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['ii'].move_into(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_i.py b/tests/python/view_layer/test_move_into_scene_collection_sync_i.py
new file mode 100644
index 00000000000..373665dd732
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_i.py
@@ -0,0 +1,52 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ reference_tree_map = [
+ ['A', [
+ ['i', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', [
+ ['ii', None],
+ ]],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return reference_tree_map
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertTrue(tree['ii'].move_into(tree['dog']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_j.py b/tests/python/view_layer/test_move_into_scene_collection_sync_j.py
new file mode 100644
index 00000000000..519c1b81269
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_j.py
@@ -0,0 +1,43 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+
+ tree = self.setup_tree()
+
+ for collection in tree.values():
+ # can't move into master_collection anywhere
+ self.assertFalse(master_collection.move_into(collection))
+
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_k.py b/tests/python/view_layer/test_move_into_scene_collection_sync_k.py
new file mode 100644
index 00000000000..4c785418b0e
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_k.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_into(tree['2']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_move_into_scene_collection_sync_l.py b/tests/python/view_layer/test_move_into_scene_collection_sync_l.py
new file mode 100644
index 00000000000..f50cd6f7072
--- /dev/null
+++ b/tests/python/view_layer/test_move_into_scene_collection_sync_l.py
@@ -0,0 +1,36 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(MoveSceneCollectionSyncTesting):
+ def get_reference_scene_tree_map(self):
+ # original tree, no changes
+ return self.get_initial_scene_tree_map()
+
+ def test_scene_collection_into(self):
+ """
+ Test outliner operations
+ """
+ tree = self.setup_tree()
+ self.assertFalse(tree['C'].move_into(tree['cat']))
+ self.compare_tree_maps()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_cylinder.py b/tests/python/view_layer/test_object_add_cylinder.py
new file mode 100644
index 00000000000..c982219a2c9
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_cylinder.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_empty.py b/tests/python/view_layer/test_object_add_empty.py
new file mode 100644
index 00000000000..376d9361319
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_empty.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_no_collection_cylinder.py b/tests/python/view_layer/test_object_add_no_collection_cylinder.py
new file mode 100644
index 00000000000..d6138040092
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_no_collection_cylinder.py
@@ -0,0 +1,32 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_object_add_cylinder(self):
+ """
+ See if new objects are added to the correct collection
+ bpy.ops.mesh.primitive_cylinder_add()
+ """
+ import os
+ self.do_object_add_no_collection('CYLINDER')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_no_collection_empty.py b/tests/python/view_layer/test_object_add_no_collection_empty.py
new file mode 100644
index 00000000000..4c4ed45dfe8
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_no_collection_empty.py
@@ -0,0 +1,31 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_syncing_object_add_empty(self):
+ """
+ See if new objects are added to the correct collection
+ bpy.ops.object.add()
+ """
+ self.do_object_add_no_collection('EMPTY')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_no_collection_torus.py b/tests/python/view_layer/test_object_add_no_collection_torus.py
new file mode 100644
index 00000000000..0bb6b03692d
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_no_collection_torus.py
@@ -0,0 +1,31 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_syncing_object_add_torus(self):
+ """
+ See if new objects are added to the correct collection
+ bpy.ops.mesh.primitive_torus_add()
+ """
+ self.do_object_add_no_collection('TORUS')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_add_torus.py b/tests/python/view_layer/test_object_add_torus.py
new file mode 100644
index 00000000000..7ee138bb93e
--- /dev/null
+++ b/tests/python/view_layer/test_object_add_torus.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_copy.py b/tests/python/view_layer/test_object_copy.py
new file mode 100644
index 00000000000..2ca5e170192
--- /dev/null
+++ b/tests/python/view_layer/test_object_copy.py
@@ -0,0 +1,93 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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)
+ self.rename_collections()
+
+ # 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.view_layers.new('Fresh new Layer')
+ layer.collections.link(subzero)
+
+ bpy.context.window.view_layer = bpy.context.scene.view_layers['Fresh new Layer']
+
+ if mode == 'DUPLICATE':
+ # assuming the latest layer is the active layer
+ bpy.ops.object.select_all(action='DESELECT')
+ three_c.select_set(True)
+ 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_delete_a.py b/tests/python/view_layer/test_object_delete_a.py
new file mode 100644
index 00000000000..39304d1dcfc
--- /dev/null
+++ b/tests/python/view_layer/test_object_delete_a.py
@@ -0,0 +1,31 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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')
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_delete_b.py b/tests/python/view_layer/test_object_delete_b.py
new file mode 100644
index 00000000000..58dae9fc8a3
--- /dev/null
+++ b/tests/python/view_layer/test_object_delete_b.py
@@ -0,0 +1,31 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_link_a.py b/tests/python/view_layer/test_object_link_a.py
new file mode 100644
index 00000000000..4f79e1c16ad
--- /dev/null
+++ b/tests/python/view_layer/test_object_link_a.py
@@ -0,0 +1,32 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_object_link_scene(self):
+ """
+ See if we can link objects
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+ self.do_object_link(master_collection)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_link_b.py b/tests/python/view_layer/test_object_link_b.py
new file mode 100644
index 00000000000..8a78251a167
--- /dev/null
+++ b/tests/python/view_layer/test_object_link_b.py
@@ -0,0 +1,33 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_object_link_context(self):
+ """
+ See if we can link objects via bpy.context.scene_collection
+ """
+ import bpy
+ bpy.context.window.view_layer = bpy.context.scene.view_layers['Viewport']
+ master_collection = bpy.context.scene_collection
+ self.do_object_link(master_collection)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_object_link_c.py b/tests/python/view_layer/test_object_link_c.py
new file mode 100644
index 00000000000..f0118beaefe
--- /dev/null
+++ b/tests/python/view_layer/test_object_link_c.py
@@ -0,0 +1,35 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_object_link_reload(self):
+ """
+ See if we can link objects and not crash
+ """
+ import bpy
+ master_collection = bpy.context.scene.master_collection
+ self.do_object_link(master_collection)
+
+ # force depsgraph to update
+ bpy.ops.wm.read_factory_settings()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_operator_context.py b/tests/python/view_layer/test_operator_context.py
new file mode 100644
index 00000000000..d11666de118
--- /dev/null
+++ b/tests/python/view_layer/test_operator_context.py
@@ -0,0 +1,131 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_operator_context(self):
+ """
+ See if view layer context is properly set/get with operators overrides
+ when we set view_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"
+
+ view_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):
+ view_layer = context.view_layer
+ ret = {'FINISHED'}
+
+ # this is simply playing safe
+ if view_layer.name != self.view_layer:
+ if self.use_verbose:
+ print('ERROR: Render Layer mismatch: "{0}" != "{1}"'.format(
+ view_layer.name, self.view_layer))
+ ret = {'CANCELLED'}
+
+ scene_collection_name = None
+ if self.scene_collection:
+ scene_collection_name = self.scene_collection
+ else:
+ scene_collection_name = view_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)
+ self.rename_collections()
+
+ # 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.view_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')
+
+ # Change active scene layer (do it for window too just to don't get mangled in window bugs)
+ scene = bpy.context.scene
+ bpy.context.window.view_layer = bpy.context.scene.view_layers['Viewport']
+
+ # old layer
+ self.assertEqual(bpy.ops.testing.sample(view_layer='Viewport', use_verbose=True), {'FINISHED'})
+
+ # expected to fail
+ self.assertTrue(bpy.ops.testing.sample(view_layer=layer.name), {'CANCELLED'})
+
+ # set view layer and scene collection
+ override = bpy.context.copy()
+ override["view_layer"] = layer
+ override["scene_collection"] = subzero
+ self.assertEqual(bpy.ops.testing.sample(
+ override,
+ view_layer=layer.name,
+ scene_collection=subzero.name, # 'sub-zero'
+ use_verbose=True), {'FINISHED'})
+
+ # set only view layer
+ override = bpy.context.copy()
+ override["view_layer"] = layer
+
+ self.assertNotEqual(bpy.context.view_layer.name, layer.name)
+ self.assertNotEqual(bpy.context.scene_collection.name, layer.collections.active.name)
+
+ self.assertEqual(bpy.ops.testing.sample(
+ override,
+ view_layer=layer.name,
+ scene_collection=layer.collections.active.name, # 'scorpion'
+ use_verbose=False), {'CANCELLED'})
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_collection_delete.py b/tests/python/view_layer/test_scene_collection_delete.py
new file mode 100644
index 00000000000..58893810545
--- /dev/null
+++ b/tests/python/view_layer/test_scene_collection_delete.py
@@ -0,0 +1,49 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_scene_collection_delete(self):
+ """
+ See if a scene collection can be properly deleted even
+ when linked
+ """
+ import bpy
+
+ # delete all initial objects
+ while bpy.data.objects:
+ bpy.data.objects.remove(bpy.data.objects[0])
+
+ # delete all initial collections
+ scene = bpy.context.scene
+ master_collection = scene.master_collection
+ while master_collection.collections:
+ master_collection.collections.remove(master_collection.collections[0])
+
+ collection_parent = master_collection.collections.new('parent')
+ collection_nested = collection_parent.collections.new('child linked')
+ bpy.context.view_layer.collections.link(collection_nested)
+ master_collection.collections.remove(collection_parent)
+
+ # Update depsgraph.
+ scene.update()
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_a.py b/tests/python/view_layer/test_scene_copy_a.py
new file mode 100644
index 00000000000..8f0f2316ce1
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_a.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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,))
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_b.py b/tests/python/view_layer/test_scene_copy_b.py
new file mode 100644
index 00000000000..73c6976c32c
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_b.py
@@ -0,0 +1,38 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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,))
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_c.py b/tests/python/view_layer/test_scene_copy_c.py
new file mode 100644
index 00000000000..57c875c047c
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_c.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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))
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_d.py b/tests/python/view_layer/test_scene_copy_d.py
new file mode 100644
index 00000000000..6db3fb797e5
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_d.py
@@ -0,0 +1,37 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_scene_layers_link(self):
+ """
+ See if scene copying 'LINK_OBJECTS' 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_e.py b/tests/python/view_layer/test_scene_copy_e.py
new file mode 100644
index 00000000000..a2d314a037a
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_e.py
@@ -0,0 +1,47 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_shared_layer_collections_copy_full(self):
+ """
+ See if scene copying 'FULL_COPY' is working for scene collections
+ with a shared object
+ """
+ import os
+ import bpy
+
+ scene = bpy.context.scene
+ layer = bpy.context.view_layer
+
+ original_cube = layer.objects.get('Cube')
+ original_cube.select_set(True)
+ self.assertTrue(original_cube.select_get())
+
+ bpy.ops.scene.new(type='FULL_COPY')
+ new_layer = bpy.context.view_layer
+
+ self.assertNotEqual(layer, new_layer)
+ new_cube = new_layer.objects.get('Cube.001')
+ self.assertNotEqual(original_cube, new_cube)
+ self.assertTrue(new_cube.select_get())
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_copy_f.py b/tests/python/view_layer/test_scene_copy_f.py
new file mode 100644
index 00000000000..13586a66f3d
--- /dev/null
+++ b/tests/python/view_layer/test_scene_copy_f.py
@@ -0,0 +1,89 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_shared_layer_collections_copy_full(self):
+ """
+ See if scene copying 'FULL_COPY' is keeping collections visibility
+ and selectability.
+ """
+ import os
+ import bpy
+
+ scene = bpy.context.scene
+
+ enabled_lookup = [True, False, False, True]
+ enabled_lookup_sub = [False, True, False]
+
+ selectable_lookup = [True, True, False, False]
+ selectable_lookup_sub = [False, True, False, True]
+ new_collections = []
+
+ # clean everything
+ for layer in scene.view_layers:
+ while layer.collections:
+ layer.collections.unlink(layer.collections[0])
+
+ # create new collections
+ for i in range(4):
+ collection = scene.master_collection.collections.new(str(i))
+ new_collections.append(collection)
+
+ for j in range(3):
+ sub_collection = collection.collections.new("{0}:{1}".format(i, j))
+
+ # link to the original scene
+ for layer in scene.view_layers:
+ for i, collection in enumerate(new_collections):
+ layer.collections.link(collection)
+ self.assertEqual(layer.collections[-1], layer.collections[i])
+
+ layer.collections[i].enabled = enabled_lookup[i]
+ layer.collections[i].selectable = selectable_lookup[i]
+
+ for j, sub_collection in enumerate(layer.collections[i].collections):
+ sub_collection.enabled = enabled_lookup_sub[j]
+ sub_collection.selectable = selectable_lookup_sub[j]
+
+ # copy scene
+ bpy.ops.scene.new(type='FULL_COPY')
+ new_scene = bpy.context.scene
+ self.assertNotEqual(scene, new_scene)
+
+ # update depsgrah
+ scene.update() # update depsgraph
+
+ # compare scenes
+ for h, layer in enumerate(scene.view_layers):
+ new_layer = new_scene.view_layers[h]
+
+ for i, collection in enumerate(layer.collections):
+ new_collection = new_layer.collections[i]
+ self.assertEqual(collection.enabled, new_collection.enabled)
+ self.assertEqual(collection.selectable, new_collection.selectable)
+
+ for j, sub_collection in enumerate(layer.collections[i].collections):
+ new_sub_collection = new_collection.collections[j]
+ self.assertEqual(sub_collection.enabled, new_sub_collection.enabled)
+ self.assertEqual(sub_collection.selectable, new_sub_collection.selectable)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_delete.py b/tests/python/view_layer/test_scene_delete.py
new file mode 100644
index 00000000000..edc997d6495
--- /dev/null
+++ b/tests/python/view_layer/test_scene_delete.py
@@ -0,0 +1,34 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_scene_delete(self):
+ """
+ See if a scene can be properly deleted
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ bpy.data.scenes.new('New')
+ bpy.data.scenes.remove(scene)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_objects.py b/tests/python/view_layer/test_scene_objects.py
new file mode 100644
index 00000000000..c5d3a0196ed
--- /dev/null
+++ b/tests/python/view_layer/test_scene_objects.py
@@ -0,0 +1,53 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_scene_objects_a(self):
+ """
+ Test vanilla scene
+ """
+ import bpy
+
+ scene = bpy.context.scene
+ self.assertEqual(len(scene.objects), 3)
+
+ def test_scene_objects_b(self):
+ """
+ Test scene with nested collections
+ """
+ import bpy
+ scene = bpy.context.scene
+
+ # move default objects to a nested collection
+ master_collection = scene.master_collection
+ collection = master_collection.collections[0]
+ collection_nested = collection.collections.new()
+
+ for ob in collection.objects:
+ collection_nested.objects.link(ob)
+
+ while collection.objects:
+ collection.objects.unlink(collection.objects[0])
+
+ self.assertEqual(len(scene.objects), 3)
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_scene_write_read.py b/tests/python/view_layer/test_scene_write_read.py
new file mode 100644
index 00000000000..92f3395d819
--- /dev/null
+++ b/tests/python/view_layer/test_scene_write_read.py
@@ -0,0 +1,144 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ 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)
+ self.rename_collections()
+ 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)
+ self.rename_collections()
+ 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__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/test_view_layer_rename.py b/tests/python/view_layer/test_view_layer_rename.py
new file mode 100644
index 00000000000..fefb317d0b1
--- /dev/null
+++ b/tests/python/view_layer/test_view_layer_rename.py
@@ -0,0 +1,33 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+ def test_view_layer_rename(self):
+ """
+ See if we can rename view layers.
+ """
+ import bpy
+ view_layer = bpy.context.view_layer
+ print("View layer name: " + view_layer.name)
+ view_layer.name = "New Name"
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+ UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+ unittest.main()
diff --git a/tests/python/view_layer/view_layer_common.py b/tests/python/view_layer/view_layer_common.py
new file mode 100644
index 00000000000..709ef4afbfe
--- /dev/null
+++ b/tests/python/view_layer/view_layer_common.py
@@ -0,0 +1,821 @@
+import unittest
+
+__all__ = (
+ "Clay",
+ "MoveLayerCollectionTesting",
+ "MoveSceneCollectionSyncTesting",
+ "MoveSceneCollectionTesting",
+ "ViewLayerTesting",
+ "compare_files",
+ "dump",
+ "get_layers",
+ "get_scene_collections",
+ "query_scene",
+ "setup_extra_arguments",
+)
+
+# ############################################################
+# 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_disabled'] = (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(scene, layer):
+ data = {}
+ name = layer.get(b'name')
+
+ data['name'] = name
+ data['engine'] = scene.get((b'r', b'engine'))
+
+ active_base = layer.get_pointer(b'basact')
+ if active_base:
+ ob = active_base.get_pointer(b'object')
+ data['active_object'] = ob.get((b'id', b'name'))[2:]
+ else:
+ data['active_object'] = ""
+
+ 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'view_layers'):
+ name, data = get_layer(scene, 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['objects'] = get_scene_collection_objects(collection, b'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"""
+ from io_blend_utils.blend 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:
+ continue
+
+ return [callback(scene) for callback in callbacks]
+
+
+# ############################################################
+# Utils
+# ############################################################
+
+def dump(data):
+ import json
+ return json.dumps(
+ data,
+ sort_keys=True,
+ indent=4,
+ separators=(',', ': '),
+ )
+
+
+# ############################################################
+# Tests
+# ############################################################
+
+PDB = False
+DUMP_DIFF = True
+UPDATE_DIFF = False # HACK used to update tests when something change
+
+
+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_b, file_a])
+
+ if UPDATE_DIFF:
+ import subprocess
+ subprocess.call(["cp", "-u", file_a, file_b])
+
+ if PDB:
+ import pdb
+ print("Files differ:", file_b, file_a)
+ pdb.set_trace()
+
+ return False
+
+ return True
+
+
+class ViewLayerTesting(unittest.TestCase):
+ _test_simple = False
+ _extra_arguments = []
+
+ @classmethod
+ def setUpClass(cls):
+ """Runs once"""
+ cls.pretest_parsing()
+
+ @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")
+
+ def setUp(self):
+ """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))
+
+ def do_object_add(self, filepath_json, add_mode):
+ """
+ Testing for adding objects and see if they
+ go to the right collection
+ """
+ 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)
+ self.rename_collections()
+
+ # 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.view_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["view_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 do_object_add_no_collection(self, add_mode):
+ """
+ Test for adding objects when no collection
+ exists in render layer
+ """
+ import bpy
+
+ # empty layer of collections
+
+ layer = bpy.context.view_layer
+ while layer.collections:
+ layer.collections.unlink(layer.collections[0])
+
+ # add new objects
+ if add_mode == 'EMPTY':
+ bpy.ops.object.add() # 'Empty'
+
+ elif add_mode == 'CYLINDER':
+ bpy.ops.mesh.primitive_cylinder_add() # 'Cylinder'
+
+ elif add_mode == 'TORUS':
+ bpy.ops.mesh.primitive_torus_add() # 'Torus'
+
+ self.assertEqual(len(layer.collections), 1, "New collection not created")
+ collection = layer.collections[0]
+ self.assertEqual(len(collection.objects), 1, "New collection is empty")
+
+ def do_object_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 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)
+ self.rename_collections()
+ 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 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)
+ self.rename_collections()
+
+ # 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.context.scene.update() # update depsgraph
+ bpy.ops.object.select_all(action='DESELECT')
+ ob.select_set(True)
+ self.assertTrue(ob.select_get())
+ 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 do_visibility_object_add(self, add_mode):
+ import bpy
+
+ scene = bpy.context.scene
+
+ # delete all objects of the file
+ for ob in bpy.data.objects:
+ bpy.data.objects.remove(ob, do_unlink=True)
+
+ # real test
+ layer = scene.view_layers.new('Visibility Test')
+ layer.collections.unlink(layer.collections[0])
+
+ scene_collection = scene.master_collection.collections.new("Collection")
+ layer.collections.link(scene_collection)
+
+ bpy.context.scene.update() # update depsgraph
+
+ self.assertEqual(len(bpy.data.objects), 0)
+
+ # add new objects
+ if add_mode == 'EMPTY':
+ bpy.ops.object.add() # 'Empty'
+
+ elif add_mode == 'CYLINDER':
+ bpy.ops.mesh.primitive_cylinder_add() # 'Cylinder'
+
+ elif add_mode == 'TORUS':
+ bpy.ops.mesh.primitive_torus_add() # 'Torus'
+
+ self.assertEqual(len(bpy.data.objects), 1)
+
+ new_ob = bpy.data.objects[0]
+ self.assertTrue(new_ob.visible_get(), "Object should be visible")
+
+ def cleanup_tree(self):
+ """
+ Remove any existent layer and collections,
+ leaving only the one view_layer we can't remove
+ """
+ import bpy
+ scene = bpy.context.scene
+ while len(scene.view_layers) > 1:
+ scene.view_layers.remove(scene.view_layers[1])
+
+ layer = scene.view_layers[0]
+ while layer.collections:
+ layer.collections.unlink(layer.collections[0])
+
+ master_collection = scene.master_collection
+ while master_collection.collections:
+ master_collection.collections.remove(master_collection.collections[0])
+
+ def rename_collections(self, collection=None):
+ """
+ Rename 'Collection 1' to '1'
+ """
+ def strip_name(collection):
+ import re
+ if collection.name.startswith("Default Collection"):
+ collection.name = '1'
+ else:
+ collection.name = re.findall(r'\d+', collection.name)[0]
+
+ if collection is None:
+ import bpy
+ collection = bpy.context.scene.master_collection
+
+ for nested_collection in collection.collections:
+ strip_name(nested_collection)
+ self.rename_collections(nested_collection)
+
+
+class MoveSceneCollectionTesting(ViewLayerTesting):
+ """
+ To be used by tests of view_layer_move_into_scene_collection
+ """
+
+ def get_initial_scene_tree_map(self):
+ collections_map = [
+ ['A', [
+ ['i', None],
+ ['ii', None],
+ ['iii', None],
+ ]],
+ ['B', None],
+ ['C', [
+ ['1', None],
+ ['2', None],
+ ['3', [
+ ['dog', None],
+ ['cat', None],
+ ]],
+ ]],
+ ]
+ return collections_map
+
+ def build_scene_tree(self, tree_map, collection=None, ret_dict=None):
+ """
+ Returns a flat dictionary with new scene collections
+ created from a nested tuple of nested tuples (name, tuple)
+ """
+ import bpy
+
+ if collection is None:
+ collection = bpy.context.scene.master_collection
+
+ if ret_dict is None:
+ ret_dict = {collection.name: collection}
+ self.assertEqual(collection.name, "Master Collection")
+
+ for name, nested_collections in tree_map:
+ new_collection = collection.collections.new(name)
+ ret_dict[name] = new_collection
+
+ if nested_collections:
+ self.build_scene_tree(nested_collections, new_collection, ret_dict)
+
+ return ret_dict
+
+ def setup_tree(self):
+ """
+ Cleanup file, and populate it with class scene tree map
+ """
+ self.cleanup_tree()
+ self.assertTrue(
+ hasattr(self, "get_initial_scene_tree_map"),
+ "Test class has no get_initial_scene_tree_map method implemented")
+
+ return self.build_scene_tree(self.get_initial_scene_tree_map())
+
+ def get_scene_tree_map(self, collection=None, ret_list=None):
+ """
+ Extract the scene collection tree from scene
+ Return as a nested list of nested lists (name, list)
+ """
+ import bpy
+
+ if collection is None:
+ scene = bpy.context.scene
+ collection = scene.master_collection
+
+ if ret_list is None:
+ ret_list = []
+
+ for nested_collection in collection.collections:
+ new_collection = [nested_collection.name, None]
+ ret_list.append(new_collection)
+
+ if nested_collection.collections:
+ new_collection[1] = list()
+ self.get_scene_tree_map(nested_collection, new_collection[1])
+
+ return ret_list
+
+ def compare_tree_maps(self):
+ """
+ Compare scene with expected (class defined) data
+ """
+ self.assertEqual(self.get_scene_tree_map(), self.get_reference_scene_tree_map())
+
+
+class MoveSceneCollectionSyncTesting(MoveSceneCollectionTesting):
+ """
+ To be used by tests of view_layer_move_into_scene_collection_sync
+ """
+
+ def get_initial_layers_tree_map(self):
+ layers_map = [
+ ['Layer 1', [
+ 'Master Collection',
+ 'C',
+ '3',
+ ]],
+ ['Layer 2', [
+ 'C',
+ '3',
+ 'dog',
+ 'cat',
+ ]],
+ ]
+ return layers_map
+
+ def get_reference_layers_tree_map(self):
+ """
+ For those classes we don't expect any changes in the layer tree
+ """
+ return self.get_initial_layers_tree_map()
+
+ def setup_tree(self):
+ tree = super(MoveSceneCollectionSyncTesting, self).setup_tree()
+
+ import bpy
+ scene = bpy.context.scene
+
+ self.assertTrue(
+ hasattr(self, "get_initial_layers_tree_map"),
+ "Test class has no get_initial_layers_tree_map method implemented")
+
+ layers_map = self.get_initial_layers_tree_map()
+
+ for layer_name, collections_names in layers_map:
+ layer = scene.view_layers.new(layer_name)
+ layer.collections.unlink(layer.collections[0])
+
+ for collection_name in collections_names:
+ layer.collections.link(tree[collection_name])
+
+ return tree
+
+ def compare_tree_maps(self):
+ """
+ Compare scene with expected (class defined) data
+ """
+ super(MoveSceneCollectionSyncTesting, self).compare_tree_maps()
+
+ import bpy
+ scene = bpy.context.scene
+ layers_map = self.get_reference_layers_tree_map()
+
+ for layer_name, collections_names in layers_map:
+ layer = scene.view_layers.get(layer_name)
+ self.assertTrue(layer)
+ self.assertEqual(len(collections_names), len(layer.collections))
+
+ for i, collection_name in enumerate(collections_names):
+ self.assertEqual(collection_name, layer.collections[i].name)
+ self.verify_collection_tree(layer.collections[i])
+
+ def verify_collection_tree(self, layer_collection):
+ """
+ Check if the LayerCollection mimics the SceneLayer tree
+ """
+ scene_collection = layer_collection.collection
+ self.assertEqual(len(layer_collection.collections), len(scene_collection.collections))
+
+ for i, nested_collection in enumerate(layer_collection.collections):
+ self.assertEqual(nested_collection.collection.name, scene_collection.collections[i].name)
+ self.assertEqual(nested_collection.collection, scene_collection.collections[i])
+ self.verify_collection_tree(nested_collection)
+
+
+class MoveLayerCollectionTesting(MoveSceneCollectionSyncTesting):
+ """
+ To be used by tests of view_layer_move_into_layer_collection
+ """
+
+ def parse_move(self, path, sep='.'):
+ """
+ convert 'Layer 1.C.2' into:
+ bpy.context.scene.view_layers['Layer 1'].collections['C'].collections['2']
+ """
+ import bpy
+
+ paths = path.split(sep)
+ layer = bpy.context.scene.view_layers[paths[0]]
+ collections = layer.collections
+
+ for subpath in paths[1:]:
+ collection = collections[subpath]
+ collections = collection.collections
+
+ return collection
+
+ def move_into(self, src, dst):
+ layer_collection_src = self.parse_move(src)
+ layer_collection_dst = self.parse_move(dst)
+ return layer_collection_src.move_into(layer_collection_dst)
+
+ def move_above(self, src, dst):
+ layer_collection_src = self.parse_move(src)
+ layer_collection_dst = self.parse_move(dst)
+ return layer_collection_src.move_above(layer_collection_dst)
+
+ def move_below(self, src, dst):
+ layer_collection_src = self.parse_move(src)
+ layer_collection_dst = self.parse_move(dst)
+ return layer_collection_src.move_below(layer_collection_dst)
+
+
+class Clay:
+ def __init__(self, extra_kid_layer=False):
+ import bpy
+
+ self._scene = bpy.context.scene
+ self._layer = self._fresh_layer()
+ self._object = bpy.data.objects.new('guinea pig', bpy.data.meshes.new('mesh'))
+
+ # update depsgraph
+ self._scene.update()
+
+ scene_collection_grandma = self._scene.master_collection.collections.new("Grandma")
+ scene_collection_mom = scene_collection_grandma.collections.new("Mom")
+ scene_collection_kid = scene_collection_mom.collections.new("Kid")
+ scene_collection_kid.objects.link(self._object)
+
+ layer_collection_grandma = self._layer.collections.link(scene_collection_grandma)
+ layer_collection_mom = layer_collection_grandma.collections[0]
+ layer_collection_kid = layer_collection_mom.collections[0]
+
+ # store the variables
+ self._scene_collections = {
+ 'grandma': scene_collection_grandma,
+ 'mom': scene_collection_mom,
+ 'kid': scene_collection_kid,
+ }
+ self._layer_collections = {
+ 'grandma': layer_collection_grandma,
+ 'mom': layer_collection_mom,
+ 'kid': layer_collection_kid,
+ }
+
+ if extra_kid_layer:
+ layer_collection_extra = self._layer.collections.link(scene_collection_kid)
+ self._layer_collections['extra'] = layer_collection_extra
+
+ self._update()
+
+ def _fresh_layer(self):
+ import bpy
+
+ # remove all other objects
+ while bpy.data.objects:
+ bpy.data.objects.remove(bpy.data.objects[0])
+
+ # remove all the other collections
+ while self._scene.master_collection.collections:
+ self._scene.master_collection.collections.remove(
+ self._scene.master_collection.collections[0])
+
+ layer = self._scene.view_layers.new('Evaluation Test')
+ layer.collections.unlink(layer.collections[0])
+ bpy.context.window.view_layer = layer
+
+ # remove all other layers
+ for layer_iter in self._scene.view_layers:
+ if layer_iter != layer:
+ self._scene.view_layers.remove(layer_iter)
+
+ return layer
+
+ def _update(self):
+ """
+ Force depsgrpah evaluation
+ and update pointers to IDProperty collections
+ """
+ ENGINE = 'BLENDER_CLAY'
+
+ self._scene.update() # update depsgraph
+ self._layer.update() # flush depsgraph evaluation
+
+ # change scene settings
+ self._properties = {
+ 'scene': self._scene.collection_properties[ENGINE],
+ 'object': self._object.collection_properties[ENGINE],
+ }
+
+ for key, value in self._layer_collections.items():
+ self._properties[key] = self._layer_collections[key].engine_overrides[ENGINE]
+
+ def get(self, name, data_path):
+ self._update()
+ return getattr(self._properties[name], data_path)
+
+ def set(self, name, data_path, value):
+ self._update()
+ self._properties[name].use(data_path)
+ setattr(self._properties[name], data_path, value)
+
+
+def setup_extra_arguments(filepath):
+ """
+ Create a value which is assigned to: ``UnitTesting._extra_arguments``
+ """
+ import sys
+
+ extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
+ sys.argv = [filepath] + extra_arguments[1:]
+
+ return extra_arguments