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