Move roundtrip-tests related helpers to SQLite3 test

This is the only place where they're used so far and it doesn't make
sense to compile them many times over when building the tests for the
other backends.

If these helpers are needed in the other backends tests, we should
extract them into their own header and include it as necessary.
This commit is contained in:
Vadim Zeitlin
2024-10-22 00:41:23 +02:00
parent a55c80984a
commit 33139741b3
2 changed files with 102 additions and 122 deletions
-122
View File
@@ -293,131 +293,9 @@ template<> struct type_conversion<PhonebookEntry3>
namespace soci
{
// Helper used by test_roundtrip() below which collects all round trip test
// data and allows to define a type conversion for it.
template<typename T>
struct Roundtrip
{
typedef T val_type;
Roundtrip(soci::db_type type, T val)
: inType(type), inVal(val) {}
soci::db_type inType;
T inVal;
soci::db_type outType;
T outVal;
};
// Test a rountrip insertion data to the current database for the arithmetic type T
// This test specifically use the dynamic bindings and the DDL creation statements.
template<typename T>
struct type_conversion<Roundtrip<T>>
{
static_assert(std::is_arithmetic<T>::value, "Roundtrip currently supported only for numeric types");
typedef soci::values base_type;
static void from_base(soci::values const &v, soci::indicator, Roundtrip<T> &t)
{
t.outType = v.get_properties(0).get_db_type();
switch (t.outType)
{
case soci::db_int8: t.outVal = static_cast<T>(v.get<std::int8_t>(0)); break;
case soci::db_uint8: t.outVal = static_cast<T>(v.get<std::uint8_t>(0)); break;
case soci::db_int16: t.outVal = static_cast<T>(v.get<std::int16_t>(0)); break;
case soci::db_uint16: t.outVal = static_cast<T>(v.get<std::uint16_t>(0)); break;
case soci::db_int32: t.outVal = static_cast<T>(v.get<std::int32_t>(0)); break;
case soci::db_uint32: t.outVal = static_cast<T>(v.get<std::uint32_t>(0)); break;
case soci::db_int64: t.outVal = static_cast<T>(v.get<std::int64_t>(0)); break;
case soci::db_uint64: t.outVal = static_cast<T>(v.get<std::uint64_t>(0)); break;
case soci::db_double: t.outVal = static_cast<T>(v.get<double>(0)); break;
default: FAIL_CHECK("Unsupported type mapped to db_type"); break;
}
}
static void to_base(Roundtrip<T> const &t, soci::values &v, soci::indicator&)
{
v.set("VAL", t.inVal);
}
};
namespace tests
{
template<typename T>
void check(soci::Roundtrip<T> const &val)
{
CHECK(val.inType == val.outType);
CHECK(val.inVal == val.outVal);
}
template<>
void check(soci::Roundtrip<double> const &val)
{
CHECK(val.inType == val.outType);
CHECK(std::fpclassify(val.inVal) == std::fpclassify(val.outVal));
if (std::isnormal(val.inVal) && std::isnormal(val.outVal))
CHECK_THAT(val.inVal, Catch::Matchers::WithinRel(val.outVal));
}
template<typename T>
void test_roundtrip(soci::session &sql, soci::db_type inputType, T inputVal)
{
try
{
Roundtrip<T> tester(inputType, inputVal);
const std::string table = "TEST_ROUNDTRIP";
sql.create_table(table).column("VAL", tester.inType);
struct table_dropper
{
table_dropper(soci::session& sql, std::string const& table)
: sql_(sql), table_(table) {}
~table_dropper() { sql_ << "DROP TABLE " << table_; }
soci::session& sql_;
const std::string table_;
} dropper(sql, table);
sql << "INSERT INTO " << table << "(VAL) VALUES (:VAL)", soci::use(const_cast<const Roundtrip<T>&>(tester));
soci::statement stmt = (sql.prepare << "SELECT * FROM " << table);
stmt.exchange(soci::into(tester));
stmt.define_and_bind();
stmt.execute();
stmt.fetch();
check(tester);
}
catch (const std::exception& e)
{
FAIL_CHECK(e.what());
}
}
// TODO: improve cleanup capabilities by subtypes, soci_test name may be omitted --mloskot
// i.e. optional ctor param accepting custom table name
class table_creator_base
{
public:
table_creator_base(session& sql)
: msession(sql) { drop(); }
virtual ~table_creator_base() { drop();}
private:
void drop()
{
try
{
msession << "drop table soci_test";
}
catch (soci_error const& e)
{
//std::cerr << e.what() << std::endl;
e.what();
}
}
session& msession;
SOCI_NOT_COPYABLE(table_creator_base)
};
class procedure_creator_base
{
public:
+102
View File
@@ -589,6 +589,108 @@ TEST_CASE("SQLite DDL with metadata", "[sqlite][ddl]")
CHECK(ddl_t3_found == false);
}
// Helpers for the DDL roundtrip test below.
namespace soci
{
// Helper used by test_roundtrip() below which collects all round trip test
// data and allows to define a type conversion for it.
template<typename T>
struct Roundtrip
{
typedef T val_type;
Roundtrip(soci::db_type type, T val)
: inType(type), inVal(val) {}
soci::db_type inType;
T inVal;
soci::db_type outType;
T outVal;
};
// Test a rountrip insertion data to the current database for the arithmetic type T
// This test specifically use the dynamic bindings and the DDL creation statements.
template<typename T>
struct type_conversion<Roundtrip<T>>
{
static_assert(std::is_arithmetic<T>::value, "Roundtrip currently supported only for numeric types");
typedef soci::values base_type;
static void from_base(soci::values const &v, soci::indicator, Roundtrip<T> &t)
{
t.outType = v.get_properties(0).get_db_type();
switch (t.outType)
{
case soci::db_int8: t.outVal = static_cast<T>(v.get<std::int8_t>(0)); break;
case soci::db_uint8: t.outVal = static_cast<T>(v.get<std::uint8_t>(0)); break;
case soci::db_int16: t.outVal = static_cast<T>(v.get<std::int16_t>(0)); break;
case soci::db_uint16: t.outVal = static_cast<T>(v.get<std::uint16_t>(0)); break;
case soci::db_int32: t.outVal = static_cast<T>(v.get<std::int32_t>(0)); break;
case soci::db_uint32: t.outVal = static_cast<T>(v.get<std::uint32_t>(0)); break;
case soci::db_int64: t.outVal = static_cast<T>(v.get<std::int64_t>(0)); break;
case soci::db_uint64: t.outVal = static_cast<T>(v.get<std::uint64_t>(0)); break;
case soci::db_double: t.outVal = static_cast<T>(v.get<double>(0)); break;
default: FAIL_CHECK("Unsupported type mapped to db_type"); break;
}
}
static void to_base(Roundtrip<T> const &t, soci::values &v, soci::indicator&)
{
v.set("VAL", t.inVal);
}
};
template<typename T>
void check(soci::Roundtrip<T> const &val)
{
CHECK(val.inType == val.outType);
CHECK(val.inVal == val.outVal);
}
template<>
void check(soci::Roundtrip<double> const &val)
{
CHECK(val.inType == val.outType);
CHECK(std::fpclassify(val.inVal) == std::fpclassify(val.outVal));
if (std::isnormal(val.inVal) && std::isnormal(val.outVal))
CHECK_THAT(val.inVal, Catch::Matchers::WithinRel(val.outVal));
}
template<typename T>
void test_roundtrip(soci::session &sql, soci::db_type inputType, T inputVal)
{
try
{
Roundtrip<T> tester(inputType, inputVal);
const std::string table = "TEST_ROUNDTRIP";
sql.create_table(table).column("VAL", tester.inType);
struct table_dropper
{
table_dropper(soci::session& sql, std::string const& table)
: sql_(sql), table_(table) {}
~table_dropper() { sql_ << "DROP TABLE " << table_; }
soci::session& sql_;
const std::string table_;
} dropper(sql, table);
sql << "INSERT INTO " << table << "(VAL) VALUES (:VAL)", soci::use(const_cast<const Roundtrip<T>&>(tester));
soci::statement stmt = (sql.prepare << "SELECT * FROM " << table);
stmt.exchange(soci::into(tester));
stmt.define_and_bind();
stmt.execute();
stmt.fetch();
check(tester);
}
catch (const std::exception& e)
{
FAIL_CHECK(e.what());
}
}
} // namespace soci
TEST_CASE("SQLite DDL roundrip", "[sqlite][ddl][roundtrip]")
{
soci::session sql(backEnd, connectString);