Skip to content

Commit

Permalink
Add common::testing module (#314)
Browse files Browse the repository at this point in the history
This introduces ignition::common::testing, a component to hold all of our testing support functionality.

Signed-off-by: Michael Carroll <[email protected]>
  • Loading branch information
mjcarroll authored Apr 11, 2022
1 parent 8761b6f commit 96df813
Show file tree
Hide file tree
Showing 24 changed files with 1,135 additions and 6 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ configure_file("${PROJECT_SOURCE_DIR}/cppcheck.suppress.in"
${PROJECT_BINARY_DIR}/cppcheck.suppress)

ign_configure_build(QUIT_IF_BUILD_ERRORS
COMPONENTS av events geospatial graphics profiler)
COMPONENTS av events geospatial graphics profiler testing)

#============================================================================
# Create package information
Expand Down
5 changes: 3 additions & 2 deletions av/src/AudioDecoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -346,7 +347,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";
Expand Down
1 change: 1 addition & 0 deletions events/src/Event_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <functional>
#include <ignition/common/Event.hh>
#include <ignition/common/Util.hh>

using namespace ignition;

Expand Down
16 changes: 16 additions & 0 deletions include/ignition/common/TempDirectory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
22 changes: 19 additions & 3 deletions src/TempDirectory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,31 @@ class ignition::common::TempDirectory::Implementation
TempDirectory::TempDirectory(const std::string &_prefix,
const std::string &_subDir,
bool _cleanup):
dataPtr(ignition::utils::MakeUniqueImpl<Implementation>())
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<Implementation>())
{
this->dataPtr->oldPath = common::cwd();
this->dataPtr->doCleanup = _cleanup;

auto tempPath = common::tempDirectoryPath();
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())
Expand All @@ -181,6 +196,7 @@ TempDirectory::TempDirectory(const std::string &_prefix,
this->dataPtr->path = common::cwd();
}


/////////////////////////////////////////////////
TempDirectory::~TempDirectory()
{
Expand Down
56 changes: 56 additions & 0 deletions src/TempDirectory_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,80 @@ 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));
}

/////////////////////////////////////////////////
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));
}

/////////////////////////////////////////////////
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));
}
Expand All @@ -97,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));
}
1 change: 1 addition & 0 deletions test/integration/video_encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// needed on MacOS
#include <cmath>

#include "ignition/common/Console.hh"
#include "ignition/common/VideoEncoder.hh"
#include "ignition/common/Video.hh"
#include "ignition/common/ffmpeg_inc.hh"
Expand Down
1 change: 1 addition & 0 deletions testing/include/ignition/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ign_install_all_headers(COMPONENT testing)
59 changes: 59 additions & 0 deletions testing/include/ignition/common/testing/AutoLogFixture.hh
Original file line number Diff line number Diff line change
@@ -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_AUTOLOGFIXTURE_HH_
#define IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_

#include <gtest/gtest.h>

#include <memory>
#include <string>

#include <ignition/utils/ImplPtr.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 Constructor
public: AutoLogFixture();

/// \brief Destructor
public: virtual ~AutoLogFixture();

/// \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;

/// \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;

/// \brief Pointer to private data.
IGN_UTILS_UNIQUE_IMPL_PTR(dataPtr)
};
} // namespace ignition::common::testing

#include <ignition/common/testing/detail/AutoLogFixture.hh>

#endif // IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_
58 changes: 58 additions & 0 deletions testing/include/ignition/common/testing/BazelTestPaths.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 <string>

#include "ignition/common/testing/TestPaths.hh"
#include "ignition/common/testing/Export.hh"

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: IGNITION_COMMON_TESTING_VISIBLE ~BazelTestPaths() override;

/// Documentation inherited
public: bool IGNITION_COMMON_TESTING_VISIBLE
ProjectSourcePath(std::string &_sourceDir) override;

/// Documentation inherited
public: bool IGNITION_COMMON_TESTING_VISIBLE
TestTmpPath(std::string &_tmpDir) override;
};

} // namespace ignition::common::testing

#endif // IGNITION_COMMON_TESTING_AUTOLOGFIXTURE_HH_
48 changes: 48 additions & 0 deletions testing/include/ignition/common/testing/CMakeTestPaths.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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 <string>

#include "ignition/common/testing/TestPaths.hh"
#include "ignition/common/testing/Export.hh"

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: IGNITION_COMMON_TESTING_VISIBLE ~CMakeTestPaths() override;

/// Documentation inherited
public: bool IGNITION_COMMON_TESTING_VISIBLE
ProjectSourcePath(std::string &_sourceDir) override;

/// Documentation inherited
public: bool IGNITION_COMMON_TESTING_VISIBLE
TestTmpPath(std::string &_tmpDir) override;
};
} // namespace ignition::common::testing
#endif // IGNITION_COMMON_TESTING_CMAKETESTPATHS_HH_
Loading

0 comments on commit 96df813

Please sign in to comment.