diff options
-rw-r--r-- | lib/dbTypes.h | 4 | ||||
-rw-r--r-- | lib/output/pq/writePqCopyStrm.cpp | 12 | ||||
-rw-r--r-- | test/helpers.cpp | 15 | ||||
-rw-r--r-- | test/helpers.h | 13 | ||||
-rw-r--r-- | test/test-postgresql.cpp | 64 |
5 files changed, 104 insertions, 4 deletions
diff --git a/lib/dbTypes.h b/lib/dbTypes.h index 31793e4..f49c929 100644 --- a/lib/dbTypes.h +++ b/lib/dbTypes.h @@ -13,10 +13,10 @@ struct timespec; namespace MyGrate { template<typename T> struct printer; template<> struct printer<double> { - constexpr static const char * const fmt {"%f"}; + constexpr static const char * const fmt {"%g"}; }; template<> struct printer<float> { - constexpr static const char * const fmt {"%f"}; + constexpr static const char * const fmt {"%g"}; }; template<> struct printer<int8_t> { constexpr static const char * const fmt {"%hhd"}; diff --git a/lib/output/pq/writePqCopyStrm.cpp b/lib/output/pq/writePqCopyStrm.cpp index dd402e7..4664e6b 100644 --- a/lib/output/pq/writePqCopyStrm.cpp +++ b/lib/output/pq/writePqCopyStrm.cpp @@ -59,7 +59,7 @@ namespace MyGrate::Output::Pq { fwrite(pos, esc - pos, 1, out); pos = esc; } - while (pos != v.end()) { + while (pos != v.end() && std::iscntrl(*pos)) { fprintf(out, "\\%03o", *pos); pos++; } @@ -74,9 +74,17 @@ namespace MyGrate::Output::Pq { void WritePqCopyStream::operator()(Blob v) const { + static constexpr const auto hex {[] { + std::array<std::array<char, 2>, 256> h {}; + std::array<char, 16> hc {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + for (int x {}; x < 256; x += 1) { + h[x] = {hc[x >> 4], hc[x & 0xF]}; + } + return h; + }()}; fputs("\\\\x", out); std::for_each(v.begin(), v.end(), [this](auto b) { - fprintf(out, "%02hhx", (uint8_t)b); + fwrite(hex[(uint8_t)b].data(), 2, 1, out); }); } } diff --git a/test/helpers.cpp b/test/helpers.cpp new file mode 100644 index 0000000..f4fc030 --- /dev/null +++ b/test/helpers.cpp @@ -0,0 +1,15 @@ +#include "helpers.h" + +MemStream::MemStream() : out {nullptr}, len {}, s {open_memstream(&out, &len)} { } + +MemStream::~MemStream() +{ + fclose(s); + free(out); +} + +void +MemStream::flush() +{ + fflush(s); +} diff --git a/test/helpers.h b/test/helpers.h index 59ae18d..87ef31d 100644 --- a/test/helpers.h +++ b/test/helpers.h @@ -3,8 +3,10 @@ #include <concepts> #include <cstddef> +#include <cstdio> #include <ctime> #include <iostream> +#include <memory> #include <optional> inline constexpr std::byte operator""_b(const unsigned long long hex) @@ -55,4 +57,15 @@ make_tm(int year, int mon, int day, int hr, int min, int sec) return tm; } +struct MemStream { + MemStream(); + virtual ~MemStream(); + + void flush(); + + char * out; + size_t len; + FILE * s; +}; + #endif diff --git a/test/test-postgresql.cpp b/test/test-postgresql.cpp index 15ba789..727e08c 100644 --- a/test/test-postgresql.cpp +++ b/test/test-postgresql.cpp @@ -1,6 +1,9 @@ #define BOOST_TEST_MODULE PostgreSQL +#include <boost/mpl/list.hpp> +#include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> +#include "helpers.h" #include "testdb-postgresql.h" #include <cstddef> #include <dbConn.h> @@ -11,6 +14,7 @@ #include <helpers.h> #include <memory> #include <output/pq/pqConn.h> +#include <output/pq/writePqCopyStrm.h> #include <stdexcept> #include <string_view> #include <type_traits> @@ -91,3 +95,63 @@ BOOST_AUTO_TEST_CASE(mock_schema) auto rs = MyGrate::DbStmt<"SELECT COUNT(*) FROM mygrate.source">::execute(&mdb); BOOST_CHECK_EQUAL(rs->at(0, 0).operator unsigned int(), 0); } + +BOOST_FIXTURE_TEST_SUITE(ms, MemStream); + +BOOST_DATA_TEST_CASE(write_strings, + boost::unit_test::data::make({ + std::make_tuple("", ""), + {"simple", "simple"}, + {"simple with spaces", "simple with spaces"}, + {"simple\twith\ttabs", "simple\\011with\\011tabs"}, + {"\ttab start", "\\011tab start"}, + {"tab end\t", "tab end\\011"}, + {"tab\t\t\t\tmany", "tab\\011\\011\\011\\011many"}, + }), + in, exp) +{ + MyGrate::Output::Pq::WritePqCopyStream c {s}; + c(in); + flush(); + + BOOST_REQUIRE(out); + BOOST_CHECK_EQUAL(out, exp); +} + +using IntTypes = boost::mpl::list<int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t>; +BOOST_AUTO_TEST_CASE_TEMPLATE(write_ints, T, IntTypes) +{ + MyGrate::Output::Pq::WritePqCopyStream c {s}; + c(T {1}); + flush(); + + BOOST_REQUIRE(out); + BOOST_CHECK_EQUAL(len, 1); + BOOST_CHECK_EQUAL(out, "1"); +} + +using FloatTypes = boost::mpl::list<float, double>; +BOOST_AUTO_TEST_CASE_TEMPLATE(write_floats, T, FloatTypes) +{ + MyGrate::Output::Pq::WritePqCopyStream c {s}; + c(T {1.1}); + flush(); + + BOOST_REQUIRE(out); + BOOST_CHECK_EQUAL(len, 3); + BOOST_CHECK_EQUAL(out, "1.1"); +} + +BOOST_AUTO_TEST_CASE(write_blob) +{ + MyGrate::Output::Pq::WritePqCopyStream c {s}; + std::array<std::byte, 10> b {0x00_b, 0x10_b, 0x12_b, 0x30_b, 0x90_b, 0xaa_b, 0xff_b}; + c(b); + flush(); + + BOOST_REQUIRE(out); + BOOST_CHECK_EQUAL(len, 23); + BOOST_CHECK_EQUAL(out, R"B(\\x0010123090AAFF000000)B"); +} + +BOOST_AUTO_TEST_SUITE_END(); |