1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/status/status.h"
16
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include "absl/strings/str_cat.h"
20
21 namespace {
22
23 using ::testing::Eq;
24 using ::testing::HasSubstr;
25 using ::testing::Optional;
26 using ::testing::UnorderedElementsAreArray;
27
TEST(StatusCode,InsertionOperator)28 TEST(StatusCode, InsertionOperator) {
29 const absl::StatusCode code = absl::StatusCode::kUnknown;
30 std::ostringstream oss;
31 oss << code;
32 EXPECT_EQ(oss.str(), absl::StatusCodeToString(code));
33 }
34
35 // This structure holds the details for testing a single error code,
36 // its creator, and its classifier.
37 struct ErrorTest {
38 absl::StatusCode code;
39 using Creator = absl::Status (*)(absl::string_view);
40 using Classifier = bool (*)(const absl::Status&);
41 Creator creator;
42 Classifier classifier;
43 };
44
45 constexpr ErrorTest kErrorTests[]{
46 {absl::StatusCode::kCancelled, absl::CancelledError, absl::IsCancelled},
47 {absl::StatusCode::kUnknown, absl::UnknownError, absl::IsUnknown},
48 {absl::StatusCode::kInvalidArgument, absl::InvalidArgumentError,
49 absl::IsInvalidArgument},
50 {absl::StatusCode::kDeadlineExceeded, absl::DeadlineExceededError,
51 absl::IsDeadlineExceeded},
52 {absl::StatusCode::kNotFound, absl::NotFoundError, absl::IsNotFound},
53 {absl::StatusCode::kAlreadyExists, absl::AlreadyExistsError,
54 absl::IsAlreadyExists},
55 {absl::StatusCode::kPermissionDenied, absl::PermissionDeniedError,
56 absl::IsPermissionDenied},
57 {absl::StatusCode::kResourceExhausted, absl::ResourceExhaustedError,
58 absl::IsResourceExhausted},
59 {absl::StatusCode::kFailedPrecondition, absl::FailedPreconditionError,
60 absl::IsFailedPrecondition},
61 {absl::StatusCode::kAborted, absl::AbortedError, absl::IsAborted},
62 {absl::StatusCode::kOutOfRange, absl::OutOfRangeError, absl::IsOutOfRange},
63 {absl::StatusCode::kUnimplemented, absl::UnimplementedError,
64 absl::IsUnimplemented},
65 {absl::StatusCode::kInternal, absl::InternalError, absl::IsInternal},
66 {absl::StatusCode::kUnavailable, absl::UnavailableError,
67 absl::IsUnavailable},
68 {absl::StatusCode::kDataLoss, absl::DataLossError, absl::IsDataLoss},
69 {absl::StatusCode::kUnauthenticated, absl::UnauthenticatedError,
70 absl::IsUnauthenticated},
71 };
72
TEST(Status,CreateAndClassify)73 TEST(Status, CreateAndClassify) {
74 for (const auto& test : kErrorTests) {
75 SCOPED_TRACE(absl::StatusCodeToString(test.code));
76
77 // Ensure that the creator does, in fact, create status objects with the
78 // expected error code and message.
79 std::string message =
80 absl::StrCat("error code ", test.code, " test message");
81 absl::Status status = test.creator(message);
82 EXPECT_EQ(test.code, status.code());
83 EXPECT_EQ(message, status.message());
84
85 // Ensure that the classifier returns true for a status produced by the
86 // creator.
87 EXPECT_TRUE(test.classifier(status));
88
89 // Ensure that the classifier returns false for status with a different
90 // code.
91 for (const auto& other : kErrorTests) {
92 if (other.code != test.code) {
93 EXPECT_FALSE(test.classifier(absl::Status(other.code, "")))
94 << " other.code = " << other.code;
95 }
96 }
97 }
98 }
99
TEST(Status,DefaultConstructor)100 TEST(Status, DefaultConstructor) {
101 absl::Status status;
102 EXPECT_TRUE(status.ok());
103 EXPECT_EQ(absl::StatusCode::kOk, status.code());
104 EXPECT_EQ("", status.message());
105 }
106
TEST(Status,OkStatus)107 TEST(Status, OkStatus) {
108 absl::Status status = absl::OkStatus();
109 EXPECT_TRUE(status.ok());
110 EXPECT_EQ(absl::StatusCode::kOk, status.code());
111 EXPECT_EQ("", status.message());
112 }
113
TEST(Status,ConstructorWithCodeMessage)114 TEST(Status, ConstructorWithCodeMessage) {
115 {
116 absl::Status status(absl::StatusCode::kCancelled, "");
117 EXPECT_FALSE(status.ok());
118 EXPECT_EQ(absl::StatusCode::kCancelled, status.code());
119 EXPECT_EQ("", status.message());
120 }
121 {
122 absl::Status status(absl::StatusCode::kInternal, "message");
123 EXPECT_FALSE(status.ok());
124 EXPECT_EQ(absl::StatusCode::kInternal, status.code());
125 EXPECT_EQ("message", status.message());
126 }
127 }
128
TEST(Status,ConstructOutOfRangeCode)129 TEST(Status, ConstructOutOfRangeCode) {
130 const int kRawCode = 9999;
131 absl::Status status(static_cast<absl::StatusCode>(kRawCode), "");
132 EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
133 EXPECT_EQ(kRawCode, status.raw_code());
134 }
135
136 constexpr char kUrl1[] = "url.payload.1";
137 constexpr char kUrl2[] = "url.payload.2";
138 constexpr char kUrl3[] = "url.payload.3";
139 constexpr char kUrl4[] = "url.payload.xx";
140
141 constexpr char kPayload1[] = "aaaaa";
142 constexpr char kPayload2[] = "bbbbb";
143 constexpr char kPayload3[] = "ccccc";
144
145 using PayloadsVec = std::vector<std::pair<std::string, absl::Cord>>;
146
TEST(Status,TestGetSetPayload)147 TEST(Status, TestGetSetPayload) {
148 absl::Status ok_status = absl::OkStatus();
149 ok_status.SetPayload(kUrl1, absl::Cord(kPayload1));
150 ok_status.SetPayload(kUrl2, absl::Cord(kPayload2));
151
152 EXPECT_FALSE(ok_status.GetPayload(kUrl1));
153 EXPECT_FALSE(ok_status.GetPayload(kUrl2));
154
155 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
156 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
157 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
158
159 EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload1)));
160 EXPECT_THAT(bad_status.GetPayload(kUrl2), Optional(Eq(kPayload2)));
161
162 EXPECT_FALSE(bad_status.GetPayload(kUrl3));
163
164 bad_status.SetPayload(kUrl1, absl::Cord(kPayload3));
165 EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload3)));
166
167 // Testing dynamically generated type_url
168 bad_status.SetPayload(absl::StrCat(kUrl1, ".1"), absl::Cord(kPayload1));
169 EXPECT_THAT(bad_status.GetPayload(absl::StrCat(kUrl1, ".1")),
170 Optional(Eq(kPayload1)));
171 }
172
TEST(Status,TestErasePayload)173 TEST(Status, TestErasePayload) {
174 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
175 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
176 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
177 bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
178
179 EXPECT_FALSE(bad_status.ErasePayload(kUrl4));
180
181 EXPECT_TRUE(bad_status.GetPayload(kUrl2));
182 EXPECT_TRUE(bad_status.ErasePayload(kUrl2));
183 EXPECT_FALSE(bad_status.GetPayload(kUrl2));
184 EXPECT_FALSE(bad_status.ErasePayload(kUrl2));
185
186 EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
187 EXPECT_TRUE(bad_status.ErasePayload(kUrl3));
188
189 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
190 EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
191 }
192
TEST(Status,TestComparePayloads)193 TEST(Status, TestComparePayloads) {
194 absl::Status bad_status1(absl::StatusCode::kInternal, "fail");
195 bad_status1.SetPayload(kUrl1, absl::Cord(kPayload1));
196 bad_status1.SetPayload(kUrl2, absl::Cord(kPayload2));
197 bad_status1.SetPayload(kUrl3, absl::Cord(kPayload3));
198
199 absl::Status bad_status2(absl::StatusCode::kInternal, "fail");
200 bad_status2.SetPayload(kUrl2, absl::Cord(kPayload2));
201 bad_status2.SetPayload(kUrl3, absl::Cord(kPayload3));
202 bad_status2.SetPayload(kUrl1, absl::Cord(kPayload1));
203
204 EXPECT_EQ(bad_status1, bad_status2);
205 }
206
AllVisitedPayloads(const absl::Status & s)207 PayloadsVec AllVisitedPayloads(const absl::Status& s) {
208 PayloadsVec result;
209
210 s.ForEachPayload([&](absl::string_view type_url, const absl::Cord& payload) {
211 result.push_back(std::make_pair(std::string(type_url), payload));
212 });
213
214 return result;
215 }
216
TEST(Status,TestForEachPayload)217 TEST(Status, TestForEachPayload) {
218 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
219 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
220 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
221 bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
222
223 int count = 0;
224
225 bad_status.ForEachPayload(
226 [&count](absl::string_view, const absl::Cord&) { ++count; });
227
228 EXPECT_EQ(count, 3);
229
230 PayloadsVec expected_payloads = {{kUrl1, absl::Cord(kPayload1)},
231 {kUrl2, absl::Cord(kPayload2)},
232 {kUrl3, absl::Cord(kPayload3)}};
233
234 // Test that we visit all the payloads in the status.
235 PayloadsVec visited_payloads = AllVisitedPayloads(bad_status);
236 EXPECT_THAT(visited_payloads, UnorderedElementsAreArray(expected_payloads));
237
238 // Test that visitation order is not consistent between run.
239 std::vector<absl::Status> scratch;
240 while (true) {
241 scratch.emplace_back(absl::StatusCode::kInternal, "fail");
242
243 scratch.back().SetPayload(kUrl1, absl::Cord(kPayload1));
244 scratch.back().SetPayload(kUrl2, absl::Cord(kPayload2));
245 scratch.back().SetPayload(kUrl3, absl::Cord(kPayload3));
246
247 if (AllVisitedPayloads(scratch.back()) != visited_payloads) {
248 break;
249 }
250 }
251 }
252
TEST(Status,ToString)253 TEST(Status, ToString) {
254 absl::Status s(absl::StatusCode::kInternal, "fail");
255 EXPECT_EQ("INTERNAL: fail", s.ToString());
256 s.SetPayload("foo", absl::Cord("bar"));
257 EXPECT_EQ("INTERNAL: fail [foo='bar']", s.ToString());
258 s.SetPayload("bar", absl::Cord("\377"));
259 EXPECT_THAT(s.ToString(),
260 AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
261 HasSubstr("[bar='\\xff']")));
262 }
263
TEST(Status,CopyConstructor)264 TEST(Status, CopyConstructor) {
265 {
266 absl::Status status;
267 absl::Status copy(status);
268 EXPECT_EQ(copy, status);
269 }
270 {
271 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
272 absl::Status copy(status);
273 EXPECT_EQ(copy, status);
274 }
275 {
276 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
277 status.SetPayload(kUrl1, absl::Cord(kPayload1));
278 absl::Status copy(status);
279 EXPECT_EQ(copy, status);
280 }
281 }
282
TEST(Status,CopyAssignment)283 TEST(Status, CopyAssignment) {
284 absl::Status assignee;
285 {
286 absl::Status status;
287 assignee = status;
288 EXPECT_EQ(assignee, status);
289 }
290 {
291 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
292 assignee = status;
293 EXPECT_EQ(assignee, status);
294 }
295 {
296 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
297 status.SetPayload(kUrl1, absl::Cord(kPayload1));
298 assignee = status;
299 EXPECT_EQ(assignee, status);
300 }
301 }
302
TEST(Status,MoveConstructor)303 TEST(Status, MoveConstructor) {
304 {
305 absl::Status status;
306 absl::Status copy(absl::Status{});
307 EXPECT_EQ(copy, status);
308 }
309 {
310 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
311 absl::Status copy(
312 absl::Status(absl::StatusCode::kInvalidArgument, "message"));
313 EXPECT_EQ(copy, status);
314 }
315 {
316 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
317 status.SetPayload(kUrl1, absl::Cord(kPayload1));
318 absl::Status copy1(status);
319 absl::Status copy2(std::move(status));
320 EXPECT_EQ(copy1, copy2);
321 }
322 }
323
TEST(Status,MoveAssignment)324 TEST(Status, MoveAssignment) {
325 absl::Status assignee;
326 {
327 absl::Status status;
328 assignee = absl::Status();
329 EXPECT_EQ(assignee, status);
330 }
331 {
332 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
333 assignee = absl::Status(absl::StatusCode::kInvalidArgument, "message");
334 EXPECT_EQ(assignee, status);
335 }
336 {
337 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
338 status.SetPayload(kUrl1, absl::Cord(kPayload1));
339 absl::Status copy(status);
340 assignee = std::move(status);
341 EXPECT_EQ(assignee, copy);
342 }
343 }
344
TEST(Status,Update)345 TEST(Status, Update) {
346 absl::Status s;
347 s.Update(absl::OkStatus());
348 EXPECT_TRUE(s.ok());
349 const absl::Status a(absl::StatusCode::kCancelled, "message");
350 s.Update(a);
351 EXPECT_EQ(s, a);
352 const absl::Status b(absl::StatusCode::kInternal, "other message");
353 s.Update(b);
354 EXPECT_EQ(s, a);
355 s.Update(absl::OkStatus());
356 EXPECT_EQ(s, a);
357 EXPECT_FALSE(s.ok());
358 }
359
TEST(Status,Equality)360 TEST(Status, Equality) {
361 absl::Status ok;
362 absl::Status no_payload = absl::CancelledError("no payload");
363 absl::Status one_payload = absl::InvalidArgumentError("one payload");
364 one_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
365 absl::Status two_payloads = one_payload;
366 two_payloads.SetPayload(kUrl2, absl::Cord(kPayload2));
367 const std::array<absl::Status, 4> status_arr = {ok, no_payload, one_payload,
368 two_payloads};
369 for (int i = 0; i < status_arr.size(); i++) {
370 for (int j = 0; j < status_arr.size(); j++) {
371 if (i == j) {
372 EXPECT_TRUE(status_arr[i] == status_arr[j]);
373 EXPECT_FALSE(status_arr[i] != status_arr[j]);
374 } else {
375 EXPECT_TRUE(status_arr[i] != status_arr[j]);
376 EXPECT_FALSE(status_arr[i] == status_arr[j]);
377 }
378 }
379 }
380 }
381
TEST(Status,Swap)382 TEST(Status, Swap) {
383 auto test_swap = [](const absl::Status& s1, const absl::Status& s2) {
384 absl::Status copy1 = s1, copy2 = s2;
385 swap(copy1, copy2);
386 EXPECT_EQ(copy1, s2);
387 EXPECT_EQ(copy2, s1);
388 };
389 const absl::Status ok;
390 const absl::Status no_payload(absl::StatusCode::kAlreadyExists, "no payload");
391 absl::Status with_payload(absl::StatusCode::kInternal, "with payload");
392 with_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
393 test_swap(ok, no_payload);
394 test_swap(no_payload, ok);
395 test_swap(ok, with_payload);
396 test_swap(with_payload, ok);
397 test_swap(no_payload, with_payload);
398 test_swap(with_payload, no_payload);
399 }
400
401 } // namespace
402