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