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 EXPECT_EQ(std::string{error.name}, sdbusErr.name()); 38 EXPECT_EQ(std::string{error.message}, sdbusErr.description()); 39 std::exception& stdErr = sdbusErr; 40 EXPECT_EQ(prefix + ": " + error.name + ": " + error.message, stdErr.what()); 41 42 sd_bus_error_free(&error); 43 } 44 45 TEST(SdBusError, EnomemErrno) 46 { 47 // Make sure no exception is thrown on construction 48 SdBusError err(ENOMEM, "EnomemErrno"); 49 } 50 51 TEST(SdBusError, NotSetErrno) 52 { 53 const int errorVal = EBUSY; 54 55 sdbusplus::SdBusMock sdbus; 56 EXPECT_CALL(sdbus, sd_bus_error_set_errno(_, errorVal)) 57 .Times(1) 58 .WillOnce(Return(errorVal)); 59 EXPECT_CALL(sdbus, sd_bus_error_is_set(_)).Times(1).WillOnce(Return(false)); 60 EXPECT_THROW(SdBusError(errorVal, "NotSetErrno", &sdbus), 61 std::runtime_error); 62 } 63 64 TEST(SdBusError, Move) 65 { 66 const int errorVal = EIO; 67 const std::string prefix = "Move"; 68 69 // Build the reference sd_bus_error 70 sd_bus_error error = SD_BUS_ERROR_NULL; 71 EXPECT_EQ(-errorVal, sd_bus_error_set_errno(&error, errorVal)); 72 EXPECT_TRUE(sd_bus_error_is_set(&error)); 73 const std::string name{error.name}; 74 const std::string message{error.message}; 75 const std::string what = prefix + ": " + error.name + ": " + error.message; 76 77 SdBusError errFinal(EBUSY, "Move2"); 78 // Nest to make sure RAII works for moves 79 { 80 // Build our first SdBusError 81 SdBusError err(errorVal, prefix.c_str()); 82 83 EXPECT_EQ(name, err.name()); 84 EXPECT_EQ(message, err.description()); 85 EXPECT_EQ(what, err.what()); 86 87 // Move our SdBusError to a new one 88 SdBusError errNew(std::move(err)); 89 90 // Ensure the old object was cleaned up 91 EXPECT_EQ(nullptr, err.name()); 92 EXPECT_EQ(nullptr, err.description()); 93 EXPECT_EQ(std::string{}, err.what()); 94 95 // Ensure our new object has the same data but moved 96 EXPECT_EQ(name, errNew.name()); 97 EXPECT_EQ(message, errNew.description()); 98 EXPECT_EQ(what, errNew.what()); 99 100 // Move our SdBusError using the operator=() 101 errFinal = std::move(errNew); 102 103 // Ensure the old object was cleaned up 104 EXPECT_EQ(nullptr, errNew.name()); 105 EXPECT_EQ(nullptr, errNew.description()); 106 EXPECT_EQ(std::string{}, errNew.what()); 107 } 108 109 // Ensure our new object has the same data but moved 110 EXPECT_EQ(name, errFinal.name()); 111 EXPECT_EQ(message, errFinal.description()); 112 EXPECT_EQ(what, errFinal.what()); 113 114 sd_bus_error_free(&error); 115 } 116 117 TEST(SdBusError, BasicError) 118 { 119 const std::string name = "org.freedesktop.DBus.Error.Failed"; 120 const std::string description = "TestCase"; 121 const std::string prefix = "BasicError"; 122 123 sd_bus_error error = SD_BUS_ERROR_NULL; 124 sd_bus_error_set(&error, name.c_str(), description.c_str()); 125 EXPECT_TRUE(sd_bus_error_is_set(&error)); 126 const char* nameBeforeMove = error.name; 127 SdBusError err(&error, prefix.c_str()); 128 129 // We expect a move not copy 130 EXPECT_EQ(nameBeforeMove, err.name()); 131 132 // The SdBusError should have moved our error so it should be freeable 133 EXPECT_FALSE(sd_bus_error_is_set(&error)); 134 sd_bus_error_free(&error); 135 sd_bus_error_free(&error); 136 137 EXPECT_EQ(name, err.name()); 138 EXPECT_EQ(description, err.description()); 139 EXPECT_EQ(prefix + ": " + name + ": " + description, err.what()); 140 } 141 142 TEST(SdBusError, CatchBaseClassExceptions) 143 { 144 /* test each class in the chain: 145 * std::exception 146 * -> sdbusplus::exception::exception 147 * -> sdbusplus::exception::internal_exception 148 * -> sdbusplus::exception::SdBusError 149 */ 150 EXPECT_THROW({ throw SdBusError(-EINVAL, "SdBusError"); }, SdBusError); 151 EXPECT_THROW({ throw SdBusError(-EINVAL, "internal_exception"); }, 152 sdbusplus::exception::internal_exception); 153 EXPECT_THROW({ throw SdBusError(-EINVAL, "exception"); }, 154 sdbusplus::exception::exception); 155 EXPECT_THROW({ throw SdBusError(-EINVAL, "std::exception"); }, 156 std::exception); 157 } 158 159 } // namespace 160