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