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