• 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 "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