test_errorhandler.cxx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include <vector>
  2. #include <pqxx/connection>
  3. #include <pqxx/errorhandler>
  4. #include "../test_helpers.hxx"
  5. namespace
  6. {
  7. class TestErrorHandler final : public pqxx::errorhandler
  8. {
  9. public:
  10. TestErrorHandler(
  11. pqxx::connection &c, std::vector<TestErrorHandler *> &activated_handlers,
  12. bool retval = true) :
  13. pqxx::errorhandler(c),
  14. return_value(retval),
  15. message(),
  16. handler_list(activated_handlers)
  17. {}
  18. bool operator()(char const msg[]) noexcept override
  19. {
  20. message = std::string{msg};
  21. handler_list.push_back(this);
  22. return return_value;
  23. }
  24. bool return_value;
  25. std::string message;
  26. std::vector<TestErrorHandler *> &handler_list;
  27. };
  28. } // namespace
  29. namespace pqxx
  30. {
  31. template<> struct nullness<TestErrorHandler *>
  32. {
  33. // clang warns about these being unused. And clang 6 won't accept a
  34. // [[maybe_unused]] attribute on them either!
  35. // static inline constexpr bool has_null{true};
  36. // static inline constexpr bool always_null{false};
  37. static constexpr bool is_null(TestErrorHandler *e) noexcept
  38. {
  39. return e == nullptr;
  40. }
  41. static constexpr TestErrorHandler *null() noexcept { return nullptr; }
  42. };
  43. template<> struct string_traits<TestErrorHandler *>
  44. {
  45. static constexpr std::size_t size_buffer(TestErrorHandler *const &) noexcept
  46. {
  47. return 100;
  48. }
  49. static char *into_buf(char *begin, char *end, TestErrorHandler *const &value)
  50. {
  51. std::string text{"TestErrorHandler at " + pqxx::to_string(value)};
  52. if (pqxx::internal::cmp_greater_equal(std::size(text), end - begin))
  53. throw conversion_overrun{"Not enough buffer for TestErrorHandler."};
  54. std::memcpy(begin, text.c_str(), std::size(text) + 1);
  55. return begin + std::size(text) + 1;
  56. }
  57. };
  58. } // namespace pqxx
  59. namespace
  60. {
  61. void test_process_notice_calls_errorhandler(pqxx::connection &c)
  62. {
  63. std::vector<TestErrorHandler *> dummy;
  64. TestErrorHandler handler(c, dummy);
  65. c.process_notice("Error!\n");
  66. PQXX_CHECK_EQUAL(handler.message, "Error!\n", "Error not handled.");
  67. }
  68. void test_error_handlers_get_called_newest_to_oldest(pqxx::connection &c)
  69. {
  70. std::vector<TestErrorHandler *> handlers;
  71. TestErrorHandler h1(c, handlers);
  72. TestErrorHandler h2(c, handlers);
  73. TestErrorHandler h3(c, handlers);
  74. c.process_notice("Warning.\n");
  75. PQXX_CHECK_EQUAL(h3.message, "Warning.\n", "Message not handled.");
  76. PQXX_CHECK_EQUAL(h2.message, "Warning.\n", "Broken handling chain.");
  77. PQXX_CHECK_EQUAL(h1.message, "Warning.\n", "Insane handling chain.");
  78. PQXX_CHECK_EQUAL(std::size(handlers), 3u, "Wrong number of handler calls.");
  79. PQXX_CHECK_EQUAL(&h3, handlers[0], "Unexpected handling order.");
  80. PQXX_CHECK_EQUAL(&h2, handlers[1], "Insane handling order.");
  81. PQXX_CHECK_EQUAL(&h1, handlers[2], "Impossible handling order.");
  82. }
  83. void test_returning_false_stops_error_handling(pqxx::connection &c)
  84. {
  85. std::vector<TestErrorHandler *> handlers;
  86. TestErrorHandler starved(c, handlers);
  87. TestErrorHandler blocker(c, handlers, false);
  88. c.process_notice("Error output.\n");
  89. PQXX_CHECK_EQUAL(std::size(handlers), 1u, "Handling chain was not stopped.");
  90. PQXX_CHECK_EQUAL(handlers[0], &blocker, "Wrong handler got message.");
  91. PQXX_CHECK_EQUAL(blocker.message, "Error output.\n", "Didn't get message.");
  92. PQXX_CHECK_EQUAL(starved.message, "", "Message received; it shouldn't be.");
  93. }
  94. void test_destroyed_error_handlers_are_not_called(pqxx::connection &c)
  95. {
  96. std::vector<TestErrorHandler *> handlers;
  97. {
  98. TestErrorHandler doomed(c, handlers);
  99. }
  100. c.process_notice("Unheard output.");
  101. PQXX_CHECK(
  102. std::empty(handlers), "Message was received on dead errorhandler.");
  103. }
  104. void test_destroying_connection_unregisters_handlers()
  105. {
  106. TestErrorHandler *survivor;
  107. std::vector<TestErrorHandler *> handlers;
  108. {
  109. pqxx::connection c;
  110. survivor = new TestErrorHandler(c, handlers);
  111. }
  112. // Make some pointless use of survivor just to prove that this doesn't crash.
  113. (*survivor)("Hi");
  114. PQXX_CHECK_EQUAL(
  115. std::size(handlers), 1u, "Ghost of dead ex-connection haunts handler.");
  116. delete survivor;
  117. }
  118. class MinimalErrorHandler final : public pqxx::errorhandler
  119. {
  120. public:
  121. explicit MinimalErrorHandler(pqxx::connection &c) : pqxx::errorhandler(c) {}
  122. bool operator()(char const[]) noexcept override { return true; }
  123. };
  124. void test_get_errorhandlers(pqxx::connection &c)
  125. {
  126. std::unique_ptr<MinimalErrorHandler> eh3;
  127. auto const handlers_before{c.get_errorhandlers()};
  128. std::size_t const base_handlers{std::size(handlers_before)};
  129. {
  130. MinimalErrorHandler eh1(c);
  131. auto const handlers_with_eh1{c.get_errorhandlers()};
  132. PQXX_CHECK_EQUAL(
  133. std::size(handlers_with_eh1), base_handlers + 1,
  134. "Registering a handler didn't create exactly one handler.");
  135. PQXX_CHECK_EQUAL(
  136. std::size_t(*std::rbegin(handlers_with_eh1)), std::size_t(&eh1),
  137. "Wrong handler or wrong order.");
  138. {
  139. MinimalErrorHandler eh2(c);
  140. auto const handlers_with_eh2{c.get_errorhandlers()};
  141. PQXX_CHECK_EQUAL(
  142. std::size(handlers_with_eh2), base_handlers + 2,
  143. "Adding second handler didn't work.");
  144. PQXX_CHECK_EQUAL(
  145. std::size_t(*(std::rbegin(handlers_with_eh2) + 1)), std::size_t(&eh1),
  146. "Second handler upset order.");
  147. PQXX_CHECK_EQUAL(
  148. std::size_t(*std::rbegin(handlers_with_eh2)), std::size_t(&eh2),
  149. "Second handler isn't right.");
  150. }
  151. auto const handlers_without_eh2{c.get_errorhandlers()};
  152. PQXX_CHECK_EQUAL(
  153. std::size(handlers_without_eh2), base_handlers + 1,
  154. "Handler destruction produced wrong-sized handlers list.");
  155. PQXX_CHECK_EQUAL(
  156. std::size_t(*std::rbegin(handlers_without_eh2)), std::size_t(&eh1),
  157. "Destroyed wrong handler.");
  158. eh3 = std::make_unique<MinimalErrorHandler>(c);
  159. auto const handlers_with_eh3{c.get_errorhandlers()};
  160. PQXX_CHECK_EQUAL(
  161. std::size(handlers_with_eh3), base_handlers + 2,
  162. "Remove-and-add breaks.");
  163. PQXX_CHECK_EQUAL(
  164. std::size_t(*std::rbegin(handlers_with_eh3)), std::size_t(eh3.get()),
  165. "Added wrong third handler.");
  166. }
  167. auto const handlers_without_eh1{c.get_errorhandlers()};
  168. PQXX_CHECK_EQUAL(
  169. std::size(handlers_without_eh1), base_handlers + 1,
  170. "Destroying oldest handler didn't work as expected.");
  171. PQXX_CHECK_EQUAL(
  172. std::size_t(*std::rbegin(handlers_without_eh1)), std::size_t(eh3.get()),
  173. "Destroyed wrong handler.");
  174. eh3.reset();
  175. auto const handlers_without_all{c.get_errorhandlers()};
  176. PQXX_CHECK_EQUAL(
  177. std::size(handlers_without_all), base_handlers,
  178. "Destroying all custom handlers didn't work as expected.");
  179. }
  180. void test_errorhandler()
  181. {
  182. pqxx::connection conn;
  183. test_process_notice_calls_errorhandler(conn);
  184. test_error_handlers_get_called_newest_to_oldest(conn);
  185. test_returning_false_stops_error_handling(conn);
  186. test_destroyed_error_handlers_are_not_called(conn);
  187. test_destroying_connection_unregisters_handlers();
  188. test_get_errorhandlers(conn);
  189. }
  190. PQXX_REGISTER_TEST(test_errorhandler);
  191. } // namespace