test_helpers.hxx 13 KB

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