diff --git a/test/test_utils.hh b/test/test_utils.hh index 150f70b60..e52599dad 100644 --- a/test/test_utils.hh +++ b/test/test_utils.hh @@ -18,7 +18,9 @@ #define SDF_TEST_UTILS_HH_ #include +#include #include "sdf/Console.hh" +#include "sdf/Root.hh" namespace sdf { @@ -104,6 +106,25 @@ class RedirectConsoleStream private: sdf::Console::ConsoleStream oldStream; }; +/// \brief Load an SDF file into a sdf::Root object +/// \param[in] _fileName The name of the file to load +/// \param[in] _root The sdf::Root object to load the file into +/// \return True if a file named _fileName was successfully loaded into +/// _root. False otherwise +bool LoadSdfFile(const std::string &_fileName, sdf::Root &_root) +{ + auto errors = _root.Load(_fileName); + if (!errors.empty()) + { + std::cerr << "Errors encountered:\n"; + for (const auto &e : errors) + std::cerr << e << "\n"; + return false; + } + + return true; +} + } // namespace testing } // namespace sdf diff --git a/usd/src/CMakeLists.txt b/usd/src/CMakeLists.txt index b447ccd8a..4b8de3a34 100644 --- a/usd/src/CMakeLists.txt +++ b/usd/src/CMakeLists.txt @@ -17,6 +17,11 @@ target_link_libraries(${usd_target} ) # Build the unit tests -ign_build_tests(TYPE UNIT SOURCES ${gtest_sources} LIB_DEPS ${usd_target}) +ign_build_tests( + TYPE UNIT + SOURCES ${gtest_sources} + LIB_DEPS ${usd_target} + INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/test +) add_subdirectory(cmd) diff --git a/usd/src/World.cc b/usd/src/World.cc index 6dd03ee71..e8ae2b2bf 100644 --- a/usd/src/World.cc +++ b/usd/src/World.cc @@ -53,7 +53,9 @@ namespace usd static_cast(sdfWorldGravity.Length())); // TODO(ahcorde) Add parser - std::cerr << "Parser for a sdf world is not yet implemented\n"; + std::cerr << "Parser for a sdf world only parses physics information at " + << "the moment. Models and lights that are children of the world " + << "are currently being ignored.\n"; return true; } diff --git a/usd/src/World_Sdf2Usd_TEST.cc b/usd/src/World_Sdf2Usd_TEST.cc new file mode 100644 index 000000000..2c52c26ad --- /dev/null +++ b/usd/src/World_Sdf2Usd_TEST.cc @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdf/usd/World.hh" +#include "sdf/Root.hh" +#include "test_config.h" +#include "test_utils.hh" + +///////////////////////////////////////////////// +// Fixture that creates a USD stage for each test case. +class UsdStageFixture : public::testing::Test +{ + public: UsdStageFixture() = default; + + protected: void SetUp() override + { + this->stage = pxr::UsdStage::CreateInMemory(); + ASSERT_TRUE(this->stage); + } + + public: pxr::UsdStageRefPtr stage; +}; + +///////////////////////////////////////////////// +TEST_F(UsdStageFixture, World) +{ + const auto path = sdf::testing::TestFile("sdf", "empty.sdf"); + sdf::Root root; + + ASSERT_TRUE(sdf::testing::LoadSdfFile(path, root)); + ASSERT_EQ(1u, root.WorldCount()); + auto world = root.WorldByIndex(0u); + + const auto worldPath = std::string("/" + world->Name()); + EXPECT_TRUE(usd::ParseSdfWorld(*world, this->stage, worldPath)); + + // check top-level stage information + EXPECT_DOUBLE_EQ(100.0, this->stage->GetEndTimeCode()); + EXPECT_DOUBLE_EQ(0.0, this->stage->GetStartTimeCode()); + EXPECT_DOUBLE_EQ(24.0, this->stage->GetTimeCodesPerSecond()); + pxr::TfToken upAxisVal; + EXPECT_TRUE(this->stage->GetMetadata(pxr::UsdGeomTokens->upAxis, &upAxisVal)); + EXPECT_EQ(pxr::UsdGeomTokens->z, upAxisVal); + double metersPerUnitVal; + EXPECT_TRUE(this->stage->GetMetadata(pxr::TfToken("metersPerUnit"), + &metersPerUnitVal)); + EXPECT_DOUBLE_EQ(1.0, metersPerUnitVal); + + // Check that world prim exists, and that things like physics information + // were parsed correctly + auto worldPrim = this->stage->GetPrimAtPath(pxr::SdfPath(worldPath)); + ASSERT_TRUE(worldPrim); + auto physicsScene = pxr::UsdPhysicsScene::Get(this->stage, + pxr::SdfPath(worldPath + "/physics")); + ASSERT_TRUE(physicsScene); + pxr::GfVec3f gravityDirectionVal; + EXPECT_TRUE(physicsScene.GetGravityDirectionAttr().Get(&gravityDirectionVal)); + EXPECT_EQ(gravityDirectionVal, pxr::GfVec3f(0, 0, -1)); + float gravityMagnitudeVal; + EXPECT_TRUE(physicsScene.GetGravityMagnitudeAttr().Get(&gravityMagnitudeVal)); + EXPECT_FLOAT_EQ(gravityMagnitudeVal, 9.8f); +}