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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H 10 #define LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H 11 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/macros/config.h" 16 #include "src/__support/macros/properties/architectures.h" 17 #include "src/errno/libc_errno.h" 18 #include "test/UnitTest/Test.h" 19 20 namespace LIBC_NAMESPACE_DECL { 21 namespace testing { 22 23 namespace internal { 24 25 enum class CompareAction { EQ = 0, GE, GT, LE, LT, NE }; 26 27 constexpr 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 32 template <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_NVPTX 56 constexpr const char *str() { return ""; } 57 #else 58 const char *str() { return CompareMessage[static_cast<int>(cmp)]; } 59 #endif 60 }; 61 62 template <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 platforms 69 // which do not have an errno. This predicate checks if errno matching is to 70 // be skipped. 71 static constexpr bool ignore_errno() { 72 #ifdef LIBC_TARGET_ARCH_IS_GPU 73 return true; 74 #else 75 return false; 76 #endif 77 } 78 79 public: 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 tlog << "Expected errno to be " << errno_cmp.str() << " \"" 105 << get_error_string(errno_cmp.expected) << "\" but got \"" 106 << get_error_string(actual_errno) << "\".\n"; 107 } 108 } 109 } 110 111 bool match(T got) { 112 actual_return = got; 113 actual_errno = LIBC_NAMESPACE::libc_errno; 114 LIBC_NAMESPACE::libc_errno = 0; 115 if constexpr (ignore_errno()) 116 return return_cmp.compare(actual_return); 117 else 118 return return_cmp.compare(actual_return) && 119 errno_cmp.compare(actual_errno); 120 } 121 }; 122 123 } // namespace internal 124 125 namespace ErrnoSetterMatcher { 126 127 template <typename T> internal::Comparator<T> LT(T val) { 128 return internal::Comparator<T>{internal::CompareAction::LT, val}; 129 } 130 131 template <typename T> internal::Comparator<T> LE(T val) { 132 return internal::Comparator<T>{internal::CompareAction::LE, val}; 133 } 134 135 template <typename T> internal::Comparator<T> GT(T val) { 136 return internal::Comparator<T>{internal::CompareAction::GT, val}; 137 } 138 139 template <typename T> internal::Comparator<T> GE(T val) { 140 return internal::Comparator<T>{internal::CompareAction::GE, val}; 141 } 142 143 template <typename T> internal::Comparator<T> EQ(T val) { 144 return internal::Comparator<T>{internal::CompareAction::EQ, val}; 145 } 146 147 template <typename T> internal::Comparator<T> NE(T val) { 148 return internal::Comparator<T>{internal::CompareAction::NE, val}; 149 } 150 151 template <typename RetT = int> 152 static internal::ErrnoSetterMatcher<RetT> Succeeds(RetT ExpectedReturn = 0, 153 int ExpectedErrno = 0) { 154 return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn), 155 EQ(ExpectedErrno)); 156 } 157 158 template <typename RetT = int> 159 static internal::ErrnoSetterMatcher<RetT> Fails(int ExpectedErrno, 160 RetT ExpectedReturn = -1) { 161 return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn), 162 EQ(ExpectedErrno)); 163 } 164 165 template <typename RetT = int> class ErrnoSetterMatcherBuilder { 166 public: 167 template <typename T> using Cmp = internal::Comparator<T>; 168 ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {} 169 170 internal::ErrnoSetterMatcher<RetT> with_errno(Cmp<int> cmp) { 171 return internal::ErrnoSetterMatcher<RetT>(return_cmp, cmp); 172 } 173 174 private: 175 Cmp<RetT> return_cmp; 176 }; 177 178 template <typename RetT> 179 static ErrnoSetterMatcherBuilder<RetT> returns(internal::Comparator<RetT> cmp) { 180 return ErrnoSetterMatcherBuilder<RetT>(cmp); 181 } 182 183 } // namespace ErrnoSetterMatcher 184 185 } // namespace testing 186 } // namespace LIBC_NAMESPACE_DECL 187 188 #endif // LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H 189