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