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/properties/architectures.h" |
16 | #include "src/errno/libc_errno.h" |
17 | #include "test/UnitTest/Test.h" |
18 | |
19 | namespace LIBC_NAMESPACE { |
20 | namespace testing { |
21 | |
22 | namespace internal { |
23 | |
24 | enum class CompareAction { EQ = 0, GE, GT, LE, LT, NE }; |
25 | |
26 | constexpr const char *CompareMessage[] = { |
27 | "equal to" , "greater than or equal to" , |
28 | "greater than" , "less than or equal to" , |
29 | "less than" , "not equal to" }; |
30 | |
31 | template <typename T> struct Comparator { |
32 | CompareAction cmp; |
33 | T expected; |
34 | bool compare(T actual) { |
35 | switch (cmp) { |
36 | case CompareAction::EQ: |
37 | return actual == expected; |
38 | case CompareAction::NE: |
39 | return actual != expected; |
40 | case CompareAction::GE: |
41 | return actual >= expected; |
42 | case CompareAction::GT: |
43 | return actual > expected; |
44 | case CompareAction::LE: |
45 | return actual <= expected; |
46 | case CompareAction::LT: |
47 | return actual < expected; |
48 | } |
49 | __builtin_unreachable(); |
50 | } |
51 | |
52 | // The NVPTX backend cannot handle circular dependencies on global variables. |
53 | // We provide a constant dummy implementation to prevent this from occurring. |
54 | #ifdef LIBC_TARGET_ARCH_IS_NVPTX |
55 | constexpr const char *str() { return "" ; } |
56 | #else |
57 | const char *str() { return CompareMessage[static_cast<int>(cmp)]; } |
58 | #endif |
59 | }; |
60 | |
61 | template <typename T> class ErrnoSetterMatcher : public Matcher<T> { |
62 | Comparator<T> return_cmp; |
63 | Comparator<int> errno_cmp; |
64 | T actual_return; |
65 | int actual_errno; |
66 | |
67 | // Even though this is a errno matcher primarily, it has to cater to platforms |
68 | // which do not have an errno. This predicate checks if errno matching is to |
69 | // be skipped. |
70 | static constexpr bool ignore_errno() { |
71 | #ifdef LIBC_TARGET_ARCH_IS_GPU |
72 | return true; |
73 | #else |
74 | return false; |
75 | #endif |
76 | } |
77 | |
78 | public: |
79 | ErrnoSetterMatcher(Comparator<T> rcmp) : return_cmp(rcmp) {} |
80 | ErrnoSetterMatcher(Comparator<T> rcmp, Comparator<int> ecmp) |
81 | : return_cmp(rcmp), errno_cmp(ecmp) {} |
82 | |
83 | ErrnoSetterMatcher<T> with_errno(Comparator<int> ecmp) { |
84 | errno_cmp = ecmp; |
85 | return *this; |
86 | } |
87 | |
88 | void explainError() override { |
89 | if (!return_cmp.compare(actual_return)) { |
90 | if constexpr (cpp::is_floating_point_v<T>) { |
91 | tlog << "Expected return value to be " << return_cmp.str() << ": " |
92 | << str(fputil::FPBits<T>(return_cmp.expected)) << '\n' |
93 | << " But got: " |
94 | << str(fputil::FPBits<T>(actual_return)) << '\n'; |
95 | } else { |
96 | tlog << "Expected return value to be " << return_cmp.str() << " " |
97 | << return_cmp.expected << " but got " << actual_return << ".\n" ; |
98 | } |
99 | } |
100 | |
101 | if constexpr (!ignore_errno()) { |
102 | if (!errno_cmp.compare(actual: actual_errno)) { |
103 | tlog << "Expected errno to be " << errno_cmp.str() << " \"" |
104 | << get_error_string(err_num: errno_cmp.expected) << "\" but got \"" |
105 | << get_error_string(err_num: actual_errno) << "\".\n" ; |
106 | } |
107 | } |
108 | } |
109 | |
110 | bool match(T got) { |
111 | actual_return = got; |
112 | actual_errno = LIBC_NAMESPACE::libc_errno; |
113 | LIBC_NAMESPACE::libc_errno = 0; |
114 | if constexpr (ignore_errno()) |
115 | return return_cmp.compare(actual_return); |
116 | else |
117 | return return_cmp.compare(actual_return) && |
118 | errno_cmp.compare(actual: actual_errno); |
119 | } |
120 | }; |
121 | |
122 | } // namespace internal |
123 | |
124 | namespace ErrnoSetterMatcher { |
125 | |
126 | template <typename T> internal::Comparator<T> LT(T val) { |
127 | return internal::Comparator<T>{internal::CompareAction::LT, val}; |
128 | } |
129 | |
130 | template <typename T> internal::Comparator<T> LE(T val) { |
131 | return internal::Comparator<T>{internal::CompareAction::LE, val}; |
132 | } |
133 | |
134 | template <typename T> internal::Comparator<T> GT(T val) { |
135 | return internal::Comparator<T>{internal::CompareAction::GT, val}; |
136 | } |
137 | |
138 | template <typename T> internal::Comparator<T> GE(T val) { |
139 | return internal::Comparator<T>{internal::CompareAction::GE, val}; |
140 | } |
141 | |
142 | template <typename T> internal::Comparator<T> EQ(T val) { |
143 | return internal::Comparator<T>{internal::CompareAction::EQ, val}; |
144 | } |
145 | |
146 | template <typename T> internal::Comparator<T> NE(T val) { |
147 | return internal::Comparator<T>{internal::CompareAction::NE, val}; |
148 | } |
149 | |
150 | template <typename RetT = int> |
151 | static internal::ErrnoSetterMatcher<RetT> Succeeds(RetT ExpectedReturn = 0, |
152 | int ExpectedErrno = 0) { |
153 | return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn), |
154 | EQ(val: ExpectedErrno)); |
155 | } |
156 | |
157 | template <typename RetT = int> |
158 | static internal::ErrnoSetterMatcher<RetT> Fails(int ExpectedErrno, |
159 | RetT ExpectedReturn = -1) { |
160 | return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn), |
161 | EQ(val: ExpectedErrno)); |
162 | } |
163 | |
164 | template <typename RetT = int> class ErrnoSetterMatcherBuilder { |
165 | public: |
166 | template <typename T> using Cmp = internal::Comparator<T>; |
167 | ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {} |
168 | |
169 | internal::ErrnoSetterMatcher<RetT> with_errno(Cmp<int> cmp) { |
170 | return internal::ErrnoSetterMatcher<RetT>(return_cmp, cmp); |
171 | } |
172 | |
173 | private: |
174 | Cmp<RetT> return_cmp; |
175 | }; |
176 | |
177 | template <typename RetT> |
178 | static ErrnoSetterMatcherBuilder<RetT> returns(internal::Comparator<RetT> cmp) { |
179 | return ErrnoSetterMatcherBuilder<RetT>(cmp); |
180 | } |
181 | |
182 | } // namespace ErrnoSetterMatcher |
183 | |
184 | } // namespace testing |
185 | } // namespace LIBC_NAMESPACE |
186 | |
187 | #endif // LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H |
188 | |