• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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