From 78e01100c2406703e5cfd69b6eac2e26f05d000c Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Wed, 23 Feb 2022 09:10:35 -0600 Subject: [PATCH 01/14] Add explicit root variant of TempDirectory Signed-off-by: Michael Carroll --- include/ignition/common/TempDirectory.hh | 16 ++++++++++++++++ src/TempDirectory.cc | 12 +++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/ignition/common/TempDirectory.hh b/include/ignition/common/TempDirectory.hh index a23c3eab..259acdf1 100644 --- a/include/ignition/common/TempDirectory.hh +++ b/include/ignition/common/TempDirectory.hh @@ -74,6 +74,22 @@ namespace ignition const std::string &_subDir = "ignition", bool _cleanup = true); + /// \brief Create a directory in the tempDirectoryPath by expanding + /// a name template. This directory can also be automatically cleaned + /// up when the object goes out of scope. + /// + /// The TempDirectory will have the form _root/_subdir/_prefixXXXXX/ + /// + /// \param[in[ _root Explicitly set the root directory + /// \param[in] _prefix String to be expanded for the template + /// \param[in] _subDir Subdirectory in OS _root, if desired + /// \param[in] _cleanup True to indicate that the filesystem should + /// be cleaned as part of the destructor + public: explicit TempDirectory(const std::string &_root, + const std::string &_prefix = "temp_dir", + const std::string &_subDir = "ignition", + bool _cleanup = true); + /// \brief Destroy the temporary directory, removing from filesystem /// if cleanup is true. public: ~TempDirectory(); diff --git a/src/TempDirectory.cc b/src/TempDirectory.cc index cf65b3a6..2a178b00 100644 --- a/src/TempDirectory.cc +++ b/src/TempDirectory.cc @@ -161,13 +161,22 @@ class ignition::common::TempDirectory::Implementation TempDirectory::TempDirectory(const std::string &_prefix, const std::string &_subDir, bool _cleanup): + TempDirectory(common::tempDirectoryPath(), _prefix, _subDir, _cleanup) +{ +} + +///////////////////////////////////////////////// +TempDirectory::TempDirectory(const std::string &_root, + const std::string &_prefix, + const std::string &_subDir, + bool _cleanup): dataPtr(ignition::utils::MakeUniqueImpl()) { this->dataPtr->oldPath = common::cwd(); this->dataPtr->doCleanup = _cleanup; - auto tempPath = common::tempDirectoryPath(); + auto tempPath = _root; if (!_subDir.empty()) { tempPath = common::joinPaths(tempPath, _subDir); @@ -181,6 +190,7 @@ TempDirectory::TempDirectory(const std::string &_prefix, this->dataPtr->path = common::cwd(); } + ///////////////////////////////////////////////// TempDirectory::~TempDirectory() { From 8d01233c306f0cbe699644740dcd3d71ed72b9da Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 22 Feb 2022 14:59:55 -0600 Subject: [PATCH 02/14] Add common::testing module Signed-off-by: Michael Carroll --- CMakeLists.txt | 2 +- .../include/ignition/common/CMakeLists.txt | 0 .../ignition/common/testing/AutoLogFixture.hh | 109 ++++++++++++++++ .../ignition/common/testing/BazelTestPaths.hh | 37 ++++++ .../ignition/common/testing/CMakeLists.txt | 2 + .../ignition/common/testing/CMakeTestPaths.hh | 37 ++++++ .../ignition/common/testing/TestPaths.hh | 118 ++++++++++++++++++ .../include/ignition/common/testing/Utils.hh | 59 +++++++++ testing/src/BazelTestPaths.cc | 53 ++++++++ testing/src/BazelTestPaths_TEST.cc | 90 +++++++++++++ testing/src/CMakeLists.txt | 14 +++ testing/src/CMakeTestPaths.cc | 44 +++++++ testing/src/CMakeTestPaths_TEST.cc | 98 +++++++++++++++ testing/src/TestPaths.cc | 96 ++++++++++++++ testing/test_files/example.txt | 0 15 files changed, 758 insertions(+), 1 deletion(-) create mode 100644 testing/include/ignition/common/CMakeLists.txt create mode 100644 testing/include/ignition/common/testing/AutoLogFixture.hh create mode 100644 testing/include/ignition/common/testing/BazelTestPaths.hh create mode 100644 testing/include/ignition/common/testing/CMakeLists.txt create mode 100644 testing/include/ignition/common/testing/CMakeTestPaths.hh create mode 100644 testing/include/ignition/common/testing/TestPaths.hh create mode 100644 testing/include/ignition/common/testing/Utils.hh create mode 100644 testing/src/BazelTestPaths.cc create mode 100644 testing/src/BazelTestPaths_TEST.cc create mode 100644 testing/src/CMakeLists.txt create mode 100644 testing/src/CMakeTestPaths.cc create mode 100644 testing/src/CMakeTestPaths_TEST.cc create mode 100644 testing/src/TestPaths.cc create mode 100644 testing/test_files/example.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index da71892b..1ac0fd7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,7 @@ configure_file("${PROJECT_SOURCE_DIR}/cppcheck.suppress.in" ${PROJECT_BINARY_DIR}/cppcheck.suppress) ign_configure_build(QUIT_IF_BUILD_ERRORS - COMPONENTS av events graphics profiler) + COMPONENTS av events graphics profiler testing) #============================================================================ # Create package information diff --git a/testing/include/ignition/common/CMakeLists.txt b/testing/include/ignition/common/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/include/ignition/common/testing/AutoLogFixture.hh b/testing/include/ignition/common/testing/AutoLogFixture.hh new file mode 100644 index 00000000..b6998754 --- /dev/null +++ b/testing/include/ignition/common/testing/AutoLogFixture.hh @@ -0,0 +1,109 @@ +/* +* Copyright (C) 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. +* +*/ +#ifndef IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_ +#define IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_ + +#include + +#include +#include + +#include "ignition/common/Console.hh" +#include "ignition/common/Filesystem.hh" +#include "ignition/common/TempDirectory.hh" +#include "ignition/common/Util.hh" + +namespace ignition::common::testing +{ +/// \brief A utility class that stores test logs in ~/.ignition/test_logs. +/// This functionality is needed to keep all the log information reported +/// by ignition during continuous integration. Without this, debugging +/// failing tests is significantly more difficult. +class AutoLogFixture : public ::testing::Test +{ + /// \brief Setup the test fixture. This gets called by gtest. + protected: virtual void SetUp() + { + const ::testing::TestInfo *const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + + std::string testName = testInfo->name(); + std::string testCaseName = testInfo->test_case_name(); + this->logFilename = testCaseName + "_" + testName + ".log"; + + this->temp = std::make_unique( + "test", "ign_common", true); + ASSERT_TRUE(this->temp->Valid()); + common::setenv(IGN_HOMEDIR, this->temp->Path()); + + // Initialize Console + ignLogInit(common::joinPaths(this->temp->Path(), "test_logs"), + this->logFilename); + + ignition::common::Console::SetVerbosity(4); + + // Read the full path to the log directory. + this->logDirectory = ignLogDirectory(); + } + + /// \brief Get a string with the full log file path. + /// \return The full log file path as a string. + protected: std::string FullLogPath() const + { + return ignition::common::joinPaths( + this->logDirectory, this->logFilename); + } + + /// \brief Get a string with all the log content loaded from the disk. + /// \return A string with all the log content. + protected: std::string LogContent() const + { + std::string loggedString; + // Open the log file, and read back the string + std::ifstream ifs(this->FullLogPath().c_str(), std::ios::in); + + while (!ifs.eof()) + { + std::string line; + std::getline(ifs, line); + loggedString += line; + } + return loggedString; + } + + /// \brief Default destructor. + public: virtual ~AutoLogFixture() + { + ignLogClose(); + EXPECT_TRUE(ignition::common::unsetenv(IGN_HOMEDIR)); + } + + /// \brief String with the full path of the logfile + private: std::string logFilename; + + /// \brief String with the full path to log directory + private: std::string logDirectory; + + /// \brief String with the base path to log directory + private: std::string logBasePath; + + /// \brief Temporary directory to run test in + private: std::unique_ptr temp; +}; +} // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_ diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh new file mode 100644 index 00000000..74a1fa13 --- /dev/null +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -0,0 +1,37 @@ +/* +* Copyright (C) 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. +* +*/ +#ifndef IGNITION_COMMON_TESTING_BAZELTESTPATHS_HH_ +#define IGNITION_COMMON_TESTING_BAZELTESTPATHS_HH_ + +#include + +#include "ignition/common/testing/TestPaths.hh" + +namespace ignition::common::testing +{ + +class BazelTestPaths: public TestPaths +{ + public: using TestPaths::TestPaths; + public: ~BazelTestPaths() override; + public: bool ProjectSourcePath(std::string &_sourceDir) override; + public: bool TestTmpPath(std::string &_tmpDir) override; +}; + +} // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_ diff --git a/testing/include/ignition/common/testing/CMakeLists.txt b/testing/include/ignition/common/testing/CMakeLists.txt new file mode 100644 index 00000000..06f5b9aa --- /dev/null +++ b/testing/include/ignition/common/testing/CMakeLists.txt @@ -0,0 +1,2 @@ + +ign_install_all_headers(COMPONENT testing) diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh new file mode 100644 index 00000000..8adbad50 --- /dev/null +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -0,0 +1,37 @@ +/* +* Copyright (C) 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. +* +*/ +#ifndef IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_ +#define IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_ + +#include + +#include "ignition/common/testing/TestPaths.hh" + +namespace ignition::common::testing +{ + +class CMakeTestPaths: public TestPaths +{ + public: using TestPaths::TestPaths; + public: ~CMakeTestPaths() override; + public: bool ProjectSourcePath(std::string &_sourceDir) override; + public: bool TestTmpPath(std::string &_tmpDir) override; +}; + +} // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_ diff --git a/testing/include/ignition/common/testing/TestPaths.hh b/testing/include/ignition/common/testing/TestPaths.hh new file mode 100644 index 00000000..bec6968e --- /dev/null +++ b/testing/include/ignition/common/testing/TestPaths.hh @@ -0,0 +1,118 @@ +/* +* Copyright (C) 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. +* +*/ +#ifndef IGNITION_COMMON_TESTING_TESTPATHS_HH_ +#define IGNITION_COMMON_TESTING_TESTPATHS_HH_ + +#include +#include + +#include "ignition/common/Filesystem.hh" +#include "ignition/common/TempDirectory.hh" +#include "ignition/common/Util.hh" + +#ifndef TESTING_PROJECT_SOURCE_DIR +#define TESTING_PROJECT_SOURCE_DIR "" +#endif + +namespace ignition::common::testing +{ + +////////////////////////////////////////////////// +constexpr char kTestingProjectSourceDir[] = TESTING_PROJECT_SOURCE_DIR; + +////////////////////////////////////////////////// +enum class BuildType +{ + kUnknown, + kCMake, + kBazel +}; + +////////////////////////////////////////////////// +class TestPaths +{ + public: explicit TestPaths(const std::string &_projectSourcePath = + kTestingProjectSourceDir); + public: virtual ~TestPaths() = 0; + public: virtual bool ProjectSourcePath(std::string &_sourceDir) = 0; + public: virtual bool TestTmpPath(std::string &_tmpDir) = 0; + + protected: std::string projectSourcePath; +}; + +////////////////////////////////////////////////// +std::shared_ptr +MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, + const std::string &_prefix = "test", + const std::string &_subDir = "ignition", + bool _cleanup = true); + + +////////////////////////////////////////////////// +inline std::shared_ptr +MakeTestTempDirectory(const std::string &_prefix = "test", + const std::string &_subDir = "ignition", + bool _cleanup = true) +{ + return MakeTestTempDirectoryImpl(kTestingProjectSourceDir, + _prefix, + _subDir, + _cleanup); +} + +////////////////////////////////////////////////// +BuildType +TestBuildType( + const std::string &_projectSourcePath = kTestingProjectSourceDir); + +////////////////////////////////////////////////// +std::unique_ptr +TestPathFactory( + const std::string &_projectSourcePath = kTestingProjectSourceDir); + +////////////////////////////////////////////////// +template +std::string SourceFile(Args const &... args) +{ + auto testPaths = TestPathFactory(kTestingProjectSourceDir); + assert(nullptr != testPaths); + + std::string dataDir; + testPaths->ProjectSourcePath(dataDir); + return common::joinPaths(dataDir, args...); +} + +////////////////////////////////////////////////// +template +std::string TestFile(Args const &... args) +{ + return SourceFile("test", args...); +} + +////////////////////////////////////////////////// +template +std::string TempPath(Args const &... args) +{ + auto testPaths = TestPathFactory(kTestingProjectSourceDir); + std::string dataDir; + testPaths->TestTmpPath(dataDir); + return common::joinPaths(dataDir, args...); +} + +} // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_TESTPATHS_HH_ diff --git a/testing/include/ignition/common/testing/Utils.hh b/testing/include/ignition/common/testing/Utils.hh new file mode 100644 index 00000000..16c1e5f5 --- /dev/null +++ b/testing/include/ignition/common/testing/Utils.hh @@ -0,0 +1,59 @@ +/* +* Copyright (C) 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. +* +*/ +#ifndef IGNITION_COMMON_TESTING_UTILS_HH_ +#define IGNITION_COMMON_TESTING_UTILS_HH_ + +#include +#include +#include +#include +#include + +namespace ignition::common::testing +{ + +/// \brief Get a random number based on an integer converted to string. +/// \return A random integer converted to string. +std::string getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX) +{ + // Initialize random number generator. + uint32_t seed = std::random_device {}(); + std::mt19937 randGenerator(seed); + + // Create a random number based on an integer converted to string. + std::uniform_int_distribution d(_min, _max); + + return std::to_string(d(randGenerator)); +} + +///////////////////////////////////////////////// +bool create_new_empty_file(const std::string &_filename) +{ + try + { + std::fstream fs(_filename, std::ios::out); + } + catch(...) + { + return false; + } + return true; +} + +} // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_TESTPATHS_HH_ diff --git a/testing/src/BazelTestPaths.cc b/testing/src/BazelTestPaths.cc new file mode 100644 index 00000000..f3cb43a3 --- /dev/null +++ b/testing/src/BazelTestPaths.cc @@ -0,0 +1,53 @@ +/* +* Copyright (C) 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 "ignition/common/testing/BazelTestPaths.hh" + +#include +#include + +namespace ignition::common::testing +{ + +////////////////////////////////////////////////// +BazelTestPaths::~BazelTestPaths() = default; + +////////////////////////////////////////////////// +bool BazelTestPaths::ProjectSourcePath(std::string &_sourceDir) { + std::string test_srcdir, bazel_path; + + if (common::env("TEST_SRCDIR", test_srcdir) && + common::env("IGN_BAZEL_PATH", bazel_path)) + { + _sourceDir = ignition::common::joinPaths(test_srcdir, + "ignition", + bazel_path); + return true; + } + else + { + return false; + } +} + +////////////////////////////////////////////////// +bool BazelTestPaths::TestTmpPath(std::string &_tmpDir) { + return common::env("TEST_UNDECLARED_OUTPUTS_DIR", _tmpDir); +} + +} // namespace ignition::common::testing + diff --git a/testing/src/BazelTestPaths_TEST.cc b/testing/src/BazelTestPaths_TEST.cc new file mode 100644 index 00000000..a88c7d7a --- /dev/null +++ b/testing/src/BazelTestPaths_TEST.cc @@ -0,0 +1,90 @@ +/* + * Copyright (C) 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 "ignition/common/Filesystem.hh" +#include "ignition/common/testing/TestPaths.hh" +#include "ignition/common/testing/BazelTestPaths.hh" + +using namespace ignition::common; + +char **kEnv; + +///////////////////////////////////////////////// +TEST(TestPaths, DISABLED_DumpEnv) +{ + for (char **env = kEnv ; *env != nullptr; env++) + { + char *varName = *env; + printf("%s\n", varName); + } +} + +///////////////////////////////////////////////// +TEST(BazelTestPaths, ProjectSourcePath) +{ + ignition::common::testing::BazelTestPaths testPaths; + + std::string sourceDir; + ASSERT_TRUE(testPaths.ProjectSourcePath(sourceDir)); + ASSERT_FALSE(sourceDir.empty()); + ASSERT_TRUE(exists(sourceDir)) << sourceDir; + ASSERT_TRUE(isDirectory(sourceDir)); + + auto installedDir = joinPaths(sourceDir, "testing", "test_files"); + EXPECT_TRUE(exists(installedDir)) << installedDir; + EXPECT_TRUE(isDirectory(installedDir)); + + auto installedFile = joinPaths(installedDir, "example.txt"); + EXPECT_TRUE(exists(installedFile)); + EXPECT_TRUE(isFile(installedFile)); +} + +///////////////////////////////////////////////// +TEST(BazelTestPaths, TestTmpPath) +{ + ignition::common::testing::BazelTestPaths testPaths; + + std::string tmpDir; + ASSERT_TRUE(testPaths.TestTmpPath(tmpDir)); + ASSERT_FALSE(tmpDir.empty()); + ASSERT_TRUE(exists(tmpDir)) << tmpDir; + ASSERT_TRUE(isDirectory(tmpDir)); +} + +///////////////////////////////////////////////// +TEST(BazelTestPaths, TestBuildType) +{ + using BuildType = ignition::common::testing::BuildType; + ASSERT_EQ(BuildType::kBazel, ignition::common::testing::TestBuildType()); +} + +///////////////////////////////////////////////// +TEST(BazelTestPaths, TestPathFactory) +{ + auto testPaths = ignition::common::testing::TestPathFactory(); + ASSERT_NE(nullptr, testPaths); +} + +///////////////////////////////////////////////// +int main(int argc, char **argv, char **envp) +{ + kEnv = envp; + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/testing/src/CMakeLists.txt b/testing/src/CMakeLists.txt new file mode 100644 index 00000000..fcd00b32 --- /dev/null +++ b/testing/src/CMakeLists.txt @@ -0,0 +1,14 @@ +set(sources + TestPaths.cc + CMakeTestPaths.cc + BazelTestPaths.cc +) + +set(test_sources + CMakeTestPaths_TEST.cc +) + +ign_add_component(testing SOURCES ${sources} GET_TARGET_NAME testing_target) + +ign_build_tests(TYPE UNIT SOURCES ${test_sources} + LIB_DEPS ${testing_target}) diff --git a/testing/src/CMakeTestPaths.cc b/testing/src/CMakeTestPaths.cc new file mode 100644 index 00000000..81612639 --- /dev/null +++ b/testing/src/CMakeTestPaths.cc @@ -0,0 +1,44 @@ +/* +* Copyright (C) 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 "ignition/common/testing/CMakeTestPaths.hh" + +namespace ignition::common::testing +{ + +////////////////////////////////////////////////// +CMakeTestPaths::~CMakeTestPaths() = default; + +////////////////////////////////////////////////// +bool CMakeTestPaths::ProjectSourcePath(std::string &_sourceDir) { + + if (!projectSourcePath.empty()) + { + _sourceDir = projectSourcePath; + return true; + } + + return false; +} + +////////////////////////////////////////////////// +bool CMakeTestPaths::TestTmpPath(std::string &_tmpDir) { + _tmpDir = ignition::common::tempDirectoryPath(); + return true; +} + +} // namespace ignition::common::testing diff --git a/testing/src/CMakeTestPaths_TEST.cc b/testing/src/CMakeTestPaths_TEST.cc new file mode 100644 index 00000000..f18aa0a8 --- /dev/null +++ b/testing/src/CMakeTestPaths_TEST.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 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 "ignition/common/Filesystem.hh" +#include "ignition/common/testing/TestPaths.hh" +#include "ignition/common/testing/CMakeTestPaths.hh" + +using namespace ignition::common; +using namespace ignition::common::testing; + +constexpr char kFakeTestPaths[] = ""; + +///////////////////////////////////////////////// +TEST(TestPaths, ProjectSourcePathUnset) +{ + EXPECT_EQ(BuildType::kUnknown, TestBuildType(kFakeTestPaths)); + + auto testPaths = TestPathFactory(kFakeTestPaths); + EXPECT_EQ(nullptr, testPaths); + + auto tempDir = MakeTestTempDirectoryImpl(kFakeTestPaths); + EXPECT_EQ(nullptr, tempDir); +} + +///////////////////////////////////////////////// +TEST(CMakeTestPaths, TestingProjectSourceDir) +{ + ASSERT_NE(0u, strlen(ignition::common::testing::kTestingProjectSourceDir)); +} + +///////////////////////////////////////////////// +TEST(CMakeTestPaths, ProjectSourcePathUnset) +{ + ignition::common::testing::CMakeTestPaths testPaths(kFakeTestPaths); + std::string sourceDir; + EXPECT_FALSE(testPaths.ProjectSourcePath(sourceDir)); + EXPECT_TRUE(sourceDir.empty()); +} + +///////////////////////////////////////////////// +TEST(CMakeTestPaths, TestBuildType) +{ + ASSERT_EQ(BuildType::kCMake, ignition::common::testing::TestBuildType()); +} + +///////////////////////////////////////////////// +TEST(CMakeTestPaths, ProjectSourcePath) +{ + ignition::common::testing::CMakeTestPaths testPaths; + + std::string sourceDir; + ASSERT_TRUE(testPaths.ProjectSourcePath(sourceDir)); + ASSERT_FALSE(sourceDir.empty()); + ASSERT_TRUE(exists(sourceDir)) << sourceDir; + ASSERT_TRUE(isDirectory(sourceDir)); + + auto installedDir = joinPaths(sourceDir, "testing", "test_files"); + EXPECT_TRUE(exists(installedDir)) << installedDir; + EXPECT_TRUE(isDirectory(installedDir)); + + auto installedFile = joinPaths(installedDir, "example.txt"); + EXPECT_TRUE(exists(installedFile)); + EXPECT_TRUE(isFile(installedFile)); +} + +///////////////////////////////////////////////// +TEST(CMakeTestPaths, TestTmpPath) +{ + ignition::common::testing::CMakeTestPaths testPaths; + + std::string tmpDir; + ASSERT_TRUE(testPaths.TestTmpPath(tmpDir)); + ASSERT_FALSE(tmpDir.empty()); + ASSERT_TRUE(exists(tmpDir)) << tmpDir; + ASSERT_TRUE(isDirectory(tmpDir)); +} + +///////////////////////////////////////////////// +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/testing/src/TestPaths.cc b/testing/src/TestPaths.cc new file mode 100644 index 00000000..80c57375 --- /dev/null +++ b/testing/src/TestPaths.cc @@ -0,0 +1,96 @@ +/* +* Copyright (C) 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 "ignition/common/testing/TestPaths.hh" +#include "ignition/common/testing/BazelTestPaths.hh" +#include "ignition/common/testing/CMakeTestPaths.hh" + +#include +#include + +namespace ignition::common::testing +{ +////////////////////////////////////////////////// +TestPaths::TestPaths(const std::string &_projectSourcePath) + : projectSourcePath(_projectSourcePath) +{ +} + +////////////////////////////////////////////////// +TestPaths::~TestPaths() = default; + +////////////////////////////////////////////////// +BuildType TestBuildType(const std::string &_projectSourcePath) +{ + std::string ign_bazel; + bool ign_bazel_set = common::env("IGN_BAZEL", ign_bazel); + bool ign_cmake_set = !_projectSourcePath.empty(); + + if (ign_bazel_set) + return BuildType::kBazel; + else if (ign_cmake_set) + return BuildType::kCMake; + else + return BuildType::kUnknown; +} + +////////////////////////////////////////////////// +std::unique_ptr +TestPathFactory(const std::string &_projectSourcePath) +{ + std::unique_ptr ret {nullptr}; + + switch(TestBuildType(_projectSourcePath)) + { + case BuildType::kBazel: + ret = std::make_unique(_projectSourcePath); + break; + case BuildType::kCMake: + ret = std::make_unique(_projectSourcePath); + break; + case BuildType::kUnknown: + ret = nullptr; + break; + default: + ret = nullptr; + break; + } + return ret; +} + +////////////////////////////////////////////////// +std::shared_ptr +MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, + const std::string &_prefix, + const std::string &_subDir, + bool _cleanup) +{ + auto testPaths = TestPathFactory(_projectSourcePath); + + if (!testPaths) + return nullptr; + + std::string dataDir; + testPaths->TestTmpPath(dataDir); + + if (dataDir.empty()) + return nullptr; + + return std::make_shared( + dataDir, _prefix, _subDir, _cleanup); +} + +} // namespace ignition::common::testing diff --git a/testing/test_files/example.txt b/testing/test_files/example.txt new file mode 100644 index 00000000..e69de29b From 4d1246c3d51996af0bc54bf538af25bd7371c8ca Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 15 Mar 2022 13:09:09 -0500 Subject: [PATCH 03/14] Address reviewer feedback Signed-off-by: Michael Carroll --- av/src/AudioDecoder.cc | 2 +- src/TempDirectory.cc | 2 +- src/TempDirectory_TEST.cc | 16 +++ .../ignition/common/testing/AutoLogFixture.hh | 74 ++---------- .../ignition/common/testing/BazelTestPaths.hh | 18 +++ .../ignition/common/testing/CMakeTestPaths.hh | 14 ++- .../ignition/common/testing/TestPaths.hh | 77 ++++++++++++- .../include/ignition/common/testing/Utils.hh | 32 ++---- testing/src/AutoLogFixture.cc | 106 ++++++++++++++++++ testing/src/AutoLogFixture_TEST.cc | 34 ++++++ testing/src/BazelTestPaths.cc | 6 +- testing/src/BazelTestPaths_TEST.cc | 21 ---- testing/src/CMakeLists.txt | 8 +- testing/src/CMakeTestPaths.cc | 10 +- testing/src/Utils.cc | 53 +++++++++ testing/src/Utils_TEST.cc | 60 ++++++++++ 16 files changed, 409 insertions(+), 124 deletions(-) create mode 100644 testing/src/AutoLogFixture.cc create mode 100644 testing/src/AutoLogFixture_TEST.cc create mode 100644 testing/src/Utils.cc create mode 100644 testing/src/Utils_TEST.cc diff --git a/av/src/AudioDecoder.cc b/av/src/AudioDecoder.cc index b639317c..cf62e6d8 100644 --- a/av/src/AudioDecoder.cc +++ b/av/src/AudioDecoder.cc @@ -269,7 +269,7 @@ bool AudioDecoder::SetFile(const std::string &_filename) #endif // Open codec - if (avcodec_open2(this->dataPtr->codecCtx, + if (avcodec_open2(this->dataPtr->codecCtx, this->dataPtr->codec, nullptr) < 0) { ignerr << "Couldn't open audio codec.\n"; diff --git a/src/TempDirectory.cc b/src/TempDirectory.cc index 2a178b00..10497981 100644 --- a/src/TempDirectory.cc +++ b/src/TempDirectory.cc @@ -176,7 +176,7 @@ TempDirectory::TempDirectory(const std::string &_root, this->dataPtr->oldPath = common::cwd(); this->dataPtr->doCleanup = _cleanup; - auto tempPath = _root; + auto tempPath = _root; if (!_subDir.empty()) { tempPath = common::joinPaths(tempPath, _subDir); diff --git a/src/TempDirectory_TEST.cc b/src/TempDirectory_TEST.cc index a0c3ad7b..6d2f9679 100644 --- a/src/TempDirectory_TEST.cc +++ b/src/TempDirectory_TEST.cc @@ -77,6 +77,22 @@ TEST(TempDirectory, TempDirectory) EXPECT_FALSE(ignition::common::exists(path)); } +///////////////////////////////////////////////// +TEST(TempDirectory, TempDirectoryRoot) +{ + std::string path; + { + auto p = ignition::common::tempDirectoryPath(); + ignition::common::TempDirectory tmp(p, "temp_dir", "ignition", true); + EXPECT_TRUE(tmp.Valid()); + EXPECT_TRUE(tmp.DoCleanup()); + path = tmp.Path(); + EXPECT_FALSE(path.empty()); + EXPECT_TRUE(ignition::common::exists(path)); + } + EXPECT_FALSE(ignition::common::exists(path)); +} + ///////////////////////////////////////////////// TEST(TempDirectory, TempDirectoryNoClean) { diff --git a/testing/include/ignition/common/testing/AutoLogFixture.hh b/testing/include/ignition/common/testing/AutoLogFixture.hh index b6998754..348c665f 100644 --- a/testing/include/ignition/common/testing/AutoLogFixture.hh +++ b/testing/include/ignition/common/testing/AutoLogFixture.hh @@ -22,10 +22,7 @@ #include #include -#include "ignition/common/Console.hh" -#include "ignition/common/Filesystem.hh" -#include "ignition/common/TempDirectory.hh" -#include "ignition/common/Util.hh" +#include namespace ignition::common::testing { @@ -35,74 +32,25 @@ namespace ignition::common::testing /// failing tests is significantly more difficult. class AutoLogFixture : public ::testing::Test { - /// \brief Setup the test fixture. This gets called by gtest. - protected: virtual void SetUp() - { - const ::testing::TestInfo *const testInfo = - ::testing::UnitTest::GetInstance()->current_test_info(); - - std::string testName = testInfo->name(); - std::string testCaseName = testInfo->test_case_name(); - this->logFilename = testCaseName + "_" + testName + ".log"; - - this->temp = std::make_unique( - "test", "ign_common", true); - ASSERT_TRUE(this->temp->Valid()); - common::setenv(IGN_HOMEDIR, this->temp->Path()); + /// \brief Constructor + public: AutoLogFixture(); - // Initialize Console - ignLogInit(common::joinPaths(this->temp->Path(), "test_logs"), - this->logFilename); + /// \brief Destructor + public: virtual ~AutoLogFixture(); - ignition::common::Console::SetVerbosity(4); - - // Read the full path to the log directory. - this->logDirectory = ignLogDirectory(); - } + /// \brief Setup the test fixture. This gets called by gtest. + protected: virtual void SetUp() override; /// \brief Get a string with the full log file path. /// \return The full log file path as a string. - protected: std::string FullLogPath() const - { - return ignition::common::joinPaths( - this->logDirectory, this->logFilename); - } + protected: std::string FullLogPath() const; /// \brief Get a string with all the log content loaded from the disk. /// \return A string with all the log content. - protected: std::string LogContent() const - { - std::string loggedString; - // Open the log file, and read back the string - std::ifstream ifs(this->FullLogPath().c_str(), std::ios::in); - - while (!ifs.eof()) - { - std::string line; - std::getline(ifs, line); - loggedString += line; - } - return loggedString; - } - - /// \brief Default destructor. - public: virtual ~AutoLogFixture() - { - ignLogClose(); - EXPECT_TRUE(ignition::common::unsetenv(IGN_HOMEDIR)); - } - - /// \brief String with the full path of the logfile - private: std::string logFilename; - - /// \brief String with the full path to log directory - private: std::string logDirectory; - - /// \brief String with the base path to log directory - private: std::string logBasePath; + protected: std::string LogContent() const; - /// \brief Temporary directory to run test in - private: std::unique_ptr temp; + /// \brief Pointer to private data. + IGN_UTILS_UNIQUE_IMPL_PTR(dataPtr) }; } // namespace ignition::common::testing diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh index 74a1fa13..0477a8c1 100644 --- a/testing/include/ignition/common/testing/BazelTestPaths.hh +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -24,11 +24,29 @@ namespace ignition::common::testing { +/// \brief Implementation of TestPaths interface for Bazel +/// +/// It is not intended that users will directly construct this, but rather +/// utilize the TestPathFactory. +/// +/// The main mechanism for detecting a bazel build is via the presence of the +/// TEST_SRCDIR and TEST_UNDECLARED_OUTPUTS_DIR environment variables. +/// Additionally, tests built via ign-bazel should set IGN_BAZEL_DIR. +/// +/// For source files to be available for bazel builds, they need to be set in +/// the "data" section of the relevant cc_library or cc_test call. class BazelTestPaths: public TestPaths { + /// \brief Constructor from TestPaths public: using TestPaths::TestPaths; + + /// \brief Destructor public: ~BazelTestPaths() override; + + /// Documentation inherited public: bool ProjectSourcePath(std::string &_sourceDir) override; + + /// Documentation inherited public: bool TestTmpPath(std::string &_tmpDir) override; }; diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh index 8adbad50..c575186a 100644 --- a/testing/include/ignition/common/testing/CMakeTestPaths.hh +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -23,15 +23,23 @@ namespace ignition::common::testing { - +/// \brief Implementation of TestPaths interface for CMake +/// +/// It is not intended that users will directly construct this, but rather +/// utilize the TestPathFactory. class CMakeTestPaths: public TestPaths { + /// \brief Constructor from TestPaths public: using TestPaths::TestPaths; + + /// \brief Destructor public: ~CMakeTestPaths() override; + + /// Documentation inherited public: bool ProjectSourcePath(std::string &_sourceDir) override; + + /// Documentation inherited public: bool TestTmpPath(std::string &_tmpDir) override; }; - } // namespace ignition::common::testing - #endif // IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_ diff --git a/testing/include/ignition/common/testing/TestPaths.hh b/testing/include/ignition/common/testing/TestPaths.hh index bec6968e..d012eb29 100644 --- a/testing/include/ignition/common/testing/TestPaths.hh +++ b/testing/include/ignition/common/testing/TestPaths.hh @@ -32,9 +32,18 @@ namespace ignition::common::testing { ////////////////////////////////////////////////// +/// \brief Constant referring to the project source dir of the current +/// project. +/// +/// For CMake builds, it is expected that this is injected via a +/// buildsystem define of TESTING_PROJECT_SOURCE_DIR. +/// This is done automatically for tests using ign-cmake's ign_build_tests +/// +/// For Bazel builds, it is expected to be empty constexpr char kTestingProjectSourceDir[] = TESTING_PROJECT_SOURCE_DIR; ////////////////////////////////////////////////// +/// \brief List of buildsystem types enum class BuildType { kUnknown, @@ -43,18 +52,45 @@ enum class BuildType }; ////////////////////////////////////////////////// +/// \brief Helper interface to generate path information to support +/// test access to source/data files +/// +/// It is intended that there is an implementation of this interface for +/// each relevant buildsystem. class TestPaths { + /// \brief Constructor public: explicit TestPaths(const std::string &_projectSourcePath = kTestingProjectSourceDir); + + /// \brief Destructor public: virtual ~TestPaths() = 0; + + /// brief Populate the path to the root project source directory + /// \param[out] _sourceDir path to the root project source directory + /// \return True if path successfully found and set, false otherwise public: virtual bool ProjectSourcePath(std::string &_sourceDir) = 0; + + /// \brief Populate the path to a temporary directory + /// \param[out] _tmpDir path to the root temporary directory + /// \return True if path successfully found and set, false otherwise public: virtual bool TestTmpPath(std::string &_tmpDir) = 0; + /// \brief Path to the root of the project source protected: std::string projectSourcePath; }; ////////////////////////////////////////////////// +/// \brief Implementation of MakeTestTempDirectory +/// +/// The TempDirectory will have the form $TMPDIR/_subdir/_prefixXXXXX/ +/// +/// \param[in] _projectSourcePath Root of project source or empty +/// \param[in] _prefix Prefix of the temporary directory +/// \param[in] _subDir Additional subdirectory for temporary directory +/// \param[in] _cleanup True to indicate that the filesystem should +/// be cleaned as part of the destructor +/// \return Shared pointer to TempDirectory std::shared_ptr MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, const std::string &_prefix = "test", @@ -63,6 +99,16 @@ MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, ////////////////////////////////////////////////// +/// \brief Create a temporary directory for test output in an OS and build +/// appropriate location +/// +/// The TempDirectory will have the form $TMPDIR/_subdir/_prefixXXXXX/ +/// +/// \param[in] _prefix Prefix of the temporary directory +/// \param[in] _subDir Additional subdirectory for temporary directory +/// \param[in] _cleanup True to indicate that the filesystem should +/// be cleaned as part of the destructor +/// \return Shared pointer to TempDirectory inline std::shared_ptr MakeTestTempDirectory(const std::string &_prefix = "test", const std::string &_subDir = "ignition", @@ -75,16 +121,31 @@ MakeTestTempDirectory(const std::string &_prefix = "test", } ////////////////////////////////////////////////// +/// \brief Return the current build type +/// +/// \param[in] _projectSourcePath Root of project source or empty +/// \return The current build type BuildType TestBuildType( const std::string &_projectSourcePath = kTestingProjectSourceDir); ////////////////////////////////////////////////// +/// \brief Get a TestPaths object for the current build type +/// +/// \param[in] _projectSourcePath Root of project source or empty +/// \return TestPaths implementation for the current build type std::unique_ptr TestPathFactory( const std::string &_projectSourcePath = kTestingProjectSourceDir); ////////////////////////////////////////////////// +/// \brief Get the path to a file in the project source tree +/// +/// Example: to get ign-common/test/data/box.dae +/// SourceFile("test", "data", "box.dae"); +/// +/// \param[in] args Relative path to the source file +/// \return Full path to the source file template std::string SourceFile(Args const &... args) { @@ -97,6 +158,13 @@ std::string SourceFile(Args const &... args) } ////////////////////////////////////////////////// +/// \brief Get the path to a file in the project test directory tree +/// +/// Example: to get ign-common/test/data/box.dae +/// TestFile("data", "box.dae"); +/// +/// \param[in] args Path to the file, relative to the test directory +/// \return Full path to the source file template std::string TestFile(Args const &... args) { @@ -104,6 +172,13 @@ std::string TestFile(Args const &... args) } ////////////////////////////////////////////////// +/// \brief Get the path to a file in a temporary directory +/// +/// Example: to get ${TMP}/.ignition/foo.log +/// TempPath(".ignition", "foo.log"); +/// +/// \param[in] args Path to the file, relative to the temporary directory +/// \return Full path to the temporary directory template std::string TempPath(Args const &... args) { @@ -112,7 +187,5 @@ std::string TempPath(Args const &... args) testPaths->TestTmpPath(dataDir); return common::joinPaths(dataDir, args...); } - } // namespace ignition::common::testing - #endif // IGNITION_COMMON_TESTING_TESTPATHS_HH_ diff --git a/testing/include/ignition/common/testing/Utils.hh b/testing/include/ignition/common/testing/Utils.hh index 16c1e5f5..a70c2812 100644 --- a/testing/include/ignition/common/testing/Utils.hh +++ b/testing/include/ignition/common/testing/Utils.hh @@ -19,40 +19,22 @@ #include #include -#include -#include #include namespace ignition::common::testing { +///////////////////////////////////////////////// /// \brief Get a random number based on an integer converted to string. /// \return A random integer converted to string. -std::string getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX) -{ - // Initialize random number generator. - uint32_t seed = std::random_device {}(); - std::mt19937 randGenerator(seed); - - // Create a random number based on an integer converted to string. - std::uniform_int_distribution d(_min, _max); - - return std::to_string(d(randGenerator)); -} +std::string getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX); ///////////////////////////////////////////////// -bool create_new_empty_file(const std::string &_filename) -{ - try - { - std::fstream fs(_filename, std::ios::out); - } - catch(...) - { - return false; - } - return true; -} +/// \brief Create an empty file with no content +/// +/// \param[in] _filename Filename of the file to be created +/// \return true if file successfully created, false otherwise +bool createNewEmptyFile(const std::string &_filename); } // namespace ignition::common::testing diff --git a/testing/src/AutoLogFixture.cc b/testing/src/AutoLogFixture.cc new file mode 100644 index 00000000..9fc80b5b --- /dev/null +++ b/testing/src/AutoLogFixture.cc @@ -0,0 +1,106 @@ +/* +* Copyright (C) 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 "ignition/common/testing/AutoLogFixture.hh" + +#include +#include +#include +#include + +namespace ignition::common::testing +{ + +////////////////////////////////////////////////// +class AutoLogFixture::Implementation +{ + /// \brief String with the full path of the logfile + public: std::string logFilename; + + /// \brief String with the full path to log directory + public: std::string logDirectory; + + /// \brief String with the base path to log directory + public: std::string logBasePath; + + /// \brief Temporary directory to run test in + public: std::unique_ptr temp; +}; + + +////////////////////////////////////////////////// +AutoLogFixture::AutoLogFixture(): + dataPtr(ignition::utils::MakeUniqueImpl()) +{ +} + +////////////////////////////////////////////////// +AutoLogFixture::~AutoLogFixture() +{ + ignLogClose(); + EXPECT_TRUE(ignition::common::unsetenv(IGN_HOMEDIR)); +} + +////////////////////////////////////////////////// +void AutoLogFixture::SetUp() +{ + const ::testing::TestInfo *const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + + std::string testName = testInfo->name(); + std::string testCaseName = testInfo->test_case_name(); + this->dataPtr->logFilename = testCaseName + "_" + testName + ".log"; + + this->dataPtr->temp = std::make_unique( + "test", "ign_common", true); + ASSERT_TRUE(this->dataPtr->temp->Valid()); + common::setenv(IGN_HOMEDIR, this->dataPtr->temp->Path()); + + // Initialize Console + ignLogInit(common::joinPaths(this->dataPtr->temp->Path(), "test_logs"), + this->dataPtr->logFilename); + + ignition::common::Console::SetVerbosity(4); + + // Read the full path to the log directory. + this->dataPtr->logDirectory = ignLogDirectory(); +} + +////////////////////////////////////////////////// +std::string AutoLogFixture::FullLogPath() const +{ + return ignition::common::joinPaths( + this->dataPtr->logDirectory, this->dataPtr->logFilename); +} + +////////////////////////////////////////////////// +std::string AutoLogFixture::LogContent() const +{ + std::string loggedString; + // Open the log file, and read back the string + std::ifstream ifs(this->FullLogPath().c_str(), std::ios::in); + + while (!ifs.eof()) + { + std::string line; + std::getline(ifs, line); + loggedString += line; + } + return loggedString; +} + +} // namespace ignition::common::testing diff --git a/testing/src/AutoLogFixture_TEST.cc b/testing/src/AutoLogFixture_TEST.cc new file mode 100644 index 00000000..c2118c69 --- /dev/null +++ b/testing/src/AutoLogFixture_TEST.cc @@ -0,0 +1,34 @@ +/* + * Copyright (C) 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 + +using namespace ignition::common; +using namespace ignition::common::testing; + +///////////////////////////////////////////////// +TEST_F(AutoLogFixture, AutoLogFixture) +{ + EXPECT_FALSE(this->FullLogPath().empty()); + EXPECT_TRUE(this->LogContent().empty()); + + Console::SetVerbosity(0); + igndbg << "This is a debug" << std::endl; + EXPECT_FALSE(this->LogContent().empty()); +} diff --git a/testing/src/BazelTestPaths.cc b/testing/src/BazelTestPaths.cc index f3cb43a3..c355df0f 100644 --- a/testing/src/BazelTestPaths.cc +++ b/testing/src/BazelTestPaths.cc @@ -27,7 +27,8 @@ namespace ignition::common::testing BazelTestPaths::~BazelTestPaths() = default; ////////////////////////////////////////////////// -bool BazelTestPaths::ProjectSourcePath(std::string &_sourceDir) { +bool BazelTestPaths::ProjectSourcePath(std::string &_sourceDir) +{ std::string test_srcdir, bazel_path; if (common::env("TEST_SRCDIR", test_srcdir) && @@ -45,7 +46,8 @@ bool BazelTestPaths::ProjectSourcePath(std::string &_sourceDir) { } ////////////////////////////////////////////////// -bool BazelTestPaths::TestTmpPath(std::string &_tmpDir) { +bool BazelTestPaths::TestTmpPath(std::string &_tmpDir) +{ return common::env("TEST_UNDECLARED_OUTPUTS_DIR", _tmpDir); } diff --git a/testing/src/BazelTestPaths_TEST.cc b/testing/src/BazelTestPaths_TEST.cc index a88c7d7a..f0ea20a6 100644 --- a/testing/src/BazelTestPaths_TEST.cc +++ b/testing/src/BazelTestPaths_TEST.cc @@ -22,18 +22,6 @@ using namespace ignition::common; -char **kEnv; - -///////////////////////////////////////////////// -TEST(TestPaths, DISABLED_DumpEnv) -{ - for (char **env = kEnv ; *env != nullptr; env++) - { - char *varName = *env; - printf("%s\n", varName); - } -} - ///////////////////////////////////////////////// TEST(BazelTestPaths, ProjectSourcePath) { @@ -79,12 +67,3 @@ TEST(BazelTestPaths, TestPathFactory) auto testPaths = ignition::common::testing::TestPathFactory(); ASSERT_NE(nullptr, testPaths); } - -///////////////////////////////////////////////// -int main(int argc, char **argv, char **envp) -{ - kEnv = envp; - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - diff --git a/testing/src/CMakeLists.txt b/testing/src/CMakeLists.txt index fcd00b32..65770182 100644 --- a/testing/src/CMakeLists.txt +++ b/testing/src/CMakeLists.txt @@ -1,11 +1,15 @@ set(sources - TestPaths.cc - CMakeTestPaths.cc + AutoLogFixture.cc BazelTestPaths.cc + CMakeTestPaths.cc + TestPaths.cc + Utils.cc ) set(test_sources + AutoLogFixture_TEST.cc CMakeTestPaths_TEST.cc + Utils_TEST.cc ) ign_add_component(testing SOURCES ${sources} GET_TARGET_NAME testing_target) diff --git a/testing/src/CMakeTestPaths.cc b/testing/src/CMakeTestPaths.cc index 81612639..cf9f69c1 100644 --- a/testing/src/CMakeTestPaths.cc +++ b/testing/src/CMakeTestPaths.cc @@ -24,11 +24,12 @@ namespace ignition::common::testing CMakeTestPaths::~CMakeTestPaths() = default; ////////////////////////////////////////////////// -bool CMakeTestPaths::ProjectSourcePath(std::string &_sourceDir) { +bool CMakeTestPaths::ProjectSourcePath(std::string &_sourceDir) +{ - if (!projectSourcePath.empty()) + if (!this->projectSourcePath.empty()) { - _sourceDir = projectSourcePath; + _sourceDir = this->projectSourcePath; return true; } @@ -36,7 +37,8 @@ bool CMakeTestPaths::ProjectSourcePath(std::string &_sourceDir) { } ////////////////////////////////////////////////// -bool CMakeTestPaths::TestTmpPath(std::string &_tmpDir) { +bool CMakeTestPaths::TestTmpPath(std::string &_tmpDir) +{ _tmpDir = ignition::common::tempDirectoryPath(); return true; } diff --git a/testing/src/Utils.cc b/testing/src/Utils.cc new file mode 100644 index 00000000..31185348 --- /dev/null +++ b/testing/src/Utils.cc @@ -0,0 +1,53 @@ +/* +* Copyright (C) 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 "ignition/common/testing/Utils.hh" + +#include +#include + +namespace ignition::common::testing +{ + +///////////////////////////////////////////////// +std::string getRandomNumber(int32_t _min, int32_t _max) +{ + // Initialize random number generator. + uint32_t seed = std::random_device {}(); + std::mt19937 randGenerator(seed); + + // Create a random number based on an integer converted to string. + std::uniform_int_distribution d(_min, _max); + + return std::to_string(d(randGenerator)); +} + +///////////////////////////////////////////////// +bool createNewEmptyFile(const std::string &_filename) +{ + try + { + std::fstream fs(_filename, std::ios::out); + } + catch(...) + { + return false; + } + return true; +} + +} // namespace ignition::common::testing diff --git a/testing/src/Utils_TEST.cc b/testing/src/Utils_TEST.cc new file mode 100644 index 00000000..2e75763f --- /dev/null +++ b/testing/src/Utils_TEST.cc @@ -0,0 +1,60 @@ +/* + * Copyright (C) 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 + +using namespace ignition::common; +using namespace ignition::common::testing; + +///////////////////////////////////////////////// +TEST(Utils, GetRandomNumber) +{ + // Force to 1 + auto val1 = getRandomNumber(1, 1); + EXPECT_EQ("1", val1); + + // Force to 100 + auto val100 = getRandomNumber(100, 100); + EXPECT_EQ("100", val100); + + + for (size_t ii = 0; ii < 1000; ++ii) + { + auto val_str = getRandomNumber(0, 100); + EXPECT_FALSE(val_str.empty()); + auto vv = std::stoi(val_str); + EXPECT_GE(vv, 0); + EXPECT_LE(vv, 100); + } +} + +///////////////////////////////////////////////// +TEST(Utils, CreateNewEmptyFile) +{ + auto tmpDir = MakeTestTempDirectory(); + auto path = joinPaths(tmpDir->Path(), "foobar.txt"); + + ASSERT_TRUE(tmpDir->Valid()); + ASSERT_FALSE(exists(path)); + + EXPECT_TRUE(createNewEmptyFile(path)); + EXPECT_TRUE(exists(path)) << path; + EXPECT_TRUE(removeFile(path)); +} + From 377e67d405beee623e4756d8ef0151dc5acef4b8 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 15 Mar 2022 13:38:33 -0500 Subject: [PATCH 04/14] Fixup AutoLogFixture and tests that had transitive depends Signed-off-by: Michael Carroll --- events/src/Event_TEST.cc | 1 + test/integration/video_encoder.cc | 1 + .../include/ignition/common/testing/AutoLogFixture.hh | 2 ++ .../ignition/common/testing/detail/AutoLogFixture.hh} | 10 +++++++++- testing/src/CMakeLists.txt | 1 - 5 files changed, 13 insertions(+), 2 deletions(-) rename testing/{src/AutoLogFixture.cc => include/ignition/common/testing/detail/AutoLogFixture.hh} (92%) diff --git a/events/src/Event_TEST.cc b/events/src/Event_TEST.cc index 388bd6b0..aac91dd6 100644 --- a/events/src/Event_TEST.cc +++ b/events/src/Event_TEST.cc @@ -21,6 +21,7 @@ #include #include +#include using namespace ignition; diff --git a/test/integration/video_encoder.cc b/test/integration/video_encoder.cc index 7368abb6..4ab28006 100644 --- a/test/integration/video_encoder.cc +++ b/test/integration/video_encoder.cc @@ -18,6 +18,7 @@ // needed on MacOS #include +#include "ignition/common/Console.hh" #include "ignition/common/VideoEncoder.hh" #include "ignition/common/Video.hh" #include "ignition/common/ffmpeg_inc.hh" diff --git a/testing/include/ignition/common/testing/AutoLogFixture.hh b/testing/include/ignition/common/testing/AutoLogFixture.hh index 348c665f..c685723f 100644 --- a/testing/include/ignition/common/testing/AutoLogFixture.hh +++ b/testing/include/ignition/common/testing/AutoLogFixture.hh @@ -54,4 +54,6 @@ class AutoLogFixture : public ::testing::Test }; } // namespace ignition::common::testing +#include + #endif // IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_ diff --git a/testing/src/AutoLogFixture.cc b/testing/include/ignition/common/testing/detail/AutoLogFixture.hh similarity index 92% rename from testing/src/AutoLogFixture.cc rename to testing/include/ignition/common/testing/detail/AutoLogFixture.hh index 9fc80b5b..31d54512 100644 --- a/testing/src/AutoLogFixture.cc +++ b/testing/include/ignition/common/testing/detail/AutoLogFixture.hh @@ -14,9 +14,14 @@ * limitations under the License. * */ +#ifndef IGNITION_COMMON_TESTING_DETAIL_AUTOLOGFIXTURE_HH_ +#define IGNITION_COMMON_TESTING_DETAIL_AUTOLOGFIXTURE_HH_ #include "ignition/common/testing/AutoLogFixture.hh" +#include +#include + #include #include #include @@ -66,7 +71,7 @@ void AutoLogFixture::SetUp() this->dataPtr->logFilename = testCaseName + "_" + testName + ".log"; this->dataPtr->temp = std::make_unique( - "test", "ign_common", true); + "test", "ign_common", false); ASSERT_TRUE(this->dataPtr->temp->Valid()); common::setenv(IGN_HOMEDIR, this->dataPtr->temp->Path()); @@ -104,3 +109,6 @@ std::string AutoLogFixture::LogContent() const } } // namespace ignition::common::testing + +#endif // IGNITION_COMMON_TESTING_DETAIL_AUTOLOGFIXTURE_HH_ + diff --git a/testing/src/CMakeLists.txt b/testing/src/CMakeLists.txt index 65770182..970bd7a8 100644 --- a/testing/src/CMakeLists.txt +++ b/testing/src/CMakeLists.txt @@ -1,5 +1,4 @@ set(sources - AutoLogFixture.cc BazelTestPaths.cc CMakeTestPaths.cc TestPaths.cc From 7825749efdc1648658de27b70bf367a09cdfd544 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 10:57:02 -0500 Subject: [PATCH 05/14] Fix visibility for Windows Signed-off-by: Michael Carroll --- .../ignition/common/testing/BazelTestPaths.hh | 1 + .../ignition/common/testing/CMakeTestPaths.hh | 1 + .../ignition/common/testing/TestPaths.hh | 19 ++++++++++++++----- .../include/ignition/common/testing/Utils.hh | 10 ++++++++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh index 0477a8c1..5192f000 100644 --- a/testing/include/ignition/common/testing/BazelTestPaths.hh +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -20,6 +20,7 @@ #include #include "ignition/common/testing/TestPaths.hh" +#include "ignition/common/testing/Export.hh" namespace ignition::common::testing { diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh index c575186a..b3411549 100644 --- a/testing/include/ignition/common/testing/CMakeTestPaths.hh +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -20,6 +20,7 @@ #include #include "ignition/common/testing/TestPaths.hh" +#include "ignition/common/testing/Export.hh" namespace ignition::common::testing { diff --git a/testing/include/ignition/common/testing/TestPaths.hh b/testing/include/ignition/common/testing/TestPaths.hh index d012eb29..571ca892 100644 --- a/testing/include/ignition/common/testing/TestPaths.hh +++ b/testing/include/ignition/common/testing/TestPaths.hh @@ -24,6 +24,8 @@ #include "ignition/common/TempDirectory.hh" #include "ignition/common/Util.hh" +#include "ignition/common/testing/Export.hh" + #ifndef TESTING_PROJECT_SOURCE_DIR #define TESTING_PROJECT_SOURCE_DIR "" #endif @@ -44,7 +46,7 @@ constexpr char kTestingProjectSourceDir[] = TESTING_PROJECT_SOURCE_DIR; ////////////////////////////////////////////////// /// \brief List of buildsystem types -enum class BuildType +enum class IGNITION_COMMON_TESTING_VISIBLE BuildType { kUnknown, kCMake, @@ -60,21 +62,25 @@ enum class BuildType class TestPaths { /// \brief Constructor - public: explicit TestPaths(const std::string &_projectSourcePath = + public: IGNITION_COMMON_TESTING_VISIBLE + explicit TestPaths(const std::string &_projectSourcePath = kTestingProjectSourceDir); /// \brief Destructor - public: virtual ~TestPaths() = 0; + public: IGNITION_COMMON_TESTING_VISIBLE + virtual ~TestPaths() = 0; /// brief Populate the path to the root project source directory /// \param[out] _sourceDir path to the root project source directory /// \return True if path successfully found and set, false otherwise - public: virtual bool ProjectSourcePath(std::string &_sourceDir) = 0; + public: virtual IGNITION_COMMON_TESTING_VISIBLE + bool ProjectSourcePath(std::string &_sourceDir) = 0; /// \brief Populate the path to a temporary directory /// \param[out] _tmpDir path to the root temporary directory /// \return True if path successfully found and set, false otherwise - public: virtual bool TestTmpPath(std::string &_tmpDir) = 0; + public: virtual IGNITION_COMMON_TESTING_VISIBLE + bool TestTmpPath(std::string &_tmpDir) = 0; /// \brief Path to the root of the project source protected: std::string projectSourcePath; @@ -92,6 +98,7 @@ class TestPaths /// be cleaned as part of the destructor /// \return Shared pointer to TempDirectory std::shared_ptr +IGNITION_COMMON_TESTING_VISIBLE MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, const std::string &_prefix = "test", const std::string &_subDir = "ignition", @@ -126,6 +133,7 @@ MakeTestTempDirectory(const std::string &_prefix = "test", /// \param[in] _projectSourcePath Root of project source or empty /// \return The current build type BuildType +IGNITION_COMMON_TESTING_VISIBLE TestBuildType( const std::string &_projectSourcePath = kTestingProjectSourceDir); @@ -135,6 +143,7 @@ TestBuildType( /// \param[in] _projectSourcePath Root of project source or empty /// \return TestPaths implementation for the current build type std::unique_ptr +IGNITION_COMMON_TESTING_VISIBLE TestPathFactory( const std::string &_projectSourcePath = kTestingProjectSourceDir); diff --git a/testing/include/ignition/common/testing/Utils.hh b/testing/include/ignition/common/testing/Utils.hh index a70c2812..39a81f09 100644 --- a/testing/include/ignition/common/testing/Utils.hh +++ b/testing/include/ignition/common/testing/Utils.hh @@ -21,20 +21,26 @@ #include #include +#include "ignition/common/testing/Export.hh" + namespace ignition::common::testing { ///////////////////////////////////////////////// /// \brief Get a random number based on an integer converted to string. /// \return A random integer converted to string. -std::string getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX); +std::string +IGNITION_COMMON_TESTING_VISIBLE +getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX); ///////////////////////////////////////////////// /// \brief Create an empty file with no content /// /// \param[in] _filename Filename of the file to be created /// \return true if file successfully created, false otherwise -bool createNewEmptyFile(const std::string &_filename); +bool +IGNITION_COMMON_TESTING_VISIBLE +createNewEmptyFile(const std::string &_filename); } // namespace ignition::common::testing From f094cad35a01f5260620ef71fb18abc05889994c Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 12:07:10 -0500 Subject: [PATCH 06/14] Visibility for unit tests Signed-off-by: Michael Carroll --- .../include/ignition/common/testing/BazelTestPaths.hh | 10 ++++++---- .../include/ignition/common/testing/CMakeTestPaths.hh | 10 ++++++---- testing/include/ignition/common/testing/TestPaths.hh | 8 ++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh index 5192f000..75d81a31 100644 --- a/testing/include/ignition/common/testing/BazelTestPaths.hh +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -39,16 +39,18 @@ namespace ignition::common::testing class BazelTestPaths: public TestPaths { /// \brief Constructor from TestPaths - public: using TestPaths::TestPaths; + public: IGNITION_COMMON_TESTING_VISIBLE using TestPaths::TestPaths; /// \brief Destructor - public: ~BazelTestPaths() override; + public: IGNITION_COMMON_TESTING_VISIBLE ~BazelTestPaths() override; /// Documentation inherited - public: bool ProjectSourcePath(std::string &_sourceDir) override; + public: bool IGNITION_COMMON_TESTING_VISIBLE + ProjectSourcePath(std::string &_sourceDir) override; /// Documentation inherited - public: bool TestTmpPath(std::string &_tmpDir) override; + public: bool IGNITION_COMMON_TESTING_VISIBLE + TestTmpPath(std::string &_tmpDir) override; }; } // namespace ignition::common::testing diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh index b3411549..6d9f92c2 100644 --- a/testing/include/ignition/common/testing/CMakeTestPaths.hh +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -31,16 +31,18 @@ namespace ignition::common::testing class CMakeTestPaths: public TestPaths { /// \brief Constructor from TestPaths - public: using TestPaths::TestPaths; + public: IGNITION_COMMON_TESTING_VISIBLE using TestPaths::TestPaths; /// \brief Destructor - public: ~CMakeTestPaths() override; + public: IGNITION_COMMON_TESTING_VISIBLE ~CMakeTestPaths() override; /// Documentation inherited - public: bool ProjectSourcePath(std::string &_sourceDir) override; + public: bool IGNITION_COMMON_TESTING_VISIBLE + ProjectSourcePath(std::string &_sourceDir) override; /// Documentation inherited - public: bool TestTmpPath(std::string &_tmpDir) override; + public: bool IGNITION_COMMON_TESTING_VISIBLE + TestTmpPath(std::string &_tmpDir) override; }; } // namespace ignition::common::testing #endif // IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_ diff --git a/testing/include/ignition/common/testing/TestPaths.hh b/testing/include/ignition/common/testing/TestPaths.hh index 571ca892..5e759701 100644 --- a/testing/include/ignition/common/testing/TestPaths.hh +++ b/testing/include/ignition/common/testing/TestPaths.hh @@ -73,14 +73,14 @@ class TestPaths /// brief Populate the path to the root project source directory /// \param[out] _sourceDir path to the root project source directory /// \return True if path successfully found and set, false otherwise - public: virtual IGNITION_COMMON_TESTING_VISIBLE - bool ProjectSourcePath(std::string &_sourceDir) = 0; + public: virtual bool IGNITION_COMMON_TESTING_VISIBLE + ProjectSourcePath(std::string &_sourceDir) = 0; /// \brief Populate the path to a temporary directory /// \param[out] _tmpDir path to the root temporary directory /// \return True if path successfully found and set, false otherwise - public: virtual IGNITION_COMMON_TESTING_VISIBLE - bool TestTmpPath(std::string &_tmpDir) = 0; + public: virtual bool IGNITION_COMMON_TESTING_VISIBLE + TestTmpPath(std::string &_tmpDir) = 0; /// \brief Path to the root of the project source protected: std::string projectSourcePath; From 84dbb6c8101c09f419c29dc9d12893e691470a74 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 12:12:01 -0500 Subject: [PATCH 07/14] Fix 'using' visibility Signed-off-by: Michael Carroll --- testing/include/ignition/common/testing/BazelTestPaths.hh | 2 +- testing/include/ignition/common/testing/CMakeTestPaths.hh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh index 75d81a31..37499656 100644 --- a/testing/include/ignition/common/testing/BazelTestPaths.hh +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -39,7 +39,7 @@ namespace ignition::common::testing class BazelTestPaths: public TestPaths { /// \brief Constructor from TestPaths - public: IGNITION_COMMON_TESTING_VISIBLE using TestPaths::TestPaths; + public: using TestPaths::TestPaths; /// \brief Destructor public: IGNITION_COMMON_TESTING_VISIBLE ~BazelTestPaths() override; diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh index 6d9f92c2..61c849bb 100644 --- a/testing/include/ignition/common/testing/CMakeTestPaths.hh +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -31,7 +31,7 @@ namespace ignition::common::testing class CMakeTestPaths: public TestPaths { /// \brief Constructor from TestPaths - public: IGNITION_COMMON_TESTING_VISIBLE using TestPaths::TestPaths; + public: using TestPaths::TestPaths; /// \brief Destructor public: IGNITION_COMMON_TESTING_VISIBLE ~CMakeTestPaths() override; From b2f7480bf1c8840d81bc12d411ce1f4fc2de2283 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:23:32 -0500 Subject: [PATCH 08/14] Add checks and tests for empty _root parameter Signed-off-by: Michael Carroll --- src/TempDirectory.cc | 10 ++++++++-- src/TempDirectory_TEST.cc | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/TempDirectory.cc b/src/TempDirectory.cc index 10497981..7f3809b3 100644 --- a/src/TempDirectory.cc +++ b/src/TempDirectory.cc @@ -172,14 +172,20 @@ TempDirectory::TempDirectory(const std::string &_root, bool _cleanup): dataPtr(ignition::utils::MakeUniqueImpl()) { - this->dataPtr->oldPath = common::cwd(); this->dataPtr->doCleanup = _cleanup; + if (_root.empty()) + { + this->dataPtr->isValid = false; + ignwarn << "Failed to create temp directory: _root was empty\n"; + return; + } + auto tempPath = _root; if (!_subDir.empty()) { - tempPath = common::joinPaths(tempPath, _subDir); + tempPath = common::joinPaths(_root, _subDir); } this->dataPtr->path = common::createTempDirectory(_prefix, tempPath); if (!this->dataPtr->path.empty()) diff --git a/src/TempDirectory_TEST.cc b/src/TempDirectory_TEST.cc index b49aaf87..9ec7c359 100644 --- a/src/TempDirectory_TEST.cc +++ b/src/TempDirectory_TEST.cc @@ -66,14 +66,20 @@ TEST(TempDirectory, createTempDirectoryEmptyBase) TEST(TempDirectory, TempDirectory) { std::string path; + auto curDir = ignition::common::cwd(); { ignition::common::TempDirectory tmp("temp_dir", "ignition", true); EXPECT_TRUE(tmp.Valid()); EXPECT_TRUE(tmp.DoCleanup()); + // Current directory changed to tempdir + EXPECT_NE(curDir, ignition::common::cwd()); path = tmp.Path(); EXPECT_FALSE(path.empty()); EXPECT_TRUE(ignition::common::exists(path)); + EXPECT_EQ(path, ignition::common::cwd()); } + // Current directory changed back to previous + EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_FALSE(ignition::common::exists(path)); } @@ -81,15 +87,39 @@ TEST(TempDirectory, TempDirectory) TEST(TempDirectory, TempDirectoryRoot) { std::string path; + auto curDir = ignition::common::cwd(); { auto p = ignition::common::tempDirectoryPath(); ignition::common::TempDirectory tmp(p, "temp_dir", "ignition", true); EXPECT_TRUE(tmp.Valid()); EXPECT_TRUE(tmp.DoCleanup()); + EXPECT_NE(curDir, ignition::common::cwd()); path = tmp.Path(); EXPECT_FALSE(path.empty()); EXPECT_TRUE(ignition::common::exists(path)); + EXPECT_EQ(path, ignition::common::cwd()); } + // Current directory changed back to previous + EXPECT_EQ(curDir, ignition::common::cwd()); + EXPECT_FALSE(ignition::common::exists(path)); +} + +///////////////////////////////////////////////// +TEST(TempDirectory, TempDirectoryEmptyRoot) +{ + std::string path; + auto curDir = ignition::common::cwd(); + { + ignition::common::TempDirectory tmp("", "temp_dir", "ignition", true); + EXPECT_FALSE(tmp.Valid()); + EXPECT_TRUE(tmp.DoCleanup()); + // Since not successfully created, no update + EXPECT_EQ(curDir, ignition::common::cwd()); + path = tmp.Path(); + EXPECT_TRUE(path.empty()); + EXPECT_FALSE(ignition::common::exists(path)); + } + EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_FALSE(ignition::common::exists(path)); } @@ -97,14 +127,19 @@ TEST(TempDirectory, TempDirectoryRoot) TEST(TempDirectory, TempDirectoryNoClean) { std::string path; + auto curDir = ignition::common::cwd(); { ignition::common::TempDirectory tmp("temp_dir", "ignition", false); EXPECT_TRUE(tmp.Valid()); EXPECT_FALSE(tmp.DoCleanup()); + EXPECT_NE(curDir, ignition::common::cwd()); path = tmp.Path(); EXPECT_FALSE(path.empty()); EXPECT_TRUE(ignition::common::exists(path)); + EXPECT_EQ(path, ignition::common::cwd()); } + // Current directory always changes back, regardless of doClean + EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_TRUE(ignition::common::exists(path)); EXPECT_TRUE(ignition::common::removeDirectory(path)); } @@ -113,16 +148,21 @@ TEST(TempDirectory, TempDirectoryNoClean) TEST(TempDirectory, TempDirectoryNoCleanLater) { std::string path; + auto curDir = ignition::common::cwd(); { ignition::common::TempDirectory tmp("temp_dir", "ignition", true); EXPECT_TRUE(tmp.Valid()); EXPECT_TRUE(tmp.DoCleanup()); + EXPECT_NE(curDir, ignition::common::cwd()); path = tmp.Path(); EXPECT_FALSE(path.empty()); EXPECT_TRUE(ignition::common::exists(path)); + EXPECT_EQ(path, ignition::common::cwd()); tmp.DoCleanup(false); EXPECT_FALSE(tmp.DoCleanup()); } + // Current directory always changes back, regardless of doClean + EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_TRUE(ignition::common::exists(path)); EXPECT_TRUE(ignition::common::removeDirectory(path)); } From bab3599167ba1bb42ccab8ce97c53a7c4f3bfa02 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:24:47 -0500 Subject: [PATCH 09/14] Add documentation to projectSourcePath Signed-off-by: Michael Carroll --- .../include/ignition/common/testing/TestPaths.hh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/testing/include/ignition/common/testing/TestPaths.hh b/testing/include/ignition/common/testing/TestPaths.hh index 5e759701..da20fb21 100644 --- a/testing/include/ignition/common/testing/TestPaths.hh +++ b/testing/include/ignition/common/testing/TestPaths.hh @@ -62,24 +62,25 @@ enum class IGNITION_COMMON_TESTING_VISIBLE BuildType class TestPaths { /// \brief Constructor - public: IGNITION_COMMON_TESTING_VISIBLE + /// \param[in] _projectSourcePath Path to the root of the project source + public: IGNITION_COMMON_TESTING_VISIBLE explicit TestPaths(const std::string &_projectSourcePath = kTestingProjectSourceDir); /// \brief Destructor - public: IGNITION_COMMON_TESTING_VISIBLE + public: IGNITION_COMMON_TESTING_VISIBLE virtual ~TestPaths() = 0; /// brief Populate the path to the root project source directory /// \param[out] _sourceDir path to the root project source directory /// \return True if path successfully found and set, false otherwise - public: virtual bool IGNITION_COMMON_TESTING_VISIBLE + public: virtual bool IGNITION_COMMON_TESTING_VISIBLE ProjectSourcePath(std::string &_sourceDir) = 0; /// \brief Populate the path to a temporary directory /// \param[out] _tmpDir path to the root temporary directory /// \return True if path successfully found and set, false otherwise - public: virtual bool IGNITION_COMMON_TESTING_VISIBLE + public: virtual bool IGNITION_COMMON_TESTING_VISIBLE TestTmpPath(std::string &_tmpDir) = 0; /// \brief Path to the root of the project source @@ -98,7 +99,7 @@ class TestPaths /// be cleaned as part of the destructor /// \return Shared pointer to TempDirectory std::shared_ptr -IGNITION_COMMON_TESTING_VISIBLE +IGNITION_COMMON_TESTING_VISIBLE MakeTestTempDirectoryImpl(const std::string &_projectSourcePath, const std::string &_prefix = "test", const std::string &_subDir = "ignition", @@ -133,7 +134,7 @@ MakeTestTempDirectory(const std::string &_prefix = "test", /// \param[in] _projectSourcePath Root of project source or empty /// \return The current build type BuildType -IGNITION_COMMON_TESTING_VISIBLE +IGNITION_COMMON_TESTING_VISIBLE TestBuildType( const std::string &_projectSourcePath = kTestingProjectSourceDir); @@ -143,7 +144,7 @@ TestBuildType( /// \param[in] _projectSourcePath Root of project source or empty /// \return TestPaths implementation for the current build type std::unique_ptr -IGNITION_COMMON_TESTING_VISIBLE +IGNITION_COMMON_TESTING_VISIBLE TestPathFactory( const std::string &_projectSourcePath = kTestingProjectSourceDir); From 44cce83d96a8a943132d4127258480d8b9e794fd Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:26:21 -0500 Subject: [PATCH 10/14] Remove getRandomNumber in favor of ign-math impl Signed-off-by: Michael Carroll --- .../include/ignition/common/testing/Utils.hh | 7 ------ testing/src/Utils_TEST.cc | 22 ------------------- 2 files changed, 29 deletions(-) diff --git a/testing/include/ignition/common/testing/Utils.hh b/testing/include/ignition/common/testing/Utils.hh index 39a81f09..480636d9 100644 --- a/testing/include/ignition/common/testing/Utils.hh +++ b/testing/include/ignition/common/testing/Utils.hh @@ -26,13 +26,6 @@ namespace ignition::common::testing { -///////////////////////////////////////////////// -/// \brief Get a random number based on an integer converted to string. -/// \return A random integer converted to string. -std::string -IGNITION_COMMON_TESTING_VISIBLE -getRandomNumber(int32_t _min = 0, int32_t _max = INT_MAX); - ///////////////////////////////////////////////// /// \brief Create an empty file with no content /// diff --git a/testing/src/Utils_TEST.cc b/testing/src/Utils_TEST.cc index 2e75763f..5a484a52 100644 --- a/testing/src/Utils_TEST.cc +++ b/testing/src/Utils_TEST.cc @@ -22,28 +22,6 @@ using namespace ignition::common; using namespace ignition::common::testing; -///////////////////////////////////////////////// -TEST(Utils, GetRandomNumber) -{ - // Force to 1 - auto val1 = getRandomNumber(1, 1); - EXPECT_EQ("1", val1); - - // Force to 100 - auto val100 = getRandomNumber(100, 100); - EXPECT_EQ("100", val100); - - - for (size_t ii = 0; ii < 1000; ++ii) - { - auto val_str = getRandomNumber(0, 100); - EXPECT_FALSE(val_str.empty()); - auto vv = std::stoi(val_str); - EXPECT_GE(vv, 0); - EXPECT_LE(vv, 100); - } -} - ///////////////////////////////////////////////// TEST(Utils, CreateNewEmptyFile) { From 9c3b6dc7580e7d4638cb65f4a4dbb835e768bbf1 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:31:03 -0500 Subject: [PATCH 11/14] Add more ASSERTs to AutoLogFixture Signed-off-by: Michael Carroll --- .../ignition/common/testing/detail/AutoLogFixture.hh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/testing/include/ignition/common/testing/detail/AutoLogFixture.hh b/testing/include/ignition/common/testing/detail/AutoLogFixture.hh index 31d54512..e4491459 100644 --- a/testing/include/ignition/common/testing/detail/AutoLogFixture.hh +++ b/testing/include/ignition/common/testing/detail/AutoLogFixture.hh @@ -76,13 +76,19 @@ void AutoLogFixture::SetUp() common::setenv(IGN_HOMEDIR, this->dataPtr->temp->Path()); // Initialize Console - ignLogInit(common::joinPaths(this->dataPtr->temp->Path(), "test_logs"), - this->dataPtr->logFilename); + auto logPath = common::joinPaths(this->dataPtr->temp->Path(), "test_logs"); + ignLogInit(logPath, this->dataPtr->logFilename); + + ASSERT_FALSE(logPath.empty()); + ASSERT_TRUE(common::exists( + common::joinPaths(logPath, this->dataPtr->logFilename))); ignition::common::Console::SetVerbosity(4); // Read the full path to the log directory. this->dataPtr->logDirectory = ignLogDirectory(); + ASSERT_FALSE(this->dataPtr->logDirectory.empty()); + ASSERT_TRUE(ignition::common::exists(this->dataPtr->logDirectory)); } ////////////////////////////////////////////////// From 046cf5b2534d827aaacf887e3cc798fb9e6c0ba0 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:32:44 -0500 Subject: [PATCH 12/14] Warn when both bazel and cmake detected Signed-off-by: Michael Carroll --- testing/src/TestPaths.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/testing/src/TestPaths.cc b/testing/src/TestPaths.cc index 80c57375..54854dda 100644 --- a/testing/src/TestPaths.cc +++ b/testing/src/TestPaths.cc @@ -39,10 +39,15 @@ BuildType TestBuildType(const std::string &_projectSourcePath) bool ign_bazel_set = common::env("IGN_BAZEL", ign_bazel); bool ign_cmake_set = !_projectSourcePath.empty(); - if (ign_bazel_set) - return BuildType::kBazel; - else if (ign_cmake_set) + if (ign_bazel_set && ign_cmake_set) + { + ignwarn << "Detected settings from Bazel and CMake, preferring CMake\n"; + } + + if (ign_cmake_set) return BuildType::kCMake; + else if (ign_bazel_set) + return BuildType::kBazel; else return BuildType::kUnknown; } From 303928d802e297c558c85ecccfb7e6cf0ef1cbf1 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Tue, 5 Apr 2022 15:34:17 -0500 Subject: [PATCH 13/14] Lintt Signed-off-by: Michael Carroll --- av/src/AudioDecoder.cc | 3 ++- src/TempDirectory_TEST.cc | 4 ++-- testing/include/ignition/common/testing/BazelTestPaths.hh | 4 ++-- testing/include/ignition/common/testing/CMakeTestPaths.hh | 4 ++-- testing/include/ignition/common/testing/Utils.hh | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/av/src/AudioDecoder.cc b/av/src/AudioDecoder.cc index b7a01b28..4ff2b237 100644 --- a/av/src/AudioDecoder.cc +++ b/av/src/AudioDecoder.cc @@ -325,7 +325,8 @@ bool AudioDecoder::SetFile(const std::string &_filename) avcodec_parameters_to_context(this->dataPtr->codecCtx, this->dataPtr->formatCtx->streams[this->dataPtr->audioStream]->codecpar); #else - this->dataPtr->codec = avcodec_find_decoder(this->dataPtr->codecCtx->codec_id); + this->dataPtr->codec = avcodec_find_decoder( + this->dataPtr->codecCtx->codec_id); #endif if (this->dataPtr->codec == nullptr) diff --git a/src/TempDirectory_TEST.cc b/src/TempDirectory_TEST.cc index 9ec7c359..4fde626d 100644 --- a/src/TempDirectory_TEST.cc +++ b/src/TempDirectory_TEST.cc @@ -138,7 +138,7 @@ TEST(TempDirectory, TempDirectoryNoClean) EXPECT_TRUE(ignition::common::exists(path)); EXPECT_EQ(path, ignition::common::cwd()); } - // Current directory always changes back, regardless of doClean + // Current directory always changes back, regardless of doClean EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_TRUE(ignition::common::exists(path)); EXPECT_TRUE(ignition::common::removeDirectory(path)); @@ -161,7 +161,7 @@ TEST(TempDirectory, TempDirectoryNoCleanLater) tmp.DoCleanup(false); EXPECT_FALSE(tmp.DoCleanup()); } - // Current directory always changes back, regardless of doClean + // Current directory always changes back, regardless of doClean EXPECT_EQ(curDir, ignition::common::cwd()); EXPECT_TRUE(ignition::common::exists(path)); EXPECT_TRUE(ignition::common::removeDirectory(path)); diff --git a/testing/include/ignition/common/testing/BazelTestPaths.hh b/testing/include/ignition/common/testing/BazelTestPaths.hh index 37499656..b8927a86 100644 --- a/testing/include/ignition/common/testing/BazelTestPaths.hh +++ b/testing/include/ignition/common/testing/BazelTestPaths.hh @@ -45,11 +45,11 @@ class BazelTestPaths: public TestPaths public: IGNITION_COMMON_TESTING_VISIBLE ~BazelTestPaths() override; /// Documentation inherited - public: bool IGNITION_COMMON_TESTING_VISIBLE + public: bool IGNITION_COMMON_TESTING_VISIBLE ProjectSourcePath(std::string &_sourceDir) override; /// Documentation inherited - public: bool IGNITION_COMMON_TESTING_VISIBLE + public: bool IGNITION_COMMON_TESTING_VISIBLE TestTmpPath(std::string &_tmpDir) override; }; diff --git a/testing/include/ignition/common/testing/CMakeTestPaths.hh b/testing/include/ignition/common/testing/CMakeTestPaths.hh index 61c849bb..9b18dd10 100644 --- a/testing/include/ignition/common/testing/CMakeTestPaths.hh +++ b/testing/include/ignition/common/testing/CMakeTestPaths.hh @@ -37,11 +37,11 @@ class CMakeTestPaths: public TestPaths public: IGNITION_COMMON_TESTING_VISIBLE ~CMakeTestPaths() override; /// Documentation inherited - public: bool IGNITION_COMMON_TESTING_VISIBLE + public: bool IGNITION_COMMON_TESTING_VISIBLE ProjectSourcePath(std::string &_sourceDir) override; /// Documentation inherited - public: bool IGNITION_COMMON_TESTING_VISIBLE + public: bool IGNITION_COMMON_TESTING_VISIBLE TestTmpPath(std::string &_tmpDir) override; }; } // namespace ignition::common::testing diff --git a/testing/include/ignition/common/testing/Utils.hh b/testing/include/ignition/common/testing/Utils.hh index 480636d9..a4ae24c1 100644 --- a/testing/include/ignition/common/testing/Utils.hh +++ b/testing/include/ignition/common/testing/Utils.hh @@ -31,8 +31,8 @@ namespace ignition::common::testing /// /// \param[in] _filename Filename of the file to be created /// \return true if file successfully created, false otherwise -bool -IGNITION_COMMON_TESTING_VISIBLE +bool +IGNITION_COMMON_TESTING_VISIBLE createNewEmptyFile(const std::string &_filename); } // namespace ignition::common::testing From 210641e95dfa9e3ffe60072c4997bd23b57ba710 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Fri, 8 Apr 2022 12:56:02 -0500 Subject: [PATCH 14/14] Move CMakeLists location for installation Signed-off-by: Michael Carroll --- testing/include/ignition/common/CMakeLists.txt | 1 + testing/include/ignition/common/testing/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 testing/include/ignition/common/testing/CMakeLists.txt diff --git a/testing/include/ignition/common/CMakeLists.txt b/testing/include/ignition/common/CMakeLists.txt index e69de29b..027bd91f 100644 --- a/testing/include/ignition/common/CMakeLists.txt +++ b/testing/include/ignition/common/CMakeLists.txt @@ -0,0 +1 @@ +ign_install_all_headers(COMPONENT testing) diff --git a/testing/include/ignition/common/testing/CMakeLists.txt b/testing/include/ignition/common/testing/CMakeLists.txt deleted file mode 100644 index 06f5b9aa..00000000 --- a/testing/include/ignition/common/testing/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ - -ign_install_all_headers(COMPONENT testing)