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 // Ensure the old object was cleaned up 95 EXPECT_EQ(0, err.get_errno()); 96 EXPECT_EQ(nullptr, err.name()); 97 EXPECT_EQ(nullptr, err.description()); 98 EXPECT_EQ(std::string{}, err.what()); 99 100 // Ensure our new object has the same data but moved 101 EXPECT_EQ(errorVal, errNew.get_errno()); 102 EXPECT_EQ(name, errNew.name()); 103 EXPECT_EQ(message, errNew.description()); 104 EXPECT_EQ(what, errNew.what()); 105 106 // Move our SdBusError using the operator=() 107 errFinal = std::move(errNew); 108 109 // Ensure the old object was cleaned up 110 EXPECT_EQ(0, errNew.get_errno()); 111 EXPECT_EQ(nullptr, errNew.name()); 112 EXPECT_EQ(nullptr, errNew.description()); 113 EXPECT_EQ(std::string{}, errNew.what()); 114 } 115 116 // Ensure our new object has the same data but moved 117 EXPECT_EQ(errorVal, errFinal.get_errno()); 118 EXPECT_EQ(name, errFinal.name()); 119 EXPECT_EQ(message, errFinal.description()); 120 EXPECT_EQ(what, errFinal.what()); 121 122 sd_bus_error_free(&error); 123 } 124 125 TEST(SdBusError, BasicError) 126 { 127 const std::string name = "org.freedesktop.DBus.Error.Failed"; 128 const std::string description = "TestCase"; 129 const std::string prefix = "BasicError"; 130 131 sd_bus_error error = SD_BUS_ERROR_NULL; 132 sd_bus_error_set(&error, name.c_str(), description.c_str()); 133 EXPECT_TRUE(sd_bus_error_is_set(&error)); 134 const char* nameBeforeMove = error.name; 135 const int errorVal = sd_bus_error_get_errno(&error); 136 SdBusError err(&error, prefix.c_str()); 137 138 // We expect a move not copy 139 EXPECT_EQ(nameBeforeMove, err.name()); 140 141 // The SdBusError should have moved our error so it should be freeable 142 EXPECT_FALSE(sd_bus_error_is_set(&error)); 143 sd_bus_error_free(&error); 144 sd_bus_error_free(&error); 145 146 EXPECT_EQ(errorVal, err.get_errno()); 147 EXPECT_EQ(name, err.name()); 148 EXPECT_EQ(description, err.description()); 149 EXPECT_EQ(prefix + ": " + name + ": " + description, err.what()); 150 } 151 152 TEST(SdBusError, CatchBaseClassExceptions) 153 { 154 /* test each class in the chain: 155 * std::exception 156 * -> sdbusplus::exception::exception 157 * -> sdbusplus::exception::internal_exception 158 * -> sdbusplus::exception::SdBusError 159 */ 160 EXPECT_THROW({ throw SdBusError(-EINVAL, "SdBusError"); }, SdBusError); 161 EXPECT_THROW({ throw SdBusError(-EINVAL, "internal_exception"); }, 162 sdbusplus::exception::internal_exception); 163 EXPECT_THROW({ throw SdBusError(-EINVAL, "exception"); }, 164 sdbusplus::exception::exception); 165 EXPECT_THROW({ throw SdBusError(-EINVAL, "std::exception"); }, 166 std::exception); 167 } 168 169 } // namespace 170