Warning: This file is not a C or C++ file. It does not have highlighting.

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/libc_errno.h"
16#include "src/__support/macros/config.h"
17#include "src/__support/macros/properties/architectures.h"
18#include "test/UnitTest/Test.h"
19
20namespace LIBC_NAMESPACE_DECL {
21namespace testing {
22
23namespace internal {
24
25enum class CompareAction { EQ = 0, GE, GT, LE, LT, NE };
26
27constexpr 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
32template <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
62template <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
79public:
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 auto expected_str = try_get_errno_name(errno_cmp.expected);
105 auto actual_str = try_get_errno_name(actual_errno);
106 tlog << "Expected errno to be " << errno_cmp.str() << " "
107 << (expected_str ? *expected_str : "<unknown>") << "("
108 << errno_cmp.expected << ") but got "
109 << (actual_str ? *actual_str : "<unknown>") << "(" << actual_errno
110 << ").\n";
111 }
112 }
113 }
114
115 bool match(T got) {
116 actual_return = got;
117 actual_errno = libc_errno;
118 libc_errno = 0;
119 if constexpr (ignore_errno())
120 return return_cmp.compare(actual_return);
121 else
122 return return_cmp.compare(actual_return) &&
123 errno_cmp.compare(actual_errno);
124 }
125};
126
127} // namespace internal
128
129namespace ErrnoSetterMatcher {
130
131template <typename T> internal::Comparator<T> LT(T val) {
132 return internal::Comparator<T>{internal::CompareAction::LT, val};
133}
134
135template <typename T> internal::Comparator<T> LE(T val) {
136 return internal::Comparator<T>{internal::CompareAction::LE, val};
137}
138
139template <typename T> internal::Comparator<T> GT(T val) {
140 return internal::Comparator<T>{internal::CompareAction::GT, val};
141}
142
143template <typename T> internal::Comparator<T> GE(T val) {
144 return internal::Comparator<T>{internal::CompareAction::GE, val};
145}
146
147template <typename T> internal::Comparator<T> EQ(T val) {
148 return internal::Comparator<T>{internal::CompareAction::EQ, val};
149}
150
151template <typename T> internal::Comparator<T> NE(T val) {
152 return internal::Comparator<T>{internal::CompareAction::NE, val};
153}
154
155template <typename RetT = int>
156static internal::ErrnoSetterMatcher<RetT> Succeeds(RetT ExpectedReturn = 0,
157 int ExpectedErrno = 0) {
158 return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),
159 EQ(ExpectedErrno));
160}
161
162template <typename RetT = int>
163static internal::ErrnoSetterMatcher<RetT> Fails(int ExpectedErrno,
164 RetT ExpectedReturn = -1) {
165 return internal::ErrnoSetterMatcher<RetT>(EQ(ExpectedReturn),
166 EQ(ExpectedErrno));
167}
168
169template <typename RetT = int> class ErrnoSetterMatcherBuilder {
170public:
171 template <typename T> using Cmp = internal::Comparator<T>;
172 ErrnoSetterMatcherBuilder(Cmp<RetT> cmp) : return_cmp(cmp) {}
173
174 internal::ErrnoSetterMatcher<RetT> with_errno(Cmp<int> cmp) {
175 return internal::ErrnoSetterMatcher<RetT>(return_cmp, cmp);
176 }
177
178private:
179 Cmp<RetT> return_cmp;
180};
181
182template <typename RetT>
183static ErrnoSetterMatcherBuilder<RetT> returns(internal::Comparator<RetT> cmp) {
184 return ErrnoSetterMatcherBuilder<RetT>(cmp);
185}
186
187} // namespace ErrnoSetterMatcher
188
189} // namespace testing
190} // namespace LIBC_NAMESPACE_DECL
191
192#endif // LLVM_LIBC_TEST_ERRNOSETTERMATCHER_H
193

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of libc/test/UnitTest/ErrnoSetterMatcher.h