xref: /aosp_15_r20/external/llvm-libc/test/UnitTest/ErrnoSetterMatcher.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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;
compareComparator35   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
strComparator56   constexpr const char *str() { return ""; }
57 #else
strComparator58   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.
ignore_errno()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:
ErrnoSetterMatcher(Comparator<T> rcmp)80   ErrnoSetterMatcher(Comparator<T> rcmp) : return_cmp(rcmp) {}
ErrnoSetterMatcher(Comparator<T> rcmp,Comparator<int> ecmp)81   ErrnoSetterMatcher(Comparator<T> rcmp, Comparator<int> ecmp)
82       : return_cmp(rcmp), errno_cmp(ecmp) {}
83 
with_errno(Comparator<int> ecmp)84   ErrnoSetterMatcher<T> with_errno(Comparator<int> ecmp) {
85     errno_cmp = ecmp;
86     return *this;
87   }
88 
explainError()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 
match(T got)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 
LT(T val)127 template <typename T> internal::Comparator<T> LT(T val) {
128   return internal::Comparator<T>{internal::CompareAction::LT, val};
129 }
130 
LE(T val)131 template <typename T> internal::Comparator<T> LE(T val) {
132   return internal::Comparator<T>{internal::CompareAction::LE, val};
133 }
134 
GT(T val)135 template <typename T> internal::Comparator<T> GT(T val) {
136   return internal::Comparator<T>{internal::CompareAction::GT, val};
137 }
138 
GE(T val)139 template <typename T> internal::Comparator<T> GE(T val) {
140   return internal::Comparator<T>{internal::CompareAction::GE, val};
141 }
142 
EQ(T val)143 template <typename T> internal::Comparator<T> EQ(T val) {
144   return internal::Comparator<T>{internal::CompareAction::EQ, val};
145 }
146 
NE(T val)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>;
ErrnoSetterMatcherBuilder(Cmp<RetT> cmp)168   ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {}
169 
with_errno(Cmp<int> cmp)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>
returns(internal::Comparator<RetT> cmp)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