gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/posix_error.h (about) 1 // Copyright 2018 The gVisor 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 // http://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 #ifndef GVISOR_TEST_UTIL_POSIX_ERROR_H_ 16 #define GVISOR_TEST_UTIL_POSIX_ERROR_H_ 17 18 #include <string> 19 20 #include "gmock/gmock.h" 21 #include "absl/base/attributes.h" 22 #include "absl/strings/string_view.h" 23 #include "absl/types/variant.h" 24 #include "test/util/logging.h" 25 26 namespace gvisor { 27 namespace testing { 28 29 // PosixError must be async-signal-safe. 30 class ABSL_MUST_USE_RESULT PosixError { 31 public: 32 PosixError() {} 33 34 explicit PosixError(int errno_value) : errno_(errno_value) {} 35 36 PosixError(int errno_value, std::string_view msg) : errno_(errno_value) { 37 // Check that `msg` will fit, leaving room for '\0' at the end. 38 TEST_CHECK(msg.size() < sizeof(msg_)); 39 msg.copy(msg_, msg.size()); 40 } 41 42 PosixError(PosixError&& other) = default; 43 PosixError& operator=(PosixError&& other) = default; 44 PosixError(const PosixError&) = default; 45 PosixError& operator=(const PosixError&) = default; 46 47 bool ok() const { return errno_ == 0; } 48 49 // Returns a reference to *this to make matchers compatible with 50 // PosixErrorOr. 51 const PosixError& error() const { return *this; } 52 53 int errno_value() const { return errno_; } 54 const char* message() const { return msg_; } 55 56 // ToString produces a full string representation of this posix error 57 // including the printable representation of the errno and the error message. 58 std::string ToString() const; 59 60 // Ignores any errors. This method does nothing except potentially suppress 61 // complaints from any tools that are checking that errors are not dropped on 62 // the floor. 63 void IgnoreError() const {} 64 65 private: 66 int errno_ = 0; 67 // std::string is not async-signal-safe. We must use a c string instead. 68 char msg_[1024] = {}; 69 }; 70 71 template <typename T> 72 class ABSL_MUST_USE_RESULT PosixErrorOr { 73 public: 74 // A PosixErrorOr will check fail if it is constructed with NoError(). 75 PosixErrorOr(const PosixError& error); 76 PosixErrorOr(const T& value); 77 PosixErrorOr(T&& value); 78 79 PosixErrorOr(PosixErrorOr&& other) = default; 80 PosixErrorOr& operator=(PosixErrorOr&& other) = default; 81 PosixErrorOr(const PosixErrorOr&) = default; 82 PosixErrorOr& operator=(const PosixErrorOr&) = default; 83 84 // Conversion copy/move constructor, T must be convertible from U. 85 template <typename U> 86 friend class PosixErrorOr; 87 88 template <typename U> 89 PosixErrorOr(PosixErrorOr<U> other); 90 91 template <typename U> 92 PosixErrorOr& operator=(PosixErrorOr<U> other); 93 94 // Returns true if this PosixErrorOr contains some T. 95 bool ok() const; 96 97 // Return a copy of the contained PosixError or NoError(). 98 PosixError error() const; 99 100 // Returns a reference to our current value, or CHECK-fails if !this->ok(). 101 const T& ValueOrDie() const&; 102 T& ValueOrDie() &; 103 const T&& ValueOrDie() const&&; 104 T&& ValueOrDie() &&; 105 106 // Ignores any errors. This method does nothing except potentially suppress 107 // complaints from any tools that are checking that errors are not dropped on 108 // the floor. 109 void IgnoreError() const {} 110 111 private: 112 absl::variant<T, PosixError> value_; 113 114 friend class PosixErrorIsMatcherCommonImpl; 115 }; 116 117 template <typename T> 118 PosixErrorOr<T>::PosixErrorOr(const PosixError& error) : value_(error) { 119 TEST_CHECK_MSG( 120 !error.ok(), 121 "Constructing PosixErrorOr with NoError, eg. errno 0 is not allowed."); 122 } 123 124 template <typename T> 125 PosixErrorOr<T>::PosixErrorOr(const T& value) : value_(value) {} 126 127 template <typename T> 128 PosixErrorOr<T>::PosixErrorOr(T&& value) : value_(std::move(value)) {} 129 130 // Conversion copy/move constructor, T must be convertible from U. 131 template <typename T> 132 template <typename U> 133 inline PosixErrorOr<T>::PosixErrorOr(PosixErrorOr<U> other) { 134 if (absl::holds_alternative<U>(other.value_)) { 135 // T is convertible from U. 136 value_ = absl::get<U>(std::move(other.value_)); 137 } else if (absl::holds_alternative<PosixError>(other.value_)) { 138 value_ = absl::get<PosixError>(std::move(other.value_)); 139 } else { 140 TEST_CHECK_MSG(false, "PosixErrorOr does not contain PosixError or value"); 141 } 142 } 143 144 template <typename T> 145 template <typename U> 146 inline PosixErrorOr<T>& PosixErrorOr<T>::operator=(PosixErrorOr<U> other) { 147 if (absl::holds_alternative<U>(other.value_)) { 148 // T is convertible from U. 149 value_ = absl::get<U>(std::move(other.value_)); 150 } else if (absl::holds_alternative<PosixError>(other.value_)) { 151 value_ = absl::get<PosixError>(std::move(other.value_)); 152 } else { 153 TEST_CHECK_MSG(false, "PosixErrorOr does not contain PosixError or value"); 154 } 155 return *this; 156 } 157 158 template <typename T> 159 PosixError PosixErrorOr<T>::error() const { 160 if (!absl::holds_alternative<PosixError>(value_)) { 161 return PosixError(); 162 } 163 return absl::get<PosixError>(value_); 164 } 165 166 template <typename T> 167 bool PosixErrorOr<T>::ok() const { 168 return absl::holds_alternative<T>(value_); 169 } 170 171 template <typename T> 172 const T& PosixErrorOr<T>::ValueOrDie() const& { 173 TEST_CHECK(absl::holds_alternative<T>(value_)); 174 return absl::get<T>(value_); 175 } 176 177 template <typename T> 178 T& PosixErrorOr<T>::ValueOrDie() & { 179 TEST_CHECK(absl::holds_alternative<T>(value_)); 180 return absl::get<T>(value_); 181 } 182 183 template <typename T> 184 const T&& PosixErrorOr<T>::ValueOrDie() const&& { 185 TEST_CHECK(absl::holds_alternative<T>(value_)); 186 return std::move(absl::get<T>(value_)); 187 } 188 189 template <typename T> 190 T&& PosixErrorOr<T>::ValueOrDie() && { 191 TEST_CHECK(absl::holds_alternative<T>(value_)); 192 return std::move(absl::get<T>(value_)); 193 } 194 195 extern ::std::ostream& operator<<(::std::ostream& os, const PosixError& e); 196 197 template <typename T> 198 ::std::ostream& operator<<(::std::ostream& os, const PosixErrorOr<T>& e) { 199 os << e.error(); 200 return os; 201 } 202 203 // NoError is a PosixError that represents a successful state, i.e. No Error. 204 inline PosixError NoError() { return PosixError(); } 205 206 // Monomorphic implementation of matcher IsPosixErrorOk() for a given type T. 207 // T can be PosixError, PosixErrorOr<>, or a reference to either of them. 208 template <typename T> 209 class MonoPosixErrorIsOkMatcherImpl : public ::testing::MatcherInterface<T> { 210 public: 211 void DescribeTo(std::ostream* os) const override { *os << "is OK"; } 212 void DescribeNegationTo(std::ostream* os) const override { 213 *os << "is not OK"; 214 } 215 bool MatchAndExplain(T actual_value, 216 ::testing::MatchResultListener*) const override { 217 return actual_value.ok(); 218 } 219 }; 220 221 // Implements IsPosixErrorOkMatcher() as a polymorphic matcher. 222 class IsPosixErrorOkMatcher { 223 public: 224 template <typename T> 225 operator ::testing::Matcher<T>() const { // NOLINT 226 return MakeMatcher(new MonoPosixErrorIsOkMatcherImpl<T>()); 227 } 228 }; 229 230 // Monomorphic implementation of a matcher for a PosixErrorOr. 231 template <typename PosixErrorOrType> 232 class IsPosixErrorOkAndHoldsMatcherImpl 233 : public ::testing::MatcherInterface<PosixErrorOrType> { 234 public: 235 using ValueType = typename std::remove_reference< 236 decltype(std::declval<PosixErrorOrType>().ValueOrDie())>::type; 237 238 template <typename InnerMatcher> 239 explicit IsPosixErrorOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher) 240 : inner_matcher_(::testing::SafeMatcherCast<const ValueType&>( 241 std::forward<InnerMatcher>(inner_matcher))) {} 242 243 void DescribeTo(std::ostream* os) const override { 244 *os << "is OK and has a value that "; 245 inner_matcher_.DescribeTo(os); 246 } 247 248 void DescribeNegationTo(std::ostream* os) const override { 249 *os << "isn't OK or has a value that "; 250 inner_matcher_.DescribeNegationTo(os); 251 } 252 253 bool MatchAndExplain( 254 PosixErrorOrType actual_value, 255 ::testing::MatchResultListener* listener) const override { 256 // We can't extract the value if it doesn't contain one. 257 if (!actual_value.ok()) { 258 return false; 259 } 260 261 ::testing::StringMatchResultListener inner_listener; 262 const bool matches = inner_matcher_.MatchAndExplain( 263 actual_value.ValueOrDie(), &inner_listener); 264 const std::string inner_explanation = inner_listener.str(); 265 *listener << "has a value " 266 << ::testing::PrintToString(actual_value.ValueOrDie()); 267 268 if (!inner_explanation.empty()) { 269 *listener << " " << inner_explanation; 270 } 271 return matches; 272 } 273 274 private: 275 const ::testing::Matcher<const ValueType&> inner_matcher_; 276 }; 277 278 // Implements IsOkAndHolds() as a polymorphic matcher. 279 template <typename InnerMatcher> 280 class IsPosixErrorOkAndHoldsMatcher { 281 public: 282 explicit IsPosixErrorOkAndHoldsMatcher(InnerMatcher inner_matcher) 283 : inner_matcher_(std::move(inner_matcher)) {} 284 285 // Converts this polymorphic matcher to a monomorphic one of the given type. 286 // PosixErrorOrType can be either PosixErrorOr<T> or a reference to 287 // PosixErrorOr<T>. 288 template <typename PosixErrorOrType> 289 operator ::testing::Matcher<PosixErrorOrType>() const { // NOLINT 290 return ::testing::MakeMatcher( 291 new IsPosixErrorOkAndHoldsMatcherImpl<PosixErrorOrType>( 292 inner_matcher_)); 293 } 294 295 private: 296 const InnerMatcher inner_matcher_; 297 }; 298 299 // PosixErrorIs() is a polymorphic matcher. This class is the common 300 // implementation of it shared by all types T where PosixErrorIs() can be 301 // used as a Matcher<T>. 302 class PosixErrorIsMatcherCommonImpl { 303 public: 304 PosixErrorIsMatcherCommonImpl( 305 ::testing::Matcher<int> code_matcher, 306 ::testing::Matcher<const std::string&> message_matcher) 307 : code_matcher_(std::move(code_matcher)), 308 message_matcher_(std::move(message_matcher)) {} 309 310 void DescribeTo(std::ostream* os) const; 311 312 void DescribeNegationTo(std::ostream* os) const; 313 314 bool MatchAndExplain(const PosixError& error, 315 ::testing::MatchResultListener* result_listener) const; 316 317 template <typename T> 318 bool MatchAndExplain(const PosixErrorOr<T>& error_or, 319 ::testing::MatchResultListener* result_listener) const { 320 if (error_or.ok()) { 321 *result_listener << "has a value " 322 << ::testing::PrintToString(error_or.ValueOrDie()); 323 return false; 324 } 325 326 return MatchAndExplain(error_or.error(), result_listener); 327 } 328 329 private: 330 const ::testing::Matcher<int> code_matcher_; 331 const ::testing::Matcher<const std::string&> message_matcher_; 332 }; 333 334 // Monomorphic implementation of matcher PosixErrorIs() for a given type 335 // T. T can be PosixError, PosixErrorOr<>, or a reference to either of them. 336 template <typename T> 337 class MonoPosixErrorIsMatcherImpl : public ::testing::MatcherInterface<T> { 338 public: 339 explicit MonoPosixErrorIsMatcherImpl( 340 PosixErrorIsMatcherCommonImpl common_impl) 341 : common_impl_(std::move(common_impl)) {} 342 343 void DescribeTo(std::ostream* os) const override { 344 common_impl_.DescribeTo(os); 345 } 346 347 void DescribeNegationTo(std::ostream* os) const override { 348 common_impl_.DescribeNegationTo(os); 349 } 350 351 bool MatchAndExplain( 352 T actual_value, 353 ::testing::MatchResultListener* result_listener) const override { 354 return common_impl_.MatchAndExplain(actual_value, result_listener); 355 } 356 357 private: 358 PosixErrorIsMatcherCommonImpl common_impl_; 359 }; 360 361 inline ::testing::Matcher<int> ToErrorCodeMatcher( 362 const ::testing::Matcher<int>& m) { 363 return m; 364 } 365 366 // Implements PosixErrorIs() as a polymorphic matcher. 367 class PosixErrorIsMatcher { 368 public: 369 template <typename ErrorCodeMatcher> 370 PosixErrorIsMatcher(ErrorCodeMatcher&& code_matcher, 371 ::testing::Matcher<const std::string&> message_matcher) 372 : common_impl_( 373 ToErrorCodeMatcher(std::forward<ErrorCodeMatcher>(code_matcher)), 374 std::move(message_matcher)) {} 375 376 // Converts this polymorphic matcher to a monomorphic matcher of the 377 // given type. T can be StatusOr<>, Status, or a reference to 378 // either of them. 379 template <typename T> 380 operator ::testing::Matcher<T>() const { // NOLINT 381 return MakeMatcher(new MonoPosixErrorIsMatcherImpl<T>(common_impl_)); 382 } 383 384 private: 385 const PosixErrorIsMatcherCommonImpl common_impl_; 386 }; 387 388 // Returns a gMock matcher that matches a PosixError or PosixErrorOr<> whose 389 // error code matches code_matcher, and whose error message matches 390 // message_matcher. 391 template <typename ErrorCodeMatcher> 392 PosixErrorIsMatcher PosixErrorIs( 393 ErrorCodeMatcher&& code_matcher, 394 ::testing::Matcher<const std::string&> message_matcher) { 395 return PosixErrorIsMatcher(std::forward<ErrorCodeMatcher>(code_matcher), 396 std::move(message_matcher)); 397 } 398 399 // Returns a gMock matcher that matches a PosixError or PosixErrorOr<> whose 400 // error code matches code_matcher. 401 template <typename ErrorCodeMatcher> 402 PosixErrorIsMatcher PosixErrorIs(ErrorCodeMatcher&& code_matcher) { 403 return PosixErrorIsMatcher(std::forward<ErrorCodeMatcher>(code_matcher), 404 ::testing::_); 405 } 406 407 // Returns a gMock matcher that matches a PosixErrorOr<> which is ok() and 408 // value matches the inner matcher. 409 template <typename InnerMatcher> 410 IsPosixErrorOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> 411 IsPosixErrorOkAndHolds(InnerMatcher&& inner_matcher) { 412 return IsPosixErrorOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>( 413 std::forward<InnerMatcher>(inner_matcher)); 414 } 415 416 // Internal helper for concatenating macro values. 417 #define POSIX_ERROR_IMPL_CONCAT_INNER_(x, y) x##y 418 #define POSIX_ERROR_IMPL_CONCAT_(x, y) POSIX_ERROR_IMPL_CONCAT_INNER_(x, y) 419 420 #define POSIX_ERROR_IMPL_ASSIGN_OR_RETURN_(posixerroror, lhs, rexpr) \ 421 auto posixerroror = (rexpr); \ 422 if (!posixerroror.ok()) { \ 423 return (posixerroror.error()); \ 424 } \ 425 lhs = std::move(posixerroror).ValueOrDie() 426 427 #define EXPECT_NO_ERRNO(expression) \ 428 EXPECT_THAT(expression, IsPosixErrorOkMatcher()) 429 #define ASSERT_NO_ERRNO(expression) \ 430 ASSERT_THAT(expression, IsPosixErrorOkMatcher()) 431 432 #define ASSIGN_OR_RETURN_ERRNO(lhs, rexpr) \ 433 POSIX_ERROR_IMPL_ASSIGN_OR_RETURN_( \ 434 POSIX_ERROR_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr) 435 436 #define RETURN_IF_ERRNO(s) \ 437 do { \ 438 if (!s.ok()) { \ 439 return s.error(); \ 440 } \ 441 } while (false); 442 443 #define ASSERT_NO_ERRNO_AND_VALUE(expr) \ 444 ({ \ 445 auto _expr_result = (expr); \ 446 ASSERT_NO_ERRNO(_expr_result); \ 447 std::move(_expr_result).ValueOrDie(); \ 448 }) 449 450 #define EXPECT_NO_ERRNO_AND_VALUE(expr) \ 451 ({ \ 452 auto _expr_result = (expr); \ 453 EXPECT_NO_ERRNO(_expr_result); \ 454 std::move(_expr_result).ValueOrDie(); \ 455 }) 456 457 } // namespace testing 458 } // namespace gvisor 459 460 #endif // GVISOR_TEST_UTIL_POSIX_ERROR_H_