• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
compareComparator34   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
strComparator55   constexpr const char *str() { return ""; }
56 #else
strComparator57   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.
ignore_errno()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:
ErrnoSetterMatcher(Comparator<T> rcmp)79   ErrnoSetterMatcher(Comparator<T> rcmp) : return_cmp(rcmp) {}
ErrnoSetterMatcher(Comparator<T> rcmp,Comparator<int> ecmp)80   ErrnoSetterMatcher(Comparator<T> rcmp, Comparator<int> ecmp)
81       : return_cmp(rcmp), errno_cmp(ecmp) {}
82 
with_errno(Comparator<int> ecmp)83   ErrnoSetterMatcher<T> with_errno(Comparator<int> ecmp) {
84     errno_cmp = ecmp;
85     return *this;
86   }
87 
explainError()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_errno)) {
103         tlog << "Expected errno to be " << errno_cmp.str() << " \""
104              << get_error_string(errno_cmp.expected) << "\" but got \""
105              << get_error_string(actual_errno) << "\".\n";
106       }
107     }
108   }
109 
match(T got)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_errno);
119   }
120 };
121 
122 } // namespace internal
123 
124 namespace ErrnoSetterMatcher {
125 
LT(T val)126 template <typename T> internal::Comparator<T> LT(T val) {
127   return internal::Comparator<T>{internal::CompareAction::LT, val};
128 }
129 
LE(T val)130 template <typename T> internal::Comparator<T> LE(T val) {
131   return internal::Comparator<T>{internal::CompareAction::LE, val};
132 }
133 
GT(T val)134 template <typename T> internal::Comparator<T> GT(T val) {
135   return internal::Comparator<T>{internal::CompareAction::GT, val};
136 }
137 
GE(T val)138 template <typename T> internal::Comparator<T> GE(T val) {
139   return internal::Comparator<T>{internal::CompareAction::GE, val};
140 }
141 
EQ(T val)142 template <typename T> internal::Comparator<T> EQ(T val) {
143   return internal::Comparator<T>{internal::CompareAction::EQ, val};
144 }
145 
NE(T val)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(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(ExpectedErrno));
162 }
163 
164 template <typename RetT = int> class ErrnoSetterMatcherBuilder {
165 public:
166   template <typename T> using Cmp = internal::Comparator<T>;
ErrnoSetterMatcherBuilder(Cmp<RetT> cmp)167   ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {}
168 
with_errno(Cmp<int> cmp)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>
returns(internal::Comparator<RetT> cmp)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