runner.cxx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* libpqxx test runner.
  2. */
  3. #include <cassert>
  4. #include <iostream>
  5. #include <list>
  6. #include <map>
  7. #include <new>
  8. #include <stdexcept>
  9. #include <string>
  10. #include <pqxx/transaction>
  11. #include "test_helpers.hxx"
  12. namespace
  13. {
  14. inline std::string deref_field(pqxx::field const &f)
  15. {
  16. return f.c_str();
  17. }
  18. } // namespace
  19. namespace pqxx::test
  20. {
  21. test_failure::test_failure(
  22. std::string const &ffile, int fline, std::string const &desc) :
  23. std::logic_error(desc), m_file(ffile), m_line(fline)
  24. {}
  25. test_failure::~test_failure() noexcept = default;
  26. /// Drop table, if it exists.
  27. inline void drop_table(transaction_base &t, std::string const &table)
  28. {
  29. t.exec("DROP TABLE IF EXISTS " + table);
  30. }
  31. [[noreturn]] void
  32. check_notreached(char const file[], int line, std::string desc)
  33. {
  34. throw test_failure(file, line, desc);
  35. }
  36. void check(
  37. char const file[], int line, bool condition, char const text[],
  38. std::string const &desc)
  39. {
  40. if (not condition)
  41. throw test_failure(
  42. file, line, desc + " (failed expression: " + text + ")");
  43. }
  44. void expected_exception(std::string const &message)
  45. {
  46. std::cout << "(Expected) " << message << std::endl;
  47. }
  48. std::string list_row(row Obj)
  49. {
  50. return separated_list(", ", std::begin(Obj), std::end(Obj), deref_field);
  51. }
  52. std::string list_result(result Obj)
  53. {
  54. if (std::empty(Obj))
  55. return "<empty>";
  56. return "{" +
  57. separated_list(
  58. "}\n{", std::begin(Obj), std::end(Obj),
  59. [](row r) { return list_row(r); }) +
  60. "}";
  61. }
  62. std::string list_result_iterator(result::const_iterator Obj)
  63. {
  64. return "<iterator at " + to_string(Obj.rownumber()) + ">";
  65. }
  66. void create_pqxxevents(transaction_base &t)
  67. {
  68. t.exec(
  69. "CREATE TEMP TABLE pqxxevents(year integer, event varchar) "
  70. "ON COMMIT PRESERVE ROWS");
  71. t.exec("INSERT INTO pqxxevents(year, event) VALUES (71, 'jtv')");
  72. t.exec("INSERT INTO pqxxevents(year, event) VALUES (38, 'time_t overflow')");
  73. t.exec(
  74. "INSERT INTO pqxxevents(year, event) VALUES (1, '''911'' WTC attack')");
  75. t.exec("INSERT INTO pqxxevents(year, event) VALUES (81, 'C:\\>')");
  76. t.exec(
  77. "INSERT INTO pqxxevents(year, event) VALUES (1978, 'bloody\t\tcold')");
  78. t.exec("INSERT INTO pqxxevents(year, event) VALUES (99, '')");
  79. t.exec("INSERT INTO pqxxevents(year, event) VALUES (2002, 'libpqxx')");
  80. t.exec(
  81. "INSERT INTO pqxxevents(year, event) "
  82. "VALUES (1989, 'Ode an die Freiheit')");
  83. t.exec(
  84. "INSERT INTO pqxxevents(year, event) VALUES (2001, 'New millennium')");
  85. t.exec("INSERT INTO pqxxevents(year, event) VALUES (1974, '')");
  86. t.exec("INSERT INTO pqxxevents(year, event) VALUES (97, 'Asian crisis')");
  87. t.exec(
  88. "INSERT INTO pqxxevents(year, event) VALUES (2001, 'A Space Odyssey')");
  89. }
  90. } // namespace pqxx::test
  91. namespace
  92. {
  93. std::map<std::string const, pqxx::test::testfunc> *all_tests{nullptr};
  94. } // namespace
  95. namespace pqxx::test
  96. {
  97. void register_test(char const name[], pqxx::test::testfunc func)
  98. {
  99. if (all_tests == nullptr)
  100. {
  101. all_tests = new std::map<std::string const, pqxx::test::testfunc>();
  102. }
  103. else
  104. {
  105. assert(all_tests->find(name) == all_tests->end());
  106. }
  107. (*all_tests)[name] = func;
  108. }
  109. } // namespace pqxx::test
  110. int main(int argc, char const *argv[])
  111. {
  112. char const *const test_name{(argc > 1) ? argv[1] : nullptr};
  113. int test_count = 0;
  114. std::list<std::string> failed;
  115. for (auto const &i : *all_tests)
  116. if (test_name == nullptr or std::string{test_name} == std::string{i.first})
  117. {
  118. std::cout << std::endl << "Running: " << i.first << std::endl;
  119. bool success = false;
  120. try
  121. {
  122. i.second();
  123. success = true;
  124. }
  125. catch (pqxx::test::test_failure const &e)
  126. {
  127. std::cerr << "Test failure in " + e.file() + " line " +
  128. pqxx::to_string(e.line())
  129. << ": " << e.what() << std::endl;
  130. }
  131. catch (std::bad_alloc const &)
  132. {
  133. std::cerr << "Out of memory!" << std::endl;
  134. }
  135. catch (pqxx::feature_not_supported const &e)
  136. {
  137. std::cerr << "Not testing unsupported feature: " << e.what()
  138. << std::endl;
  139. success = true;
  140. --test_count;
  141. }
  142. catch (pqxx::sql_error const &e)
  143. {
  144. std::cerr << "SQL error: " << e.what() << std::endl
  145. << "Query was: " << e.query() << std::endl;
  146. }
  147. catch (std::exception const &e)
  148. {
  149. std::cerr << "Exception: " << e.what() << std::endl;
  150. }
  151. catch (...)
  152. {
  153. std::cerr << "Unknown exception" << std::endl;
  154. }
  155. if (not success)
  156. {
  157. std::cerr << "FAILED: " << i.first << std::endl;
  158. failed.emplace_back(i.first);
  159. }
  160. ++test_count;
  161. }
  162. std::cout << "Ran " << test_count << " test(s).\n";
  163. if (not std::empty(failed))
  164. {
  165. std::cerr << "*** " << std::size(failed) << " test(s) failed: ***\n";
  166. for (auto const &i : failed) std::cerr << "\t" << i << '\n';
  167. }
  168. return int(std::size(failed));
  169. }