1 //===-- TestMatchers.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_UTILS_UNITTEST_FPMATCHER_H
10 #define LLVM_LIBC_UTILS_UNITTEST_FPMATCHER_H
11 
12 #include "src/__support/FPUtil/FEnvImpl.h"
13 #include "src/__support/FPUtil/FPBits.h"
14 #include "utils/UnitTest/Test.h"
15 
16 #include <errno.h>
17 #include <math.h>
18 
19 namespace __llvm_libc {
20 namespace fputil {
21 namespace testing {
22 
23 template <typename ValType, typename StreamType>
24 cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, void>
25 describeValue(const char *label, ValType value, StreamType &stream);
26 
27 template <typename T, __llvm_libc::testing::TestCondition Condition>
28 class FPMatcher : public __llvm_libc::testing::Matcher<T> {
29   static_assert(__llvm_libc::cpp::IsFloatingPointType<T>::Value,
30                 "FPMatcher can only be used with floating point values.");
31   static_assert(Condition == __llvm_libc::testing::Cond_EQ ||
32                     Condition == __llvm_libc::testing::Cond_NE,
33                 "Unsupported FPMathcer test condition.");
34 
35   T expected;
36   T actual;
37 
38 public:
FPMatcher(T expectedValue)39   FPMatcher(T expectedValue) : expected(expectedValue) {}
40 
match(T actualValue)41   bool match(T actualValue) {
42     actual = actualValue;
43     fputil::FPBits<T> actualBits(actual), expectedBits(expected);
44     if (Condition == __llvm_libc::testing::Cond_EQ)
45       return (actualBits.is_nan() && expectedBits.is_nan()) ||
46              (actualBits.uintval() == expectedBits.uintval());
47 
48     // If condition == Cond_NE.
49     if (actualBits.is_nan())
50       return !expectedBits.is_nan();
51     return expectedBits.is_nan() ||
52            (actualBits.uintval() != expectedBits.uintval());
53   }
54 
explainError(testutils::StreamWrapper & stream)55   void explainError(testutils::StreamWrapper &stream) override {
56     describeValue("Expected floating point value: ", expected, stream);
57     describeValue("  Actual floating point value: ", actual, stream);
58   }
59 };
60 
61 template <__llvm_libc::testing::TestCondition C, typename T>
getMatcher(T expectedValue)62 FPMatcher<T, C> getMatcher(T expectedValue) {
63   return FPMatcher<T, C>(expectedValue);
64 }
65 
66 } // namespace testing
67 } // namespace fputil
68 } // namespace __llvm_libc
69 
70 #define DECLARE_SPECIAL_CONSTANTS(T)                                           \
71   using FPBits = __llvm_libc::fputil::FPBits<T>;                               \
72   using UIntType = typename FPBits::UIntType;                                  \
73   const T zero = T(FPBits::zero());                                            \
74   const T neg_zero = T(FPBits::neg_zero());                                    \
75   const T aNaN = T(FPBits::build_nan(1));                                      \
76   const T inf = T(FPBits::inf());                                              \
77   const T neg_inf = T(FPBits::neg_inf());
78 
79 #define EXPECT_FP_EQ(expected, actual)                                         \
80   EXPECT_THAT(                                                                 \
81       actual,                                                                  \
82       __llvm_libc::fputil::testing::getMatcher<__llvm_libc::testing::Cond_EQ>( \
83           expected))
84 
85 #define ASSERT_FP_EQ(expected, actual)                                         \
86   ASSERT_THAT(                                                                 \
87       actual,                                                                  \
88       __llvm_libc::fputil::testing::getMatcher<__llvm_libc::testing::Cond_EQ>( \
89           expected))
90 
91 #define EXPECT_FP_NE(expected, actual)                                         \
92   EXPECT_THAT(                                                                 \
93       actual,                                                                  \
94       __llvm_libc::fputil::testing::getMatcher<__llvm_libc::testing::Cond_NE>( \
95           expected))
96 
97 #define ASSERT_FP_NE(expected, actual)                                         \
98   ASSERT_THAT(                                                                 \
99       actual,                                                                  \
100       __llvm_libc::fputil::testing::getMatcher<__llvm_libc::testing::Cond_NE>( \
101           expected))
102 
103 #define EXPECT_MATH_ERRNO(expected)                                            \
104   do {                                                                         \
105     if (math_errhandling & MATH_ERRNO) {                                       \
106       int actual = errno;                                                      \
107       errno = 0;                                                               \
108       EXPECT_EQ(actual, expected);                                             \
109     }                                                                          \
110   } while (0)
111 
112 #define ASSERT_MATH_ERRNO(expected)                                            \
113   do {                                                                         \
114     if (math_errhandling & MATH_ERRNO) {                                       \
115       int actual = errno;                                                      \
116       errno = 0;                                                               \
117       ASSERT_EQ(actual, expected);                                             \
118     }                                                                          \
119   } while (0)
120 
121 #define EXPECT_FP_EXCEPTION(expected)                                          \
122   do {                                                                         \
123     if (math_errhandling & MATH_ERREXCEPT) {                                   \
124       EXPECT_EQ(__llvm_libc::fputil::test_except(FE_ALL_EXCEPT), expected);    \
125     }                                                                          \
126   } while (0)
127 
128 #define ASSERT_FP_EXCEPTION(expected)                                          \
129   do {                                                                         \
130     if (math_errhandling & MATH_ERREXCEPT) {                                   \
131       ASSERT_EQ(__llvm_libc::fputil::test_except(FE_ALL_EXCEPT), expected);    \
132     }                                                                          \
133   } while (0)
134 
135 #endif // LLVM_LIBC_UTILS_UNITTEST_FPMATCHER_H
136