diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/gtests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/gtests/usd/CMakeLists.txt | 87 | ||||
-rw-r--r-- | tests/gtests/usd/abstract_hierarchy_iterator_test.cc | 202 | ||||
-rw-r--r-- | tests/gtests/usd/hierarchy_context_order_test.cc | 123 | ||||
-rw-r--r-- | tests/gtests/usd/usd_stage_creation_test.cc | 72 |
5 files changed, 487 insertions, 0 deletions
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt index 54a1ee41198..7da65bcc8b9 100644 --- a/tests/gtests/CMakeLists.txt +++ b/tests/gtests/CMakeLists.txt @@ -19,4 +19,7 @@ if(WITH_GTESTS) if(WITH_ALEMBIC) add_subdirectory(alembic) endif() + if(WITH_USD) + add_subdirectory(usd) + endif() endif() diff --git a/tests/gtests/usd/CMakeLists.txt b/tests/gtests/usd/CMakeLists.txt new file mode 100644 index 00000000000..e2768509ec4 --- /dev/null +++ b/tests/gtests/usd/CMakeLists.txt @@ -0,0 +1,87 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2019, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +# This suppresses the warning "This file includes at least one deprecated or antiquated +# header which may be removed without further notice at a future date", which is caused +# by the USD library including <ext/hash_set> on Linux. This has been reported at: +# https://github.com/PixarAnimationStudios/USD/issues/1057. +if(UNIX AND NOT APPLE) + add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH) +endif() +if(WIN32) + add_definitions(-DNOMINMAX) +endif() +add_definitions(-DPXR_STATIC) + +set(INC + . + .. + ../../../source/blender/blenlib + ../../../source/blender/blenkernel + ../../../source/blender/usd + ../../../source/blender/makesdna + ../../../source/blender/depsgraph + ${USD_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} + ${TBB_INCLUDE_DIR} +) + +set(LIB + bf_blenloader_test + bf_blenloader + + # Should not be needed but gives windows linker errors if the ocio libs are linked before this: + bf_intern_opencolorio + bf_gpu + + bf_usd +) + +include_directories(${INC}) + +setup_libdirs() +get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP) + +set(SRC + abstract_hierarchy_iterator_test.cc + hierarchy_context_order_test.cc +) + +if(UNIX AND NOT APPLE) + # TODO(Sybren): This unit test has only been tested on Linux, and should possibly be + # restructured to support other platforms as well. + list(APPEND SRC usd_stage_creation_test.cc) +endif() + + +if(WITH_BUILDINFO) + list(APPEND SRC "$<TARGET_OBJECTS:buildinfoobj>") +endif() + +BLENDER_SRC_GTEST_EX( + NAME usd + SRC "${SRC}" + EXTRA_LIBS "${LIB}" + COMMAND_ARGS + --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests" + --test-blender-executable-dir "${EXECUTABLE_OUTPUT_PATH}" +) + +setup_liblinks(usd_test) diff --git a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc new file mode 100644 index 00000000000..e87ef547052 --- /dev/null +++ b/tests/gtests/usd/abstract_hierarchy_iterator_test.cc @@ -0,0 +1,202 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ +#include "blenloader/blendfile_loading_base_test.h" +#include "intern/abstract_hierarchy_iterator.h" + +extern "C" { +#include "BLI_math.h" +#include "DEG_depsgraph.h" +#include "DNA_object_types.h" +} + +#include <map> +#include <set> + +/* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported + * multiple times, hence the set. */ +typedef std::map<std::string, std::set<std::string>> created_writers; + +using namespace USD; + +class TestHierarchyWriter : public AbstractHierarchyWriter { + public: + created_writers &writers_map; + + TestHierarchyWriter(created_writers &writers_map) : writers_map(writers_map) + { + } + + void write(HierarchyContext &context) override + { + const char *id_name = context.object->id.name; + created_writers::mapped_type &writers = writers_map[id_name]; + + BLI_assert(writers.find(context.export_path) == writers.end()); + writers.insert(context.export_path); + } +}; + +void debug_print_writers(const char *label, const created_writers &writers_map) +{ + printf("%s:\n", label); + for (auto idname_writers : writers_map) { + printf(" %s:\n", idname_writers.first.c_str()); + for (const std::string &export_path : idname_writers.second) { + printf(" - %s\n", export_path.c_str()); + } + } +} + +class TestingHierarchyIterator : public AbstractHierarchyIterator { + public: /* Public so that the test cases can directly inspect the created writers. */ + created_writers transform_writers; + created_writers data_writers; + created_writers hair_writers; + created_writers particle_writers; + + public: + explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph) + { + } + virtual ~TestingHierarchyIterator() + { + } + + protected: + AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) override + { + return new TestHierarchyWriter(transform_writers); + } + AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override + { + return new TestHierarchyWriter(data_writers); + } + AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override + { + return new TestHierarchyWriter(hair_writers); + } + AbstractHierarchyWriter *create_particle_writer(const HierarchyContext *context) override + { + return new TestHierarchyWriter(particle_writers); + } + + void delete_object_writer(AbstractHierarchyWriter *writer) override + { + delete writer; + } +}; + +class USDHierarchyIteratorTest : public BlendfileLoadingBaseTest { + protected: + TestingHierarchyIterator *iterator; + + virtual void SetUp() + { + BlendfileLoadingBaseTest::SetUp(); + iterator = nullptr; + } + + virtual void TearDown() + { + iterator_free(); + BlendfileLoadingBaseTest::TearDown(); + } + + /* Create a test iterator. */ + void iterator_create() + { + iterator = new TestingHierarchyIterator(depsgraph); + } + /* Free the test iterator if it is not nullptr. */ + void iterator_free() + { + if (iterator == nullptr) { + return; + } + delete iterator; + iterator = nullptr; + } +}; + +TEST_F(USDHierarchyIteratorTest, ExportHierarchyTest) +{ + /* Load the test blend file. */ + if (!blendfile_load("usd/usd_hierarchy_export_test.blend")) { + return; + } + depsgraph_create(DAG_EVAL_RENDER); + iterator_create(); + + iterator->iterate_and_write(); + + // Mapping from object name to set of export paths. + created_writers expected_transforms = { + {"OBCamera", {"/Camera"}}, + {"OBDupli1", {"/Dupli1"}}, + {"OBDupli2", {"/ParentOfDupli2/Dupli2"}}, + {"OBGEO_Ear_L", + {"/Dupli1/GEO_Head-0/GEO_Ear_L-1", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1"}}, + {"OBGEO_Ear_R", + {"/Dupli1/GEO_Head-0/GEO_Ear_R-2", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2"}}, + {"OBGEO_Head", + {"/Dupli1/GEO_Head-0", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head", + "/ParentOfDupli2/Dupli2/GEO_Head-0"}}, + {"OBGEO_Nose", + {"/Dupli1/GEO_Head-0/GEO_Nose-3", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3"}}, + {"OBGround plane", {"/Ground plane"}}, + {"OBOutsideDupliGrandParent", {"/Ground plane/OutsideDupliGrandParent"}}, + {"OBOutsideDupliParent", {"/Ground plane/OutsideDupliGrandParent/OutsideDupliParent"}}, + {"OBParentOfDupli2", {"/ParentOfDupli2"}}}; + EXPECT_EQ(expected_transforms, iterator->transform_writers); + + created_writers expected_data = { + {"OBCamera", {"/Camera/Camera"}}, + {"OBGEO_Ear_L", + {"/Dupli1/GEO_Head-0/GEO_Ear_L-1/Ear", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L/Ear", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1/Ear"}}, + {"OBGEO_Ear_R", + {"/Dupli1/GEO_Head-0/GEO_Ear_R-2/Ear", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R/Ear", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2/Ear"}}, + {"OBGEO_Head", + {"/Dupli1/GEO_Head-0/Face", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/Face", + "/ParentOfDupli2/Dupli2/GEO_Head-0/Face"}}, + {"OBGEO_Nose", + {"/Dupli1/GEO_Head-0/GEO_Nose-3/Nose", + "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose/Nose", + "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3/Nose"}}, + {"OBGround plane", {"/Ground plane/Plane"}}, + {"OBParentOfDupli2", {"/ParentOfDupli2/Icosphere"}}, + }; + + EXPECT_EQ(expected_data, iterator->data_writers); + + // The scene has no hair or particle systems. + EXPECT_EQ(0, iterator->hair_writers.size()); + EXPECT_EQ(0, iterator->particle_writers.size()); +} diff --git a/tests/gtests/usd/hierarchy_context_order_test.cc b/tests/gtests/usd/hierarchy_context_order_test.cc new file mode 100644 index 00000000000..ce3b43484e7 --- /dev/null +++ b/tests/gtests/usd/hierarchy_context_order_test.cc @@ -0,0 +1,123 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ +#include "intern/abstract_hierarchy_iterator.h" + +#include "testing/testing.h" + +extern "C" { +#include "BLI_utildefines.h" +} + +using namespace USD; + +class HierarchyContextOrderTest : public testing::Test { +}; + +static Object *fake_pointer(int value) +{ + return static_cast<Object *>(POINTER_FROM_INT(value)); +} + +TEST_F(HierarchyContextOrderTest, ObjectPointerTest) +{ + HierarchyContext ctx_a; + ctx_a.object = fake_pointer(1); + ctx_a.duplicator = nullptr; + + HierarchyContext ctx_b; + ctx_b.object = fake_pointer(2); + ctx_b.duplicator = nullptr; + + EXPECT_EQ(true, ctx_a < ctx_b); + EXPECT_EQ(false, ctx_b < ctx_a); + EXPECT_EQ(false, ctx_a < ctx_a); +} + +TEST_F(HierarchyContextOrderTest, DuplicatorPointerTest) +{ + HierarchyContext ctx_a; + ctx_a.object = fake_pointer(1); + ctx_a.duplicator = fake_pointer(1); + ctx_a.export_name = "A"; + + HierarchyContext ctx_b; + ctx_b.object = fake_pointer(1); + ctx_b.duplicator = fake_pointer(1); + ctx_b.export_name = "B"; + + EXPECT_EQ(true, ctx_a < ctx_b); + EXPECT_EQ(false, ctx_b < ctx_a); + EXPECT_EQ(false, ctx_a < ctx_a); +} + +TEST_F(HierarchyContextOrderTest, ExportParentTest) +{ + HierarchyContext ctx_a; + ctx_a.object = fake_pointer(1); + ctx_a.export_parent = fake_pointer(1); + + HierarchyContext ctx_b; + ctx_b.object = fake_pointer(1); + ctx_b.export_parent = fake_pointer(2); + + EXPECT_EQ(true, ctx_a < ctx_b); + EXPECT_EQ(false, ctx_b < ctx_a); + EXPECT_EQ(false, ctx_a < ctx_a); +} + +TEST_F(HierarchyContextOrderTest, TransitiveTest) +{ + HierarchyContext ctx_a; + ctx_a.object = fake_pointer(1); + ctx_a.export_parent = fake_pointer(1); + ctx_a.duplicator = nullptr; + ctx_a.export_name = "A"; + + HierarchyContext ctx_b; + ctx_b.object = fake_pointer(2); + ctx_b.export_parent = nullptr; + ctx_b.duplicator = fake_pointer(1); + ctx_b.export_name = "B"; + + HierarchyContext ctx_c; + ctx_c.object = fake_pointer(2); + ctx_c.export_parent = fake_pointer(2); + ctx_c.duplicator = fake_pointer(1); + ctx_c.export_name = "C"; + + HierarchyContext ctx_d; + ctx_d.object = fake_pointer(2); + ctx_d.export_parent = fake_pointer(3); + ctx_d.duplicator = nullptr; + ctx_d.export_name = "D"; + + EXPECT_EQ(true, ctx_a < ctx_b); + EXPECT_EQ(true, ctx_a < ctx_c); + EXPECT_EQ(true, ctx_a < ctx_d); + EXPECT_EQ(true, ctx_b < ctx_c); + EXPECT_EQ(true, ctx_b < ctx_d); + EXPECT_EQ(true, ctx_c < ctx_d); + + EXPECT_EQ(false, ctx_b < ctx_a); + EXPECT_EQ(false, ctx_c < ctx_a); + EXPECT_EQ(false, ctx_d < ctx_a); + EXPECT_EQ(false, ctx_c < ctx_b); + EXPECT_EQ(false, ctx_d < ctx_b); + EXPECT_EQ(false, ctx_d < ctx_c); +} diff --git a/tests/gtests/usd/usd_stage_creation_test.cc b/tests/gtests/usd/usd_stage_creation_test.cc new file mode 100644 index 00000000000..fcf1e93ea7d --- /dev/null +++ b/tests/gtests/usd/usd_stage_creation_test.cc @@ -0,0 +1,72 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ +#include "testing/testing.h" +#include <pxr/usd/usd/stage.h> + +#include <string> + +extern "C" { +#include "BLI_path_util.h" +#include "BLI_utildefines.h" + +#include "BKE_appdir.h" + +/* Workaround to make it possible to pass a path at runtime to USD. See creator.c. */ +void usd_initialise_plugin_path(const char *datafiles_usd_path); +} + +DEFINE_string(test_blender_executable_dir, "", "Blender's installation directory."); + +class USDStageCreationTest : public testing::Test { +}; + +TEST_F(USDStageCreationTest, JSONFileLoadingTest) +{ + std::string filename = "usd-stage-creation-test.usdc"; + + if (FLAGS_test_blender_executable_dir.empty()) { + FAIL() << "Pass the flag"; + } + + /* Required on Linux to make BKE_appdir_folder_id() find the datafiles. + * Without going to this directory, Blender looks for the datafiles in + * .../bin/tests instead of .../bin */ + const char *blender_executable_dir = FLAGS_test_blender_executable_dir.c_str(); + if (chdir(blender_executable_dir) < 0) { + FAIL() << "unable to change directory to " << FLAGS_test_blender_executable_dir; + } + + const char *usd_datafiles_relpath = BKE_appdir_folder_id(BLENDER_DATAFILES, "usd"); + EXPECT_NE(usd_datafiles_relpath, nullptr) << "Unable to find datafiles/usd"; + + char usd_datafiles_abspath[FILE_MAX]; + BLI_path_join(usd_datafiles_abspath, + sizeof(usd_datafiles_abspath), + blender_executable_dir, + usd_datafiles_relpath, + NULL); + + usd_initialise_plugin_path(usd_datafiles_abspath); + + /* Simply the ability to create a USD Stage for a specific filename means that the extension has + * been recognised by the USD library, and that a USD plugin has been loaded to write such files. + * Practically, this is a test to see whether the USD JSON files can be found and loaded. */ + pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(filename); + EXPECT_TRUE(usd_stage) << "unable to find suitable USD plugin to write " << filename; +} |