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_