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 <errno.h>
18
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "absl/strings/str_cat.h"
22
23 namespace {
24
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27 using ::testing::Optional;
28 using ::testing::UnorderedElementsAreArray;
29
TEST(StatusCode,InsertionOperator)30 TEST(StatusCode, InsertionOperator) {
31 const absl::StatusCode code = absl::StatusCode::kUnknown;
32 std::ostringstream oss;
33 oss << code;
34 EXPECT_EQ(oss.str(), absl::StatusCodeToString(code));
35 }
36
37 // This structure holds the details for testing a single error code,
38 // its creator, and its classifier.
39 struct ErrorTest {
40 absl::StatusCode code;
41 using Creator = absl::Status (*)(
42 absl::string_view
43 );
44 using Classifier = bool (*)(const absl::Status&);
45 Creator creator;
46 Classifier classifier;
47 };
48
49 constexpr ErrorTest kErrorTests[]{
50 {absl::StatusCode::kCancelled, absl::CancelledError, absl::IsCancelled},
51 {absl::StatusCode::kUnknown, absl::UnknownError, absl::IsUnknown},
52 {absl::StatusCode::kInvalidArgument, absl::InvalidArgumentError,
53 absl::IsInvalidArgument},
54 {absl::StatusCode::kDeadlineExceeded, absl::DeadlineExceededError,
55 absl::IsDeadlineExceeded},
56 {absl::StatusCode::kNotFound, absl::NotFoundError, absl::IsNotFound},
57 {absl::StatusCode::kAlreadyExists, absl::AlreadyExistsError,
58 absl::IsAlreadyExists},
59 {absl::StatusCode::kPermissionDenied, absl::PermissionDeniedError,
60 absl::IsPermissionDenied},
61 {absl::StatusCode::kResourceExhausted, absl::ResourceExhaustedError,
62 absl::IsResourceExhausted},
63 {absl::StatusCode::kFailedPrecondition, absl::FailedPreconditionError,
64 absl::IsFailedPrecondition},
65 {absl::StatusCode::kAborted, absl::AbortedError, absl::IsAborted},
66 {absl::StatusCode::kOutOfRange, absl::OutOfRangeError, absl::IsOutOfRange},
67 {absl::StatusCode::kUnimplemented, absl::UnimplementedError,
68 absl::IsUnimplemented},
69 {absl::StatusCode::kInternal, absl::InternalError, absl::IsInternal},
70 {absl::StatusCode::kUnavailable, absl::UnavailableError,
71 absl::IsUnavailable},
72 {absl::StatusCode::kDataLoss, absl::DataLossError, absl::IsDataLoss},
73 {absl::StatusCode::kUnauthenticated, absl::UnauthenticatedError,
74 absl::IsUnauthenticated},
75 };
76
TEST(Status,CreateAndClassify)77 TEST(Status, CreateAndClassify) {
78 for (const auto& test : kErrorTests) {
79 SCOPED_TRACE(absl::StatusCodeToString(test.code));
80
81 // Ensure that the creator does, in fact, create status objects with the
82 // expected error code and message.
83 std::string message =
84 absl::StrCat("error code ", test.code, " test message");
85 absl::Status status = test.creator(
86 message
87 );
88 EXPECT_EQ(test.code, status.code());
89 EXPECT_EQ(message, status.message());
90
91 // Ensure that the classifier returns true for a status produced by the
92 // creator.
93 EXPECT_TRUE(test.classifier(status));
94
95 // Ensure that the classifier returns false for status with a different
96 // code.
97 for (const auto& other : kErrorTests) {
98 if (other.code != test.code) {
99 EXPECT_FALSE(test.classifier(absl::Status(other.code, "")))
100 << " other.code = " << other.code;
101 }
102 }
103 }
104 }
105
TEST(Status,DefaultConstructor)106 TEST(Status, DefaultConstructor) {
107 absl::Status status;
108 EXPECT_TRUE(status.ok());
109 EXPECT_EQ(absl::StatusCode::kOk, status.code());
110 EXPECT_EQ("", status.message());
111 }
112
TEST(Status,OkStatus)113 TEST(Status, OkStatus) {
114 absl::Status status = absl::OkStatus();
115 EXPECT_TRUE(status.ok());
116 EXPECT_EQ(absl::StatusCode::kOk, status.code());
117 EXPECT_EQ("", status.message());
118 }
119
TEST(Status,ConstructorWithCodeMessage)120 TEST(Status, ConstructorWithCodeMessage) {
121 {
122 absl::Status status(absl::StatusCode::kCancelled, "");
123 EXPECT_FALSE(status.ok());
124 EXPECT_EQ(absl::StatusCode::kCancelled, status.code());
125 EXPECT_EQ("", status.message());
126 }
127 {
128 absl::Status status(absl::StatusCode::kInternal, "message");
129 EXPECT_FALSE(status.ok());
130 EXPECT_EQ(absl::StatusCode::kInternal, status.code());
131 EXPECT_EQ("message", status.message());
132 }
133 }
134
TEST(Status,StatusMessageCStringTest)135 TEST(Status, StatusMessageCStringTest) {
136 {
137 absl::Status status = absl::OkStatus();
138 EXPECT_EQ(status.message(), "");
139 EXPECT_STREQ(absl::StatusMessageAsCStr(status), "");
140 EXPECT_EQ(status.message(), absl::StatusMessageAsCStr(status));
141 EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr);
142 }
143 {
144 absl::Status status;
145 EXPECT_EQ(status.message(), "");
146 EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr);
147 EXPECT_STREQ(absl::StatusMessageAsCStr(status), "");
148 }
149 {
150 absl::Status status(absl::StatusCode::kInternal, "message");
151 EXPECT_FALSE(status.ok());
152 EXPECT_EQ(absl::StatusCode::kInternal, status.code());
153 EXPECT_EQ("message", status.message());
154 EXPECT_STREQ("message", absl::StatusMessageAsCStr(status));
155 }
156 }
157
TEST(Status,ConstructOutOfRangeCode)158 TEST(Status, ConstructOutOfRangeCode) {
159 const int kRawCode = 9999;
160 absl::Status status(static_cast<absl::StatusCode>(kRawCode), "");
161 EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
162 EXPECT_EQ(kRawCode, status.raw_code());
163 }
164
165 constexpr char kUrl1[] = "url.payload.1";
166 constexpr char kUrl2[] = "url.payload.2";
167 constexpr char kUrl3[] = "url.payload.3";
168 constexpr char kUrl4[] = "url.payload.xx";
169
170 constexpr char kPayload1[] = "aaaaa";
171 constexpr char kPayload2[] = "bbbbb";
172 constexpr char kPayload3[] = "ccccc";
173
174 using PayloadsVec = std::vector<std::pair<std::string, absl::Cord>>;
175
TEST(Status,TestGetSetPayload)176 TEST(Status, TestGetSetPayload) {
177 absl::Status ok_status = absl::OkStatus();
178 ok_status.SetPayload(kUrl1, absl::Cord(kPayload1));
179 ok_status.SetPayload(kUrl2, absl::Cord(kPayload2));
180
181 EXPECT_FALSE(ok_status.GetPayload(kUrl1));
182 EXPECT_FALSE(ok_status.GetPayload(kUrl2));
183
184 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
185 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
186 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
187
188 EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload1)));
189 EXPECT_THAT(bad_status.GetPayload(kUrl2), Optional(Eq(kPayload2)));
190
191 EXPECT_FALSE(bad_status.GetPayload(kUrl3));
192
193 bad_status.SetPayload(kUrl1, absl::Cord(kPayload3));
194 EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload3)));
195
196 // Testing dynamically generated type_url
197 bad_status.SetPayload(absl::StrCat(kUrl1, ".1"), absl::Cord(kPayload1));
198 EXPECT_THAT(bad_status.GetPayload(absl::StrCat(kUrl1, ".1")),
199 Optional(Eq(kPayload1)));
200 }
201
TEST(Status,TestErasePayload)202 TEST(Status, TestErasePayload) {
203 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
204 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
205 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
206 bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
207
208 EXPECT_FALSE(bad_status.ErasePayload(kUrl4));
209
210 EXPECT_TRUE(bad_status.GetPayload(kUrl2));
211 EXPECT_TRUE(bad_status.ErasePayload(kUrl2));
212 EXPECT_FALSE(bad_status.GetPayload(kUrl2));
213 EXPECT_FALSE(bad_status.ErasePayload(kUrl2));
214
215 EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
216 EXPECT_TRUE(bad_status.ErasePayload(kUrl3));
217
218 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
219 EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
220 }
221
TEST(Status,TestComparePayloads)222 TEST(Status, TestComparePayloads) {
223 absl::Status bad_status1(absl::StatusCode::kInternal, "fail");
224 bad_status1.SetPayload(kUrl1, absl::Cord(kPayload1));
225 bad_status1.SetPayload(kUrl2, absl::Cord(kPayload2));
226 bad_status1.SetPayload(kUrl3, absl::Cord(kPayload3));
227
228 absl::Status bad_status2(absl::StatusCode::kInternal, "fail");
229 bad_status2.SetPayload(kUrl2, absl::Cord(kPayload2));
230 bad_status2.SetPayload(kUrl3, absl::Cord(kPayload3));
231 bad_status2.SetPayload(kUrl1, absl::Cord(kPayload1));
232
233 EXPECT_EQ(bad_status1, bad_status2);
234 }
235
TEST(Status,TestComparePayloadsAfterErase)236 TEST(Status, TestComparePayloadsAfterErase) {
237 absl::Status payload_status(absl::StatusCode::kInternal, "");
238 payload_status.SetPayload(kUrl1, absl::Cord(kPayload1));
239 payload_status.SetPayload(kUrl2, absl::Cord(kPayload2));
240
241 absl::Status empty_status(absl::StatusCode::kInternal, "");
242
243 // Different payloads, not equal
244 EXPECT_NE(payload_status, empty_status);
245 EXPECT_TRUE(payload_status.ErasePayload(kUrl1));
246
247 // Still Different payloads, still not equal.
248 EXPECT_NE(payload_status, empty_status);
249 EXPECT_TRUE(payload_status.ErasePayload(kUrl2));
250
251 // Both empty payloads, should be equal
252 EXPECT_EQ(payload_status, empty_status);
253 }
254
AllVisitedPayloads(const absl::Status & s)255 PayloadsVec AllVisitedPayloads(const absl::Status& s) {
256 PayloadsVec result;
257
258 s.ForEachPayload([&](absl::string_view type_url, const absl::Cord& payload) {
259 result.push_back(std::make_pair(std::string(type_url), payload));
260 });
261
262 return result;
263 }
264
TEST(Status,TestForEachPayload)265 TEST(Status, TestForEachPayload) {
266 absl::Status bad_status(absl::StatusCode::kInternal, "fail");
267 bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
268 bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
269 bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
270
271 int count = 0;
272
273 bad_status.ForEachPayload(
274 [&count](absl::string_view, const absl::Cord&) { ++count; });
275
276 EXPECT_EQ(count, 3);
277
278 PayloadsVec expected_payloads = {{kUrl1, absl::Cord(kPayload1)},
279 {kUrl2, absl::Cord(kPayload2)},
280 {kUrl3, absl::Cord(kPayload3)}};
281
282 // Test that we visit all the payloads in the status.
283 PayloadsVec visited_payloads = AllVisitedPayloads(bad_status);
284 EXPECT_THAT(visited_payloads, UnorderedElementsAreArray(expected_payloads));
285
286 // Test that visitation order is not consistent between run.
287 std::vector<absl::Status> scratch;
288 while (true) {
289 scratch.emplace_back(absl::StatusCode::kInternal, "fail");
290
291 scratch.back().SetPayload(kUrl1, absl::Cord(kPayload1));
292 scratch.back().SetPayload(kUrl2, absl::Cord(kPayload2));
293 scratch.back().SetPayload(kUrl3, absl::Cord(kPayload3));
294
295 if (AllVisitedPayloads(scratch.back()) != visited_payloads) {
296 break;
297 }
298 }
299 }
300
TEST(Status,ToString)301 TEST(Status, ToString) {
302 absl::Status s(absl::StatusCode::kInternal, "fail");
303 EXPECT_EQ("INTERNAL: fail", s.ToString());
304 s.SetPayload("foo", absl::Cord("bar"));
305 EXPECT_EQ("INTERNAL: fail [foo='bar']", s.ToString());
306 s.SetPayload("bar", absl::Cord("\377"));
307 EXPECT_THAT(s.ToString(),
308 AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
309 HasSubstr("[bar='\\xff']")));
310 }
311
TEST(Status,ToStringMode)312 TEST(Status, ToStringMode) {
313 absl::Status s(absl::StatusCode::kInternal, "fail");
314 s.SetPayload("foo", absl::Cord("bar"));
315 s.SetPayload("bar", absl::Cord("\377"));
316
317 EXPECT_EQ("INTERNAL: fail",
318 s.ToString(absl::StatusToStringMode::kWithNoExtraData));
319
320 EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithPayload),
321 AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
322 HasSubstr("[bar='\\xff']")));
323
324 EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithEverything),
325 AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
326 HasSubstr("[bar='\\xff']")));
327
328 EXPECT_THAT(s.ToString(~absl::StatusToStringMode::kWithPayload),
329 AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")),
330 Not(HasSubstr("[bar='\\xff']"))));
331 }
332
EraseAndReturn(const absl::Status & base)333 absl::Status EraseAndReturn(const absl::Status& base) {
334 absl::Status copy = base;
335 EXPECT_TRUE(copy.ErasePayload(kUrl1));
336 return copy;
337 }
338
TEST(Status,CopyOnWriteForErasePayload)339 TEST(Status, CopyOnWriteForErasePayload) {
340 {
341 absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
342 base.SetPayload(kUrl1, absl::Cord(kPayload1));
343 EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
344 absl::Status copy = EraseAndReturn(base);
345 EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
346 EXPECT_FALSE(copy.GetPayload(kUrl1).has_value());
347 }
348 {
349 absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
350 base.SetPayload(kUrl1, absl::Cord(kPayload1));
351 absl::Status copy = base;
352
353 EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
354 EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
355
356 EXPECT_TRUE(base.ErasePayload(kUrl1));
357
358 EXPECT_FALSE(base.GetPayload(kUrl1).has_value());
359 EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
360 }
361 }
362
TEST(Status,CopyConstructor)363 TEST(Status, CopyConstructor) {
364 {
365 absl::Status status;
366 absl::Status copy(status);
367 EXPECT_EQ(copy, status);
368 }
369 {
370 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
371 absl::Status copy(status);
372 EXPECT_EQ(copy, status);
373 }
374 {
375 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
376 status.SetPayload(kUrl1, absl::Cord(kPayload1));
377 absl::Status copy(status);
378 EXPECT_EQ(copy, status);
379 }
380 }
381
TEST(Status,CopyAssignment)382 TEST(Status, CopyAssignment) {
383 absl::Status assignee;
384 {
385 absl::Status status;
386 assignee = status;
387 EXPECT_EQ(assignee, status);
388 }
389 {
390 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
391 assignee = status;
392 EXPECT_EQ(assignee, status);
393 }
394 {
395 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
396 status.SetPayload(kUrl1, absl::Cord(kPayload1));
397 assignee = status;
398 EXPECT_EQ(assignee, status);
399 }
400 }
401
TEST(Status,CopyAssignmentIsNotRef)402 TEST(Status, CopyAssignmentIsNotRef) {
403 const absl::Status status_orig(absl::StatusCode::kInvalidArgument, "message");
404 absl::Status status_copy = status_orig;
405 EXPECT_EQ(status_orig, status_copy);
406 status_copy.SetPayload(kUrl1, absl::Cord(kPayload1));
407 EXPECT_NE(status_orig, status_copy);
408 }
409
TEST(Status,MoveConstructor)410 TEST(Status, MoveConstructor) {
411 {
412 absl::Status status;
413 absl::Status copy(absl::Status{});
414 EXPECT_EQ(copy, status);
415 }
416 {
417 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
418 absl::Status copy(
419 absl::Status(absl::StatusCode::kInvalidArgument, "message"));
420 EXPECT_EQ(copy, status);
421 }
422 {
423 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
424 status.SetPayload(kUrl1, absl::Cord(kPayload1));
425 absl::Status copy1(status);
426 absl::Status copy2(std::move(status));
427 EXPECT_EQ(copy1, copy2);
428 }
429 }
430
TEST(Status,MoveAssignment)431 TEST(Status, MoveAssignment) {
432 absl::Status assignee;
433 {
434 absl::Status status;
435 assignee = absl::Status();
436 EXPECT_EQ(assignee, status);
437 }
438 {
439 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
440 assignee = absl::Status(absl::StatusCode::kInvalidArgument, "message");
441 EXPECT_EQ(assignee, status);
442 }
443 {
444 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
445 status.SetPayload(kUrl1, absl::Cord(kPayload1));
446 absl::Status copy(status);
447 assignee = std::move(status);
448 EXPECT_EQ(assignee, copy);
449 }
450 {
451 absl::Status status(absl::StatusCode::kInvalidArgument, "message");
452 absl::Status copy(status);
453 status = static_cast<absl::Status&&>(status);
454 EXPECT_EQ(status, copy);
455 }
456 }
457
TEST(Status,Update)458 TEST(Status, Update) {
459 absl::Status s;
460 s.Update(absl::OkStatus());
461 EXPECT_TRUE(s.ok());
462 const absl::Status a(absl::StatusCode::kCancelled, "message");
463 s.Update(a);
464 EXPECT_EQ(s, a);
465 const absl::Status b(absl::StatusCode::kInternal, "other message");
466 s.Update(b);
467 EXPECT_EQ(s, a);
468 s.Update(absl::OkStatus());
469 EXPECT_EQ(s, a);
470 EXPECT_FALSE(s.ok());
471 }
472
TEST(Status,Equality)473 TEST(Status, Equality) {
474 absl::Status ok;
475 absl::Status no_payload = absl::CancelledError("no payload");
476 absl::Status one_payload = absl::InvalidArgumentError("one payload");
477 one_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
478 absl::Status two_payloads = one_payload;
479 two_payloads.SetPayload(kUrl2, absl::Cord(kPayload2));
480 const std::array<absl::Status, 4> status_arr = {ok, no_payload, one_payload,
481 two_payloads};
482 for (int i = 0; i < status_arr.size(); i++) {
483 for (int j = 0; j < status_arr.size(); j++) {
484 if (i == j) {
485 EXPECT_TRUE(status_arr[i] == status_arr[j]);
486 EXPECT_FALSE(status_arr[i] != status_arr[j]);
487 } else {
488 EXPECT_TRUE(status_arr[i] != status_arr[j]);
489 EXPECT_FALSE(status_arr[i] == status_arr[j]);
490 }
491 }
492 }
493 }
494
TEST(Status,Swap)495 TEST(Status, Swap) {
496 auto test_swap = [](const absl::Status& s1, const absl::Status& s2) {
497 absl::Status copy1 = s1, copy2 = s2;
498 swap(copy1, copy2);
499 EXPECT_EQ(copy1, s2);
500 EXPECT_EQ(copy2, s1);
501 };
502 const absl::Status ok;
503 const absl::Status no_payload(absl::StatusCode::kAlreadyExists, "no payload");
504 absl::Status with_payload(absl::StatusCode::kInternal, "with payload");
505 with_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
506 test_swap(ok, no_payload);
507 test_swap(no_payload, ok);
508 test_swap(ok, with_payload);
509 test_swap(with_payload, ok);
510 test_swap(no_payload, with_payload);
511 test_swap(with_payload, no_payload);
512 }
513
TEST(StatusErrno,ErrnoToStatusCode)514 TEST(StatusErrno, ErrnoToStatusCode) {
515 EXPECT_EQ(absl::ErrnoToStatusCode(0), absl::StatusCode::kOk);
516
517 // Spot-check a few errno values.
518 EXPECT_EQ(absl::ErrnoToStatusCode(EINVAL),
519 absl::StatusCode::kInvalidArgument);
520 EXPECT_EQ(absl::ErrnoToStatusCode(ENOENT), absl::StatusCode::kNotFound);
521
522 // We'll pick a very large number so it hopefully doesn't collide to errno.
523 EXPECT_EQ(absl::ErrnoToStatusCode(19980927), absl::StatusCode::kUnknown);
524 }
525
TEST(StatusErrno,ErrnoToStatus)526 TEST(StatusErrno, ErrnoToStatus) {
527 absl::Status status = absl::ErrnoToStatus(ENOENT, "Cannot open 'path'");
528 EXPECT_EQ(status.code(), absl::StatusCode::kNotFound);
529 EXPECT_EQ(status.message(), "Cannot open 'path': No such file or directory");
530 }
531
532 } // namespace
533