1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
#include <cstdint>
#include <variant>
#include <pqxx/connection>
#include <pqxx/transaction>
#include "../test_helpers.hxx"
using namespace std::literals;
// Some enums with string conversions.
enum EnumA
{
ea0,
ea1,
ea2
};
enum EnumB
{
eb0,
eb1,
eb2
};
namespace pqxx
{
PQXX_DECLARE_ENUM_CONVERSION(EnumA);
PQXX_DECLARE_ENUM_CONVERSION(EnumB);
} // namespace pqxx
namespace
{
// "A minimal difference."
constexpr double thres{0.00001};
void test_string_conversion()
{
PQXX_CHECK_EQUAL(
"C string array", pqxx::to_string("C string array"),
"C-style string constant does not convert to string properly.");
char text_array[]{"C char array"};
PQXX_CHECK_EQUAL(
"C char array", pqxx::to_string(text_array),
"C-style non-const char array does not convert to string properly.");
char const *text_ptr{"C string pointer"};
PQXX_CHECK_EQUAL(
"C string pointer", pqxx::to_string(text_ptr),
"C-style string pointer does not convert to string properly.");
std::string const cxx_string{"C++ string"};
PQXX_CHECK_EQUAL(
"C++ string", pqxx::to_string(cxx_string),
"C++-style string object does not convert to string properly.");
PQXX_CHECK_EQUAL("0", pqxx::to_string(0), "Zero does not convert right.");
PQXX_CHECK_EQUAL(
"1", pqxx::to_string(1), "Basic integer does not convert right.");
PQXX_CHECK_EQUAL("-1", pqxx::to_string(-1), "Negative numbers don't work.");
PQXX_CHECK_EQUAL(
"9999", pqxx::to_string(9999), "Larger numbers don't work.");
PQXX_CHECK_EQUAL(
"-9999", pqxx::to_string(-9999), "Larger negative numbers don't work.");
int x;
pqxx::from_string("0", x);
PQXX_CHECK_EQUAL(0, x, "Zero does not parse right.");
pqxx::from_string("1", x);
PQXX_CHECK_EQUAL(1, x, "Basic integer does not parse right.");
pqxx::from_string("-1", x);
PQXX_CHECK_EQUAL(-1, x, "Negative numbers don't work.");
pqxx::from_string("9999", x);
PQXX_CHECK_EQUAL(9999, x, "Larger numbers don't work.");
pqxx::from_string("-9999", x);
PQXX_CHECK_EQUAL(-9999, x, "Larger negative numbers don't work.");
// Bug #263 describes a case where this kind of overflow went undetected.
if (sizeof(unsigned int) == 4)
{
std::uint32_t u;
PQXX_CHECK_THROWS(
pqxx::from_string("4772185884", u), pqxx::conversion_error,
"Overflow not detected.");
}
// We can convert to and from long double. The implementation may fall
// back on a thread-local std::stringstream. Each call does its own
// cleanup, so the conversion works multiple times.
constexpr long double ld1{123456789.25}, ld2{9876543210.5};
constexpr char lds1[]{"123456789.25"}, lds2[]{"9876543210.5"};
PQXX_CHECK_EQUAL(
pqxx::to_string(ld1).substr(0, 12), lds1,
"Wrong conversion from long double.");
PQXX_CHECK_EQUAL(
pqxx::to_string(ld2).substr(0, 12), lds2,
"Wrong value on repeated conversion from long double.");
long double ldi1, ldi2;
pqxx::from_string(lds1, ldi1);
PQXX_CHECK_BOUNDS(
ldi1, ld1 - thres, ld1 + thres, "Wrong conversion to long double.");
pqxx::from_string(lds2, ldi2);
PQXX_CHECK_BOUNDS(
ldi2, ld2 - thres, ld2 + thres,
"Wrong repeated conversion to long double.");
// We can define string conversions for enums.
PQXX_CHECK_EQUAL(
pqxx::to_string(ea0), "0", "Enum-to-string conversion is broken.");
PQXX_CHECK_EQUAL(
pqxx::to_string(eb0), "0",
"Enum-to-string conversion is inconsistent between enum types.");
PQXX_CHECK_EQUAL(
pqxx::to_string(ea1), "1",
"Enum-to-string conversion breaks for nonzero value.");
EnumA ea;
pqxx::from_string("2", ea);
PQXX_CHECK_EQUAL(ea, ea2, "String-to-enum conversion is broken.");
}
void test_convert_variant_to_string()
{
PQXX_CHECK_EQUAL(
pqxx::to_string(std::variant<int, std::string>{99}), "99",
"First variant field did not convert right.");
PQXX_CHECK_EQUAL(
pqxx::to_string(std::variant<int, std::string>{"Text"}), "Text",
"Second variant field did not convert right.");
}
void test_integer_conversion()
{
PQXX_CHECK_EQUAL(
pqxx::from_string<int>("12"), 12, "Basic integer conversion failed.");
PQXX_CHECK_EQUAL(
pqxx::from_string<int>(" 12"), 12,
"Leading whitespace confused integer conversion.");
PQXX_CHECK_THROWS(
pqxx::ignore_unused(pqxx::from_string<int>("")), pqxx::conversion_error,
"Converting empty string to integer did not throw conversion error.");
PQXX_CHECK_THROWS(
pqxx::ignore_unused(pqxx::from_string<int>(" ")), pqxx::conversion_error,
"Converting whitespace to integer did not throw conversion error.");
PQXX_CHECK_EQUAL(
pqxx::from_string<int>("-6"), -6,
"Leading whitespace did not work with negative number.");
PQXX_CHECK_THROWS(
pqxx::ignore_unused(pqxx::from_string<int>("- 3")), pqxx::conversion_error,
"A space between negation and number was not properly flagged.");
PQXX_CHECK_THROWS(
pqxx::ignore_unused(pqxx::from_string<int>("-")), pqxx::conversion_error,
"Just a minus sign should not parse as an integer.");
}
void test_convert_null()
{
pqxx::connection cx;
pqxx::work tx{cx};
PQXX_CHECK_EQUAL(
tx.quote(nullptr), "NULL", "Null pointer did not come out as SQL 'null'.");
PQXX_CHECK_EQUAL(
tx.quote(std::nullopt), "NULL",
"std::nullopt did not come out as SQL 'null'.");
PQXX_CHECK_EQUAL(
tx.quote(std::monostate{}), "NULL",
"std::monostate did not come out as SQL 'null'.");
}
void test_string_view_conversion()
{
using traits = pqxx::string_traits<std::string_view>;
PQXX_CHECK_EQUAL(
pqxx::to_string("view here"sv), "view here"s,
"Bad conversion from string_view.");
char buf[200];
char *end{traits::into_buf(std::begin(buf), std::end(buf), "more view"sv)};
PQXX_CHECK(
std::begin(buf) < end and end < std::end(buf),
"string_view into_buf did not stay within its buffer.");
assert(end > std::begin(buf));
PQXX_CHECK(
*(end - 1) == '\0', "string_view into_buf did not zero-terminate.");
PQXX_CHECK_EQUAL(
(std::string{buf, static_cast<std::size_t>(end - std::begin(buf) - 1)}),
"more view"s, "string_view into_buf wrote wrong data.");
PQXX_CHECK(*(end - 2) == 'w', "string_view into_buf is in the wrong place.");
std::string_view org{"another!"sv};
pqxx::zview out{traits::to_buf(std::begin(buf), std::end(buf), org)};
PQXX_CHECK_EQUAL(
std::string{out}, "another!"s, "string_view to_buf returned wrong data.");
PQXX_CHECK(
std::data(out) != std::data(org),
"string_view to_buf returned original view, which may not be terminated.");
}
PQXX_REGISTER_TEST(test_string_conversion);
PQXX_REGISTER_TEST(test_convert_variant_to_string);
PQXX_REGISTER_TEST(test_integer_conversion);
PQXX_REGISTER_TEST(test_convert_null);
PQXX_REGISTER_TEST(test_string_view_conversion);
} // namespace
|