File: test_string_conversion.cxx

package info (click to toggle)
libpqxx 7.10.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,184 kB
  • sloc: cpp: 14,681; sh: 4,859; python: 801; makefile: 244
file content (214 lines) | stat: -rw-r--r-- 6,828 bytes parent folder | download
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