mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-28 00:38:51 +00:00
204 lines
4.9 KiB
C++
204 lines
4.9 KiB
C++
|
/* libpqxx test runner.
|
||
|
*/
|
||
|
#include <cassert>
|
||
|
#include <iostream>
|
||
|
#include <list>
|
||
|
#include <map>
|
||
|
#include <new>
|
||
|
#include <stdexcept>
|
||
|
#include <string>
|
||
|
|
||
|
#include <pqxx/transaction>
|
||
|
|
||
|
#include "test_helpers.hxx"
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
inline std::string deref_field(pqxx::field const &f)
|
||
|
{
|
||
|
return f.c_str();
|
||
|
}
|
||
|
} // namespace
|
||
|
|
||
|
|
||
|
namespace pqxx::test
|
||
|
{
|
||
|
test_failure::test_failure(
|
||
|
std::string const &ffile, int fline, std::string const &desc) :
|
||
|
std::logic_error(desc), m_file(ffile), m_line(fline)
|
||
|
{}
|
||
|
|
||
|
test_failure::~test_failure() noexcept = default;
|
||
|
|
||
|
|
||
|
/// Drop table, if it exists.
|
||
|
inline void drop_table(transaction_base &t, std::string const &table)
|
||
|
{
|
||
|
t.exec("DROP TABLE IF EXISTS " + table);
|
||
|
}
|
||
|
|
||
|
|
||
|
[[noreturn]] void
|
||
|
check_notreached(char const file[], int line, std::string desc)
|
||
|
{
|
||
|
throw test_failure(file, line, desc);
|
||
|
}
|
||
|
|
||
|
|
||
|
void check(
|
||
|
char const file[], int line, bool condition, char const text[],
|
||
|
std::string const &desc)
|
||
|
{
|
||
|
if (not condition)
|
||
|
throw test_failure(
|
||
|
file, line, desc + " (failed expression: " + text + ")");
|
||
|
}
|
||
|
|
||
|
|
||
|
void expected_exception(std::string const &message)
|
||
|
{
|
||
|
std::cout << "(Expected) " << message << std::endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
std::string list_row(row Obj)
|
||
|
{
|
||
|
return separated_list(", ", std::begin(Obj), std::end(Obj), deref_field);
|
||
|
}
|
||
|
|
||
|
|
||
|
std::string list_result(result Obj)
|
||
|
{
|
||
|
if (std::empty(Obj))
|
||
|
return "<empty>";
|
||
|
return "{" +
|
||
|
separated_list(
|
||
|
"}\n{", std::begin(Obj), std::end(Obj),
|
||
|
[](row r) { return list_row(r); }) +
|
||
|
"}";
|
||
|
}
|
||
|
|
||
|
|
||
|
std::string list_result_iterator(result::const_iterator Obj)
|
||
|
{
|
||
|
return "<iterator at " + to_string(Obj.rownumber()) + ">";
|
||
|
}
|
||
|
|
||
|
|
||
|
void create_pqxxevents(transaction_base &t)
|
||
|
{
|
||
|
t.exec(
|
||
|
"CREATE TEMP TABLE pqxxevents(year integer, event varchar) "
|
||
|
"ON COMMIT PRESERVE ROWS");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (71, 'jtv')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (38, 'time_t overflow')");
|
||
|
t.exec(
|
||
|
"INSERT INTO pqxxevents(year, event) VALUES (1, '''911'' WTC attack')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (81, 'C:\\>')");
|
||
|
t.exec(
|
||
|
"INSERT INTO pqxxevents(year, event) VALUES (1978, 'bloody\t\tcold')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (99, '')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (2002, 'libpqxx')");
|
||
|
t.exec(
|
||
|
"INSERT INTO pqxxevents(year, event) "
|
||
|
"VALUES (1989, 'Ode an die Freiheit')");
|
||
|
t.exec(
|
||
|
"INSERT INTO pqxxevents(year, event) VALUES (2001, 'New millennium')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (1974, '')");
|
||
|
t.exec("INSERT INTO pqxxevents(year, event) VALUES (97, 'Asian crisis')");
|
||
|
t.exec(
|
||
|
"INSERT INTO pqxxevents(year, event) VALUES (2001, 'A Space Odyssey')");
|
||
|
}
|
||
|
} // namespace pqxx::test
|
||
|
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
std::map<std::string const, pqxx::test::testfunc> *all_tests{nullptr};
|
||
|
} // namespace
|
||
|
|
||
|
|
||
|
namespace pqxx::test
|
||
|
{
|
||
|
void register_test(char const name[], pqxx::test::testfunc func)
|
||
|
{
|
||
|
if (all_tests == nullptr)
|
||
|
{
|
||
|
all_tests = new std::map<std::string const, pqxx::test::testfunc>();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
assert(all_tests->find(name) == all_tests->end());
|
||
|
}
|
||
|
(*all_tests)[name] = func;
|
||
|
}
|
||
|
} // namespace pqxx::test
|
||
|
|
||
|
|
||
|
int main(int argc, char const *argv[])
|
||
|
{
|
||
|
char const *const test_name{(argc > 1) ? argv[1] : nullptr};
|
||
|
|
||
|
int test_count = 0;
|
||
|
std::list<std::string> failed;
|
||
|
for (auto const &i : *all_tests)
|
||
|
if (test_name == nullptr or std::string{test_name} == std::string{i.first})
|
||
|
{
|
||
|
std::cout << std::endl << "Running: " << i.first << std::endl;
|
||
|
|
||
|
bool success = false;
|
||
|
try
|
||
|
{
|
||
|
i.second();
|
||
|
success = true;
|
||
|
}
|
||
|
catch (pqxx::test::test_failure const &e)
|
||
|
{
|
||
|
std::cerr << "Test failure in " + e.file() + " line " +
|
||
|
pqxx::to_string(e.line())
|
||
|
<< ": " << e.what() << std::endl;
|
||
|
}
|
||
|
catch (std::bad_alloc const &)
|
||
|
{
|
||
|
std::cerr << "Out of memory!" << std::endl;
|
||
|
}
|
||
|
catch (pqxx::feature_not_supported const &e)
|
||
|
{
|
||
|
std::cerr << "Not testing unsupported feature: " << e.what()
|
||
|
<< std::endl;
|
||
|
success = true;
|
||
|
--test_count;
|
||
|
}
|
||
|
catch (pqxx::sql_error const &e)
|
||
|
{
|
||
|
std::cerr << "SQL error: " << e.what() << std::endl
|
||
|
<< "Query was: " << e.query() << std::endl;
|
||
|
}
|
||
|
catch (std::exception const &e)
|
||
|
{
|
||
|
std::cerr << "Exception: " << e.what() << std::endl;
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
std::cerr << "Unknown exception" << std::endl;
|
||
|
}
|
||
|
|
||
|
if (not success)
|
||
|
{
|
||
|
std::cerr << "FAILED: " << i.first << std::endl;
|
||
|
failed.emplace_back(i.first);
|
||
|
}
|
||
|
++test_count;
|
||
|
}
|
||
|
|
||
|
std::cout << "Ran " << test_count << " test(s).\n";
|
||
|
|
||
|
if (not std::empty(failed))
|
||
|
{
|
||
|
std::cerr << "*** " << std::size(failed) << " test(s) failed: ***\n";
|
||
|
for (auto const &i : failed) std::cerr << "\t" << i << '\n';
|
||
|
}
|
||
|
|
||
|
return int(std::size(failed));
|
||
|
}
|