brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.0 KiB · 212b7a8 Raw
193 lines · c
1//===-- ErrnoSetterMatcher.h ------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H10#define LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H11 12#include "src/__support/FPUtil/FPBits.h"13#include "src/__support/FPUtil/fpbits_str.h"14#include "src/__support/StringUtil/error_to_string.h"15#include "src/__support/libc_errno.h"16#include "src/__support/macros/config.h"17#include "src/__support/macros/properties/architectures.h"18#include "test/UnitTest/Test.h"19 20namespace LIBC_NAMESPACE_DECL {21namespace testing {22 23namespace internal {24 25enum class CompareAction { EQ = 0, GE, GT, LE, LT, NE };26 27constexpr const char *CompareMessage[] = {28    "equal to",     "greater than or equal to",29    "greater than", "less than or equal to",30    "less than",    "not equal to"};31 32template <typename T> struct Comparator {33  CompareAction cmp;34  T expected;35  bool compare(T actual) {36    switch (cmp) {37    case CompareAction::EQ:38      return actual == expected;39    case CompareAction::NE:40      return actual != expected;41    case CompareAction::GE:42      return actual >= expected;43    case CompareAction::GT:44      return actual > expected;45    case CompareAction::LE:46      return actual <= expected;47    case CompareAction::LT:48      return actual < expected;49    }50    __builtin_unreachable();51  }52 53  // The NVPTX backend cannot handle circular dependencies on global variables.54  // We provide a constant dummy implementation to prevent this from occurring.55#ifdef LIBC_TARGET_ARCH_IS_NVPTX56  constexpr const char *str() { return ""; }57#else58  const char *str() { return CompareMessage[static_cast<int>(cmp)]; }59#endif60};61 62template <typename T> class ErrnoSetterMatcher : public Matcher<T> {63  Comparator<T> return_cmp;64  Comparator<int> errno_cmp;65  T actual_return;66  int actual_errno;67 68  // Even though this is a errno matcher primarily, it has to cater to platforms69  // which do not have an errno. This predicate checks if errno matching is to70  // be skipped.71  static constexpr bool ignore_errno() {72#ifdef LIBC_TARGET_ARCH_IS_GPU73    return true;74#else75    return false;76#endif77  }78 79public:80  ErrnoSetterMatcher(Comparator<T> rcmp) : return_cmp(rcmp) {}81  ErrnoSetterMatcher(Comparator<T> rcmp, Comparator<int> ecmp)82      : return_cmp(rcmp), errno_cmp(ecmp) {}83 84  ErrnoSetterMatcher<T> with_errno(Comparator<int> ecmp) {85    errno_cmp = ecmp;86    return *this;87  }88 89  void explainError() override {90    if (!return_cmp.compare(actual_return)) {91      if constexpr (cpp::is_floating_point_v<T>) {92        tlog << "Expected return value to be " << return_cmp.str() << ": "93             << str(fputil::FPBits<T>(return_cmp.expected)) << '\n'94             << "                    But got: "95             << str(fputil::FPBits<T>(actual_return)) << '\n';96      } else {97        tlog << "Expected return value to be " << return_cmp.str() << " "98             << return_cmp.expected << " but got " << actual_return << ".\n";99      }100    }101 102    if constexpr (!ignore_errno()) {103      if (!errno_cmp.compare(actual_errno)) {104        auto expected_str = try_get_errno_name(errno_cmp.expected);105        auto actual_str = try_get_errno_name(actual_errno);106        tlog << "Expected errno to be " << errno_cmp.str() << " "107             << (expected_str ? *expected_str : "<unknown>") << "("108             << errno_cmp.expected << ") but got "109             << (actual_str ? *actual_str : "<unknown>") << "(" << actual_errno110             << ").\n";111      }112    }113  }114 115  bool match(T got) {116    actual_return = got;117    actual_errno = libc_errno;118    libc_errno = 0;119    if constexpr (ignore_errno())120      return return_cmp.compare(actual_return);121    else122      return return_cmp.compare(actual_return) &&123             errno_cmp.compare(actual_errno);124  }125};126 127} // namespace internal128 129namespace ErrnoSetterMatcher {130 131template <typename T> internal::Comparator<T> LT(T val) {132  return internal::Comparator<T>{internal::CompareAction::LT, val};133}134 135template <typename T> internal::Comparator<T> LE(T val) {136  return internal::Comparator<T>{internal::CompareAction::LE, val};137}138 139template <typename T> internal::Comparator<T> GT(T val) {140  return internal::Comparator<T>{internal::CompareAction::GT, val};141}142 143template <typename T> internal::Comparator<T> GE(T val) {144  return internal::Comparator<T>{internal::CompareAction::GE, val};145}146 147template <typename T> internal::Comparator<T> EQ(T val) {148  return internal::Comparator<T>{internal::CompareAction::EQ, val};149}150 151template <typename T> internal::Comparator<T> NE(T val) {152  return internal::Comparator<T>{internal::CompareAction::NE, val};153}154 155template <typename RetT = int>156static internal::ErrnoSetterMatcher<RetT> Succeeds(RetT ExpectedReturn = 0,157                                                   int ExpectedErrno = 0) {158  return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),159                                            EQ(ExpectedErrno));160}161 162template <typename RetT = int>163static internal::ErrnoSetterMatcher<RetT> Fails(int ExpectedErrno,164                                                RetT ExpectedReturn = -1) {165  return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),166                                            EQ(ExpectedErrno));167}168 169template <typename RetT = int> class ErrnoSetterMatcherBuilder {170public:171  template <typename T> using Cmp = internal::Comparator<T>;172  ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {}173 174  internal::ErrnoSetterMatcher<RetT> with_errno(Cmp<int> cmp) {175    return internal::ErrnoSetterMatcher<RetT>(return_cmp, cmp);176  }177 178private:179  Cmp<RetT> return_cmp;180};181 182template <typename RetT>183static ErrnoSetterMatcherBuilder<RetT> returns(internal::Comparator<RetT> cmp) {184  return ErrnoSetterMatcherBuilder<RetT>(cmp);185}186 187} // namespace ErrnoSetterMatcher188 189} // namespace testing190} // namespace LIBC_NAMESPACE_DECL191 192#endif // LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H193