1 /*
2 * Copyright (c) 2020-2024 Stefan Krah. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27
28 #ifndef TESTS_HH_
29 #define TESTS_HH_
30
31
32 #include <exception>
33 #include <string>
34 #include <sstream>
35 #include <vector>
36
37
38 namespace test {
39
40
41 /******************************************************************************/
42 /* Util */
43 /******************************************************************************/
44
45 template<typename T>
46 static inline const std::string
str(const T & t)47 str(const T& t)
48 {
49 std::stringstream ss;
50 ss << t;
51 return ss.str();
52 }
53
54 static inline const std::string
stringize()55 stringize()
56 {
57 return std::string();
58 }
59
60 template<typename T, typename... Args>
61 static inline const std::string
stringize(const T & t,Args...args)62 stringize(const T& t, Args... args)
63 {
64 return str(t) + stringize(args...);
65 }
66
67
68 /******************************************************************************/
69 /* Exceptions */
70 /******************************************************************************/
71
72 class Failure: public std::exception {
73 private:
74 std::runtime_error m;
75 public:
76 template<typename... Args>
Failure(Args...args)77 explicit Failure(Args... args) : m(stringize(args...)) {}
78 virtual const char* what() const noexcept;
79 };
80
81 template<typename... Args>
82 static void
raise(const char * file,const int64_t line,Args...args)83 raise(const char *file, const int64_t line, Args... args)
84 {
85 throw Failure("error: ", args..., " [", file, ":", line, "]");
86 }
87
88
89 /******************************************************************************/
90 /* Test support */
91 /******************************************************************************/
92
93 void assert_true(const char *file, const int64_t line, const bool p);
94 void assert_false(const char *file, const int64_t line, const bool p);
95
96 template<class T, class U>
97 void
assert_equal(const char * file,const int64_t line,const T & calc,const U & expected)98 assert_equal(const char *file, const int64_t line, const T& calc, const U& expected)
99 {
100 if (calc != expected) {
101 raise(file, line, "values not equal: ", "expected: ", test::str(expected),
102 " got: ", test::str(calc));
103 }
104 }
105
106 template<class T, class U>
107 void
assert_equal_str(const char * file,int64_t line,const T & calc,const U & expected)108 assert_equal_str(const char *file, int64_t line, const T& calc, const U& expected)
109 {
110 if (str(calc) != str(expected)) {
111 raise(file, line, "string representations not equal: expected: ", test::str(expected),
112 " got: ", test::str(calc));
113 }
114 }
115
116 template<typename Exc, typename F>
117 void
assert_raises(const char * file,const int64_t line,const F & f)118 assert_raises(const char *file, const int64_t line, const F& f)
119 {
120 try {
121 f();
122 raise(file, line, "exception not raised");
123 }
124 catch (Exc& e) {
125 (void)e;
126 return;
127 }
128 catch (std::exception& e) {
129 raise(file, line, "unexpected exception: ", e.what());
130 }
131 }
132
133 #define assertTrue(p) test::assert_true(__FILE__, __LINE__, p)
134 #define assertFalse(p) test::assert_false(__FILE__, __LINE__, p)
135 #define assertEqual(calc, expected) test::assert_equal(__FILE__, __LINE__, calc, expected)
136 #define assertEqualStr(calc, expected) test::assert_equal_str(__FILE__, __LINE__, calc, expected)
137 #define assertRaises(ex, func) test::assert_raises<ex>(__FILE__, __LINE__, func)
138
139 #define err_exit(msg) \
140 do {std::cerr << __FILE__ << ":" << __LINE__ << ": error: "; \
141 std::cerr << msg << std::endl; \
142 std::exit(EXIT_FAILURE); \
143 } while (0)
144
145 #define err_raise(...) \
146 do { throw test::Failure( "error: ", __VA_ARGS__, " [", __FILE__, ":", __LINE__, "]"); } while (0)
147
148 #define err_token(token, ...) \
149 do { throw test::Failure(token.at(0), ": ", __VA_ARGS__, " [", __FILE__, ":", __LINE__, "]"); } while (0)
150
151 #define DECIMAL_ASSERT(p, token) \
152 do { if (!(p)) { err_token(token, "assertion failure"); } } while (0)
153
154
155 /******************************************************************************/
156 /* API for testing allocation failures */
157 /******************************************************************************/
158
159 void init_alloc(bool custom_alloc, bool check_alloc);
160
161 #ifdef MPD_CONFIG_32
162 void set_alloc_limit(size_t size);
163 #endif
164
165 void set_alloc_fail(decimal::Context &ctx, uint64_t n);
166 void set_alloc(decimal::Context &ctx);
167
168 } // namespace test
169
170
171 #endif // TESTS_HH_
172