SdBusError: Add test cases
This adds basic unit testing to the SdBusError class so we have full
coverage of all the functionality.
Tested:
Ran through the unit test suite including the changes that build
valgrind runs and code coverage suppport.
Change-Id: I6d3bdbd2e0332ae5372796cb2a380ccddbee10ec
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/Makefile.am b/test/Makefile.am
index 0c71949..442d084 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -24,6 +24,10 @@
bus_match_SOURCES = bus/match.cpp
bus_match_LDADD = $(gtest_ldadd)
+check_PROGRAMS += exception_sdbus_error
+exception_sdbus_error_SOURCES = exception/sdbus_error.cpp
+exception_sdbus_error_LDADD = $(gtest_ldadd)
+
check_PROGRAMS += message_append
message_append_SOURCES = message/append.cpp
message_append_CXXFLAGS = $(legacy_test_cxxflags)
diff --git a/test/exception/sdbus_error.cpp b/test/exception/sdbus_error.cpp
new file mode 100644
index 0000000..02d063d
--- /dev/null
+++ b/test/exception/sdbus_error.cpp
@@ -0,0 +1,153 @@
+#include <cstdlib>
+#include <gtest/gtest.h>
+#include <sdbusplus/exception.hpp>
+#include <sdbusplus/test/sdbus_mock.hpp>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <systemd/sd-bus.h>
+#include <utility>
+
+// Needed for constuctor error testing
+extern sdbusplus::SdBusImpl sdbus_impl;
+
+namespace
+{
+
+using sdbusplus::exception::SdBusError;
+using testing::Return;
+using testing::_;
+
+std::error_code errnoToErrorCode(int error)
+{
+ return std::error_code(error, std::generic_category());
+}
+
+TEST(SdBusError, BasicErrno)
+{
+ const int errorVal = EBUSY;
+ const std::string prefix = "BasicErrno";
+
+ // Build the reference sd_bus_error
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ EXPECT_EQ(-errorVal, sd_bus_error_set_errno(&error, errorVal));
+ EXPECT_TRUE(sd_bus_error_is_set(&error));
+
+ // Build the SdBusError
+ SdBusError err(errorVal, prefix.c_str());
+
+ // Make sure inheritance is defined correctly
+ sdbusplus::exception::exception& sdbusErr = err;
+ EXPECT_EQ(std::string{error.name}, sdbusErr.name());
+ EXPECT_EQ(std::string{error.message}, sdbusErr.description());
+ std::system_error& systemErr = err;
+ EXPECT_EQ(errnoToErrorCode(errorVal), systemErr.code());
+ std::exception& stdErr = sdbusErr;
+ EXPECT_EQ(prefix + ": " + error.name + ": " + error.message, stdErr.what());
+
+ sd_bus_error_free(&error);
+}
+
+TEST(SdBusError, EnomemErrno)
+{
+ // Make sure no exception is thrown on construction
+ SdBusError err(ENOMEM, "EnomemErrno");
+}
+
+TEST(SdBusError, NotSetErrno)
+{
+ const int errorVal = EBUSY;
+
+ sdbusplus::SdBusMock sdbus;
+ EXPECT_CALL(sdbus, sd_bus_error_set_errno(_, errorVal))
+ .Times(1)
+ .WillOnce(Return(errorVal));
+ EXPECT_CALL(sdbus, sd_bus_error_is_set(_)).Times(1).WillOnce(Return(false));
+ EXPECT_THROW(SdBusError(errorVal, "NotSetErrno", &sdbus),
+ std::runtime_error);
+}
+
+TEST(SdBusError, Move)
+{
+ const int errorVal = EIO;
+ const std::string prefix = "Move";
+
+ // Build the reference sd_bus_error
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ EXPECT_EQ(-errorVal, sd_bus_error_set_errno(&error, errorVal));
+ EXPECT_TRUE(sd_bus_error_is_set(&error));
+ const std::string name{error.name};
+ const std::string message{error.message};
+ const std::string what = prefix + ": " + error.name + ": " + error.message;
+
+ SdBusError errFinal(EBUSY, "Move2");
+ // Nest to make sure RAII works for moves
+ {
+ // Build our first SdBusError
+ SdBusError err(errorVal, prefix.c_str());
+
+ EXPECT_EQ(name, err.name());
+ EXPECT_EQ(message, err.description());
+ EXPECT_EQ(what, err.what());
+ EXPECT_EQ(errnoToErrorCode(errorVal), err.code());
+
+ // Move our SdBusError to a new one
+ SdBusError errNew(std::move(err));
+
+ // Ensure the old object was cleaned up
+ EXPECT_EQ(nullptr, err.name());
+ EXPECT_EQ(nullptr, err.description());
+ EXPECT_EQ(std::string{}, err.what());
+
+ // Ensure our new object has the same data but moved
+ EXPECT_EQ(name, errNew.name());
+ EXPECT_EQ(message, errNew.description());
+ EXPECT_EQ(what, errNew.what());
+ EXPECT_EQ(errnoToErrorCode(errorVal), errNew.code());
+
+ // Move our SdBusError using the operator=()
+ errFinal = std::move(errNew);
+
+ // Ensure the old object was cleaned up
+ EXPECT_EQ(nullptr, errNew.name());
+ EXPECT_EQ(nullptr, errNew.description());
+ EXPECT_EQ(std::string{}, errNew.what());
+ }
+
+ // Ensure our new object has the same data but moved
+ EXPECT_EQ(name, errFinal.name());
+ EXPECT_EQ(message, errFinal.description());
+ EXPECT_EQ(what, errFinal.what());
+ EXPECT_EQ(errnoToErrorCode(errorVal), errFinal.code());
+
+ sd_bus_error_free(&error);
+}
+
+TEST(SdBusError, BasicError)
+{
+ const std::string name = "org.freedesktop.DBus.Error.Failed";
+ const std::string description = "TestCase";
+ const std::string prefix = "BasicError";
+
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_error_set(&error, name.c_str(), description.c_str());
+ EXPECT_TRUE(sd_bus_error_is_set(&error));
+ const char* nameBeforeMove = error.name;
+ const int errorVal = sd_bus_error_get_errno(&error);
+ SdBusError err(&error, prefix.c_str());
+
+ // We expect a move not copy
+ EXPECT_EQ(nameBeforeMove, err.name());
+
+ // The SdBusError should have moved our error so it should be freeable
+ EXPECT_FALSE(sd_bus_error_is_set(&error));
+ sd_bus_error_free(&error);
+ sd_bus_error_free(&error);
+
+ EXPECT_EQ(name, err.name());
+ EXPECT_EQ(description, err.description());
+ EXPECT_EQ(prefix + ": " + name + ": " + description, err.what());
+ EXPECT_EQ(errnoToErrorCode(errorVal), err.code());
+}
+
+} // namespace