1 //===-- ErrnoSetterMatcher.h ------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H
10 #define LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H
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"
20 namespace LIBC_NAMESPACE_DECL
{
25 enum class CompareAction
{ EQ
= 0, GE
, GT
, LE
, LT
, NE
};
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"};
32 template <typename T
> struct Comparator
{
35 bool compare(T actual
) {
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
;
50 __builtin_unreachable();
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 ""; }
58 const char *str() { return CompareMessage
[static_cast<int>(cmp
)]; }
62 template <typename T
> class ErrnoSetterMatcher
: public Matcher
<T
> {
63 Comparator
<T
> return_cmp
;
64 Comparator
<int> errno_cmp
;
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
71 static constexpr bool ignore_errno() {
72 #ifdef LIBC_TARGET_ARCH_IS_GPU
80 ErrnoSetterMatcher(Comparator
<T
> rcmp
) : return_cmp(rcmp
) {}
81 ErrnoSetterMatcher(Comparator
<T
> rcmp
, Comparator
<int> ecmp
)
82 : return_cmp(rcmp
), errno_cmp(ecmp
) {}
84 ErrnoSetterMatcher
<T
> with_errno(Comparator
<int> ecmp
) {
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'
95 << str(fputil::FPBits
<T
>(actual_return
)) << '\n';
97 tlog
<< "Expected return value to be " << return_cmp
.str() << " "
98 << return_cmp
.expected
<< " but got " << actual_return
<< ".\n";
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";
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
);
118 return return_cmp
.compare(actual_return
) &&
119 errno_cmp
.compare(actual_errno
);
123 } // namespace internal
125 namespace ErrnoSetterMatcher
{
127 template <typename T
> internal::Comparator
<T
> LT(T val
) {
128 return internal::Comparator
<T
>{internal::CompareAction::LT
, val
};
131 template <typename T
> internal::Comparator
<T
> LE(T val
) {
132 return internal::Comparator
<T
>{internal::CompareAction::LE
, val
};
135 template <typename T
> internal::Comparator
<T
> GT(T val
) {
136 return internal::Comparator
<T
>{internal::CompareAction::GT
, val
};
139 template <typename T
> internal::Comparator
<T
> GE(T val
) {
140 return internal::Comparator
<T
>{internal::CompareAction::GE
, val
};
143 template <typename T
> internal::Comparator
<T
> EQ(T val
) {
144 return internal::Comparator
<T
>{internal::CompareAction::EQ
, val
};
147 template <typename T
> internal::Comparator
<T
> NE(T val
) {
148 return internal::Comparator
<T
>{internal::CompareAction::NE
, val
};
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
),
158 template <typename RetT
= int>
159 static internal::ErrnoSetterMatcher
<RetT
> Fails(int ExpectedErrno
,
160 RetT ExpectedReturn
= -1) {
161 return internal::ErrnoSetterMatcher
<RetT
>(EQ(ExpectedReturn
),
165 template <typename RetT
= int> class ErrnoSetterMatcherBuilder
{
167 template <typename T
> using Cmp
= internal::Comparator
<T
>;
168 ErrnoSetterMatcherBuilder(Cmp
<RetT
> cmp
) : return_cmp(cmp
) {}
170 internal::ErrnoSetterMatcher
<RetT
> with_errno(Cmp
<int> cmp
) {
171 return internal::ErrnoSetterMatcher
<RetT
>(return_cmp
, cmp
);
175 Cmp
<RetT
> return_cmp
;
178 template <typename RetT
>
179 static ErrnoSetterMatcherBuilder
<RetT
> returns(internal::Comparator
<RetT
> cmp
) {
180 return ErrnoSetterMatcherBuilder
<RetT
>(cmp
);
183 } // namespace ErrnoSetterMatcher
185 } // namespace testing
186 } // namespace LIBC_NAMESPACE_DECL
188 #endif // LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H