1 #include <systemd/sd-bus.h> 2 3 #include <sdbusplus/exception.hpp> 4 #include <sdbusplus/test/sdbus_mock.hpp> 5 6 #include <cstdlib> 7 #include <stdexcept> 8 #include <string> 9 #include <utility> 10 11 #include <gtest/gtest.h> 12 13 // Needed for constructor error testing 14 extern sdbusplus::SdBusImpl sdbus_impl; 15 16 namespace 17 { 18 19 using sdbusplus::exception::SdBusError; 20 using testing::_; 21 using testing::Return; 22 23 TEST(SdBusError, BasicErrno) 24 { 25 const int errorVal = EBUSY; 26 const std::string prefix = "BasicErrno"; 27 28 // Build the reference sd_bus_error 29 sd_bus_error error = SD_BUS_ERROR_NULL; 30 EXPECT_EQ(-errorVal, sd_bus_error_set_errno(&error, errorVal)); 31 EXPECT_TRUE(sd_bus_error_is_set(&error)); 32 33 // Build the SdBusError 34 SdBusError err(errorVal, prefix.c_str()); 35 36 // Make sure inheritance is defined correctly 37 sdbusplus::exception::exception& sdbusErr = err; 38 SdBusError& errNew = err; 39 EXPECT_EQ(errorVal, errNew.get_errno()); 40 EXPECT_EQ(std::string{error.name}, sdbusErr.name()); 41 EXPECT_EQ(std::string{error.message}, sdbusErr.description()); 42 std::exception& stdErr = sdbusErr; 43 EXPECT_EQ(prefix + ": " + error.name + ": " + error.message, stdErr.what()); 44 45 sd_bus_error_free(&error); 46 } 47 48 TEST(SdBusError, EnomemErrno) 49 { 50 // Make sure no exception is thrown on construction 51 SdBusError err(ENOMEM, "EnomemErrno"); 52 } 53 54 TEST(SdBusError, NotSetErrno) 55 { 56 const int errorVal = EBUSY; 57 58 sdbusplus::SdBusMock sdbus; 59 EXPECT_CALL(sdbus, sd_bus_error_set_errno(_, errorVal)) 60 .Times(1) 61 .WillOnce(Return(errorVal)); 62 EXPECT_CALL(sdbus, sd_bus_error_is_set(_)).Times(1).WillOnce(Return(false)); 63 EXPECT_THROW(SdBusError(errorVal, "NotSetErrno", &sdbus), 64 std::runtime_error); 65 } 66 67 TEST(SdBusError, Move) 68 { 69 const int errorVal = EIO; 70 const std::string prefix = "Move"; 71 72 // Build the reference sd_bus_error 73 sd_bus_error error = SD_BUS_ERROR_NULL; 74 EXPECT_EQ(-errorVal, sd_bus_error_set_errno(&error, errorVal)); 75 EXPECT_TRUE(sd_bus_error_is_set(&error)); 76 const std::string name{error.name}; 77 const std::string message{error.message}; 78 const std::string what = prefix + ": " + error.name + ": " + error.message; 79 80 SdBusError errFinal(EBUSY, "Move2"); 81 // Nest to make sure RAII works for moves 82 { 83 // Build our first SdBusError 84 SdBusError err(errorVal, prefix.c_str()); 85 86 EXPECT_EQ(errorVal, err.get_errno()); 87 EXPECT_EQ(name, err.name()); 88 EXPECT_EQ(message, err.description()); 89 EXPECT_EQ(what, err.what()); 90 91 // Move our SdBusError to a new one 92 SdBusError errNew(std::move(err)); 93 94 // We are purposefully calling functions on a moved-from object, 95 // so we need to suppress the clang warnings. 96 #ifndef __clang_analyzer__ 97 // Ensure the old object was cleaned up 98 EXPECT_EQ(0, err.get_errno()); 99 EXPECT_EQ(nullptr, err.name()); 100 EXPECT_EQ(nullptr, err.description()); 101 #endif 102 103 // Ensure our new object has the same data but moved 104 EXPECT_EQ(errorVal, errNew.get_errno()); 105 EXPECT_EQ(name, errNew.name()); 106 EXPECT_EQ(message, errNew.description()); 107 EXPECT_EQ(what, errNew.what()); 108 109 // Move our SdBusError using the operator=() 110 errFinal = std::move(errNew); 111 112 // We are purposefully calling functions on a moved-from object, 113 // so we need to suppress the clang warnings. 114 #ifndef __clang_analyzer__ 115 // Ensure the old object was cleaned up 116 EXPECT_EQ(0, errNew.get_errno()); 117 EXPECT_EQ(nullptr, errNew.name()); 118 EXPECT_EQ(nullptr, errNew.description()); 119 #endif 120 } 121 122 // Ensure our new object has the same data but moved 123 EXPECT_EQ(errorVal, errFinal.get_errno()); 124 EXPECT_EQ(name, errFinal.name()); 125 EXPECT_EQ(message, errFinal.description()); 126 EXPECT_EQ(what, errFinal.what()); 127 128 sd_bus_error_free(&error); 129 } 130 131 TEST(SdBusError, BasicError) 132 { 133 const std::string name = "org.freedesktop.DBus.Error.Failed"; 134 const std::string description = "TestCase"; 135 const std::string prefix = "BasicError"; 136 137 sd_bus_error error = SD_BUS_ERROR_NULL; 138 sd_bus_error_set(&error, name.c_str(), description.c_str()); 139 EXPECT_TRUE(sd_bus_error_is_set(&error)); 140 const char* nameBeforeMove = error.name; 141 const int errorVal = sd_bus_error_get_errno(&error); 142 SdBusError err(&error, prefix.c_str()); 143 144 // We expect a move not copy 145 EXPECT_EQ(nameBeforeMove, err.name()); 146 147 // The SdBusError should have moved our error so it should be freeable 148 EXPECT_FALSE(sd_bus_error_is_set(&error)); 149 sd_bus_error_free(&error); 150 sd_bus_error_free(&error); 151 152 EXPECT_EQ(errorVal, err.get_errno()); 153 EXPECT_EQ(name, err.name()); 154 EXPECT_EQ(description, err.description()); 155 EXPECT_EQ(prefix + ": " + name + ": " + description, err.what()); 156 } 157 158 TEST(SdBusError, CatchBaseClassExceptions) 159 { 160 /* test each class in the chain: 161 * std::exception 162 * -> sdbusplus::exception::exception 163 * -> sdbusplus::exception::internal_exception 164 * -> sdbusplus::exception::SdBusError 165 */ 166 EXPECT_THROW({ throw SdBusError(-EINVAL, "SdBusError"); }, SdBusError); 167 EXPECT_THROW({ throw SdBusError(-EINVAL, "internal_exception"); }, 168 sdbusplus::exception::internal_exception); 169 EXPECT_THROW({ throw SdBusError(-EINVAL, "exception"); }, 170 sdbusplus::exception::exception); 171 EXPECT_THROW({ throw SdBusError(-EINVAL, "std::exception"); }, 172 std::exception); 173 } 174 175 } // namespace 176