1 #include <stdexcept>
2 #include <string>
3
4 #include <pqxx/result>
5 #include <pqxx/row>
6
7 namespace pqxx
8 {
9 namespace test
10 {
11 class test_failure : public std::logic_error
12 {
13 std::string const m_file;
14 int m_line;
15
16 public:
17 test_failure(std::string const &ffile, int fline, std::string const &desc);
18
19 ~test_failure() noexcept override;
20
file() const21 std::string const &file() const noexcept { return m_file; }
line() const22 int line() const noexcept { return m_line; }
23 };
24
25
26 /// Drop a table, if it exists.
27 void drop_table(transaction_base &, std::string const &table);
28
29
30 using testfunc = void (*)();
31
32
33 void register_test(char const name[], testfunc func);
34
35
36 /// Register a test while not inside a function.
37 struct registrar
38 {
registrarpqxx::test::registrar39 registrar(char const name[], testfunc func)
40 {
41 pqxx::test::register_test(name, func);
42 }
43 };
44
45
46 // Register a test function, so the runner will run it.
47 #define PQXX_REGISTER_TEST(func) \
48 pqxx::test::registrar tst_##func { #func, func }
49
50
51 // Unconditional test failure.
52 #define PQXX_CHECK_NOTREACHED(desc) \
53 pqxx::test::check_notreached(__FILE__, __LINE__, (desc))
54 [[noreturn]] void
55 check_notreached(char const file[], int line, std::string desc);
56
57 // Verify that a condition is met, similar to assert()
58 #define PQXX_CHECK(condition, desc) \
59 pqxx::test::check(__FILE__, __LINE__, (condition), #condition, (desc))
60 void check(
61 char const file[], int line, bool condition, char const text[],
62 std::string desc);
63
64 // Verify that variable has the expected value.
65 #define PQXX_CHECK_EQUAL(actual, expected, desc) \
66 pqxx::test::check_equal( \
67 __FILE__, __LINE__, (actual), #actual, (expected), #expected, (desc))
68 template<typename ACTUAL, typename EXPECTED>
check_equal(char const file[],int line,ACTUAL actual,char const actual_text[],EXPECTED expected,char const expected_text[],std::string const & desc)69 inline void check_equal(
70 char const file[], int line, ACTUAL actual, char const actual_text[],
71 EXPECTED expected, char const expected_text[], std::string const &desc)
72 {
73 if (expected == actual)
74 return;
75 std::string const fulldesc = desc + " (" + actual_text + " <> " +
76 expected_text +
77 ": "
78 "actual=" +
79 to_string(actual) +
80 ", "
81 "expected=" +
82 to_string(expected) + ")";
83 throw test_failure(file, line, fulldesc);
84 }
85
86 // Verify that two values are not equal.
87 #define PQXX_CHECK_NOT_EQUAL(value1, value2, desc) \
88 pqxx::test::check_not_equal( \
89 __FILE__, __LINE__, (value1), #value1, (value2), #value2, (desc))
90 template<typename VALUE1, typename VALUE2>
check_not_equal(char const file[],int line,VALUE1 value1,char const text1[],VALUE2 value2,char const text2[],std::string const & desc)91 inline void check_not_equal(
92 char const file[], int line, VALUE1 value1, char const text1[],
93 VALUE2 value2, char const text2[], std::string const &desc)
94 {
95 if (value1 != value2)
96 return;
97 std::string const fulldesc = desc + " (" + text1 + " == " + text2 +
98 ": "
99 "both are " +
100 to_string(value2) + ")";
101 throw test_failure(file, line, fulldesc);
102 }
103
104
105 // Verify that value1 is less than value2.
106 #define PQXX_CHECK_LESS(value1, value2, desc) \
107 pqxx::test::check_less( \
108 __FILE__, __LINE__, (value1), #value1, (value2), #value2, (desc))
109 // Verify that value1 is greater than value2.
110 #define PQXX_CHECK_GREATER(value2, value1, desc) \
111 pqxx::test::check_less( \
112 __FILE__, __LINE__, (value1), #value1, (value2), #value2, (desc))
113 template<typename VALUE1, typename VALUE2>
check_less(char const file[],int line,VALUE1 value1,char const text1[],VALUE2 value2,char const text2[],std::string const & desc)114 inline void check_less(
115 char const file[], int line, VALUE1 value1, char const text1[],
116 VALUE2 value2, char const text2[], std::string const &desc)
117 {
118 if (value1 < value2)
119 return;
120 std::string const fulldesc = desc + " (" + text1 + " >= " + text2 +
121 ": "
122 "\"lower\"=" +
123 to_string(value1) +
124 ", "
125 "\"upper\"=" +
126 to_string(value2) + ")";
127 throw test_failure(file, line, fulldesc);
128 }
129
130
131 // Verify that value1 is less than or equal to value2.
132 #define PQXX_CHECK_LESS_EQUAL(value1, value2, desc) \
133 pqxx::test::check_less_equal( \
134 __FILE__, __LINE__, (value1), #value1, (value2), #value2, (desc))
135 // Verify that value1 is greater than or equal to value2.
136 #define PQXX_CHECK_GREATER_EQUAL(value2, value1, desc) \
137 pqxx::test::check_less_equal( \
138 __FILE__, __LINE__, (value1), #value1, (value2), #value2, (desc))
139 template<typename VALUE1, typename VALUE2>
check_less_equal(char const file[],int line,VALUE1 value1,char const text1[],VALUE2 value2,char const text2[],std::string const & desc)140 inline void check_less_equal(
141 char const file[], int line, VALUE1 value1, char const text1[],
142 VALUE2 value2, char const text2[], std::string const &desc)
143 {
144 if (value1 <= value2)
145 return;
146 std::string const fulldesc = desc + " (" + text1 + " > " + text2 +
147 ": "
148 "\"lower\"=" +
149 to_string(value1) +
150 ", "
151 "\"upper\"=" +
152 to_string(value2) + ")";
153 throw test_failure(file, line, fulldesc);
154 }
155
156
157 struct failure_to_fail
158 {};
159
160
161 namespace internal
162 {
163 /// Syntactic placeholder: require (and accept) semicolon after block.
end_of_statement()164 inline void end_of_statement() {}
165 } // namespace internal
166
167
168 // Verify that "action" does not throw an exception.
169 #define PQXX_CHECK_SUCCEEDS(action, desc) \
170 { \
171 try \
172 { \
173 action; \
174 } \
175 catch (std::exception const &e) \
176 { \
177 PQXX_CHECK_NOTREACHED( \
178 std::string{desc} + " - \"" + \
179 #action "\" threw exception: " + e.what()); \
180 } \
181 catch (...) \
182 { \
183 PQXX_CHECK_NOTREACHED( \
184 std::string{desc} + " - \"" + #action "\" threw a non-exception!"); \
185 } \
186 } \
187 pqxx::test::internal::end_of_statement()
188
189 // Verify that "action" throws an exception, of any std::exception-based type.
190 #define PQXX_CHECK_THROWS_EXCEPTION(action, desc) \
191 { \
192 try \
193 { \
194 action; \
195 throw pqxx::test::failure_to_fail(); \
196 } \
197 catch (pqxx::test::failure_to_fail const &) \
198 { \
199 PQXX_CHECK_NOTREACHED( \
200 std::string{desc} + " (\"" #action "\" did not throw)"); \
201 } \
202 catch (std::exception const &) \
203 {} \
204 catch (...) \
205 { \
206 PQXX_CHECK_NOTREACHED( \
207 std::string{desc} + " (\"" #action "\" threw non-exception type)"); \
208 } \
209 } \
210 pqxx::test::internal::end_of_statement()
211
212 // Verify that "action" throws "exception_type" (which is not std::exception).
213 #define PQXX_CHECK_THROWS(action, exception_type, desc) \
214 { \
215 try \
216 { \
217 action; \
218 throw pqxx::test::failure_to_fail(); \
219 } \
220 catch (pqxx::test::failure_to_fail const &) \
221 { \
222 PQXX_CHECK_NOTREACHED( \
223 std::string{desc} + " (\"" #action \
224 "\" did not throw " #exception_type ")"); \
225 } \
226 catch (exception_type const &) \
227 {} \
228 catch (std::exception const &e) \
229 { \
230 PQXX_CHECK_NOTREACHED( \
231 std::string{desc} + \
232 " (\"" #action \
233 "\" " \
234 "threw exception other than " #exception_type ": " + \
235 e.what() + ")"); \
236 } \
237 catch (...) \
238 { \
239 PQXX_CHECK_NOTREACHED( \
240 std::string{desc} + " (\"" #action "\" threw non-exception type)"); \
241 } \
242 } \
243 pqxx::test::internal::end_of_statement()
244
245 #define PQXX_CHECK_BOUNDS(value, lower, upper, desc) \
246 pqxx::test::check_bounds( \
247 __FILE__, __LINE__, (value), #value, (lower), #lower, (upper), #upper, \
248 (desc))
249 template<typename VALUE, typename LOWER, typename UPPER>
check_bounds(char const file[],int line,VALUE value,char const text[],LOWER lower,char const lower_text[],UPPER upper,char const upper_text[],std::string const & desc)250 inline void check_bounds(
251 char const file[], int line, VALUE value, char const text[], LOWER lower,
252 char const lower_text[], UPPER upper, char const upper_text[],
253 std::string const &desc)
254 {
255 std::string const range_check = std::string{lower_text} + " < " + upper_text,
256 lower_check =
257 std::string{"!("} + text + " < " + lower_text + ")",
258 upper_check = std::string{text} + " < " + upper_text;
259
260 pqxx::test::check(
261 file, line, lower < upper, range_check.c_str(),
262 desc + " (acceptable range is empty; value was " + text + ")");
263 pqxx::test::check(
264 file, line, not(value < lower), lower_check.c_str(),
265 desc + " (" + text + " is below lower bound " + lower_text + ")");
266 pqxx::test::check(
267 file, line, value < upper, upper_check.c_str(),
268 desc + " (" + text + " is not below upper bound " + upper_text + ")");
269 }
270
271
272 // Report expected exception
273 void expected_exception(std::string const &);
274
275
276 // Represent result row as string.
277 std::string list_row(row);
278 // Represent result as string.
279 std::string list_result(result);
280 // Represent result iterator as string.
281 std::string list_result_iterator(result::const_iterator);
282
283
284 // @deprecated Set up test data for legacy tests.
285 void create_pqxxevents(transaction_base &);
286 } // namespace test
287
288
to_string(row const & value)289 template<> inline std::string to_string(row const &value)
290 {
291 return pqxx::test::list_row(value);
292 }
293
294
to_string(result const & value)295 template<> inline std::string to_string(result const &value)
296 {
297 return pqxx::test::list_result(value);
298 }
299
300
to_string(result::const_iterator const & value)301 template<> inline std::string to_string(result::const_iterator const &value)
302 {
303 return pqxx::test::list_result_iterator(value);
304 }
305 } // namespace pqxx
306