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