1 | #include "catch.hpp" |
2 | #include "duckdb/common/operator/cast_operators.hpp" |
3 | #include "duckdb/common/string_util.hpp" |
4 | #include "duckdb/common/limits.hpp" |
5 | #include "duckdb/common/types.hpp" |
6 | #include "duckdb/common/types/vector.hpp" |
7 | #include <vector> |
8 | |
9 | using namespace duckdb; |
10 | using namespace std; |
11 | |
12 | template <class SRC, class DST> static void TestNumericCast(vector<SRC> &working_values, vector<SRC> &broken_values) { |
13 | DST result; |
14 | for (auto value : working_values) { |
15 | REQUIRE_NOTHROW(Cast::Operation<SRC, DST>(value) == (DST)value); |
16 | REQUIRE(TryCast::Operation<SRC, DST>(value, result)); |
17 | REQUIRE(result == (DST)value); |
18 | } |
19 | for (auto value : broken_values) { |
20 | REQUIRE_THROWS(Cast::Operation<SRC, DST>(value)); |
21 | REQUIRE(!TryCast::Operation<SRC, DST>(value, result)); |
22 | } |
23 | } |
24 | |
25 | template <class DST> |
26 | static void TestStringCast(vector<string> &working_values, vector<DST> &expected_values, |
27 | vector<string> &broken_values) { |
28 | DST result; |
29 | for (idx_t i = 0; i < working_values.size(); i++) { |
30 | auto &value = working_values[i]; |
31 | auto expected_value = expected_values[i]; |
32 | REQUIRE_NOTHROW(Cast::Operation<string_t, DST>(string_t(value)) == expected_value); |
33 | REQUIRE(TryCast::Operation<string_t, DST>(string_t(value), result)); |
34 | REQUIRE(result == expected_value); |
35 | |
36 | StringUtil::Trim(value); |
37 | vector<string> splits; |
38 | splits = StringUtil::Split(value, 'e'); |
39 | if (splits.size() > 1) { |
40 | continue; |
41 | } |
42 | splits = StringUtil::Split(value, '.'); |
43 | REQUIRE(Cast::Operation<DST, string>(result) == splits[0]); |
44 | } |
45 | for (auto &value : broken_values) { |
46 | REQUIRE_THROWS(Cast::Operation<string_t, DST>(string_t(value))); |
47 | REQUIRE(!TryCast::Operation<string_t, DST>(string_t(value), result)); |
48 | } |
49 | } |
50 | |
51 | template <class T> static void TestExponent() { |
52 | T parse_result; |
53 | string str; |
54 | double value = 1; |
55 | T expected_value = 1; |
56 | for (idx_t exponent = 0; exponent < 100; exponent++) { |
57 | if (value < MaximumValue<T>()) { |
58 | // expect success |
59 | str = "1e" + to_string(exponent); |
60 | REQUIRE(TryCast::Operation<string_t, T>(string_t(str), parse_result)); |
61 | REQUIRE(parse_result == expected_value); |
62 | str = "-1e" + to_string(exponent); |
63 | REQUIRE(TryCast::Operation<string_t, T>(string_t(str), parse_result)); |
64 | REQUIRE(parse_result == -expected_value); |
65 | value *= 10; |
66 | expected_value *= 10; |
67 | } else { |
68 | // expect failure |
69 | str = "1e" + to_string(exponent); |
70 | REQUIRE(!TryCast::Operation<string_t, T>(string_t(str), parse_result)); |
71 | str = "-1e" + to_string(exponent); |
72 | REQUIRE(!TryCast::Operation<string_t, T>(string_t(str), parse_result)); |
73 | } |
74 | } |
75 | } |
76 | |
77 | TEST_CASE("Test casting to boolean" , "[cast]" ) { |
78 | vector<string> working_values = {"true" , "false" , "TRUE" , "FALSE" , "T" , "F" }; |
79 | vector<bool> expected_values = {true, false, true, false, true, false}; |
80 | vector<string> broken_values = {"1" , "blabla" , "" , "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }; |
81 | |
82 | bool result; |
83 | for (idx_t i = 0; i < working_values.size(); i++) { |
84 | auto &value = working_values[i]; |
85 | auto expected_value = expected_values[i]; |
86 | REQUIRE_NOTHROW(Cast::Operation<string_t, bool>(value) == expected_value); |
87 | REQUIRE(TryCast::Operation<string_t, bool>(value, result)); |
88 | REQUIRE(result == expected_value); |
89 | } |
90 | for (auto &value : broken_values) { |
91 | REQUIRE_THROWS(Cast::Operation<string_t, bool>(value)); |
92 | REQUIRE(!TryCast::Operation<string_t, bool>(value, result)); |
93 | } |
94 | } |
95 | |
96 | TEST_CASE("Test casting to int8_t" , "[cast]" ) { |
97 | // int16_t -> int8_t |
98 | vector<int16_t> working_values_int16 = {10, -10, 127, -127}; |
99 | vector<int16_t> broken_values_int16 = {128, -128, 1000, -1000}; |
100 | TestNumericCast<int16_t, int8_t>(working_values_int16, broken_values_int16); |
101 | // int32_t -> int8_t |
102 | vector<int32_t> working_values_int32 = {10, -10, 127, -127}; |
103 | vector<int32_t> broken_values_int32 = {128, -128, 1000000, -1000000}; |
104 | TestNumericCast<int32_t, int8_t>(working_values_int32, broken_values_int32); |
105 | // int64_t -> int8_t |
106 | vector<int64_t> working_values_int64 = {10, -10, 127, -127}; |
107 | vector<int64_t> broken_values_int64 = {128, -128, 10000000000, -10000000000}; |
108 | TestNumericCast<int64_t, int8_t>(working_values_int64, broken_values_int64); |
109 | // float -> int8_t |
110 | vector<float> working_values_float = {10, -10, 127, -127, 1.3f, -2.7f}; |
111 | vector<float> broken_values_float = {128, -128, 10000000000, -10000000000, 1e30f, -1e30f}; |
112 | TestNumericCast<float, int8_t>(working_values_float, broken_values_float); |
113 | // double -> int8_t |
114 | vector<double> working_values_double = {10, -10, 127, -127, 1.3, -2.7}; |
115 | vector<double> broken_values_double = {128, -128, 10000000000, -10000000000, 1e100, -1e100}; |
116 | TestNumericCast<double, int8_t>(working_values_double, broken_values_double); |
117 | // string -> int8_t |
118 | vector<string> working_values_str = {"10" , "-10" , "127" , "-127" , "1.3" , "1e2" , "2e1" , |
119 | "2e0" , "20e-1" , "1." , " 3" , " 3 " , "\t3 \t \n" }; |
120 | vector<int8_t> expected_values_str = {10, -10, 127, -127, 1, 100, 20, 2, 2, 1, 3, 3, 3}; |
121 | vector<string> broken_values_str = { |
122 | "128" , "-128" , "10000000000000000000000000000000000000000000000000000000000000" , |
123 | "aaaa" , "19A" , "" , |
124 | "1e3" , "1e" , "1e-" , |
125 | "1e100" , "1e100000000" , "1000e-1" , |
126 | " 3 2" }; |
127 | TestStringCast<int8_t>(working_values_str, expected_values_str, broken_values_str); |
128 | TestExponent<int8_t>(); |
129 | } |
130 | |
131 | TEST_CASE("Test casting to int16_t" , "[cast]" ) { |
132 | // int32_t -> int16_t |
133 | vector<int32_t> working_values_int32 = {10, -10, 127, -127, 32767, -32767}; |
134 | vector<int32_t> broken_values_int32 = {32768, -32768, 1000000, -1000000}; |
135 | TestNumericCast<int32_t, int16_t>(working_values_int32, broken_values_int32); |
136 | // int64_t -> int16_t |
137 | vector<int64_t> working_values_int64 = {10, -10, 127, -127, 32767, -32767}; |
138 | vector<int64_t> broken_values_int64 = {32768, -32768, 10000000000, -10000000000}; |
139 | TestNumericCast<int64_t, int16_t>(working_values_int64, broken_values_int64); |
140 | // float -> int16_t |
141 | vector<float> working_values_float = {10.0f, -10.0f, 32767.0f, -32767.0f, 1.3f, -2.7f}; |
142 | vector<float> broken_values_float = {32768.0f, -32768.0f, 10000000000.0f, -10000000000.0f, 1e30f, -1e30f}; |
143 | TestNumericCast<float, int16_t>(working_values_float, broken_values_float); |
144 | // double -> int16_t |
145 | vector<double> working_values_double = {10, -10, 32767, -32767, 1.3, -2.7}; |
146 | vector<double> broken_values_double = {32768, -32768, 10000000000, -10000000000, 1e100, -1e100}; |
147 | TestNumericCast<double, int16_t>(working_values_double, broken_values_double); |
148 | // string -> int16_t |
149 | vector<string> working_values_str = {"10" , "-10" , "32767" , "-32767" , "1.3" , "3e4" , "250e2" }; |
150 | vector<int16_t> expected_values_str = {10, -10, 32767, -32767, 1, 30000, 25000}; |
151 | vector<string> broken_values_str = { |
152 | "32768" , "-32768" , "10000000000000000000000000000000000000000000000000000000000000" , |
153 | "aaaa" , "19A" , "" , |
154 | "1.A" , "1e" , "1e-" , |
155 | "1e100" , "1e100000000" }; |
156 | TestStringCast<int16_t>(working_values_str, expected_values_str, broken_values_str); |
157 | TestExponent<int16_t>(); |
158 | } |
159 | |
160 | TEST_CASE("Test casting to int32_t" , "[cast]" ) { |
161 | // int64_t -> int32_t |
162 | vector<int64_t> working_values_int64 = {10, -10, 127, -127, 32767, -32767, 2147483647, -2147483647}; |
163 | vector<int64_t> broken_values_int64 = {2147483648LL, -2147483648LL, 10000000000LL, -10000000000LL}; |
164 | TestNumericCast<int64_t, int32_t>(working_values_int64, broken_values_int64); |
165 | // float -> int32_t |
166 | vector<float> working_values_float = {10.0f, -10.0f, 2000000000.0f, -2000000000.0f, 1.3f, -2.7f}; |
167 | vector<float> broken_values_float = {3000000000.0f, -3000000000.0f, 10000000000.0f, -10000000000.0f, 1e30f, -1e30f}; |
168 | TestNumericCast<float, int32_t>(working_values_float, broken_values_float); |
169 | // double -> int32_t |
170 | vector<double> working_values_double = {10, -10, 32767.0, -32767.0, 1.3, -2.7, 2147483647.0, -2147483647.0}; |
171 | vector<double> broken_values_double = {2147483648.0, -2147483648.0, 10000000000.0, -10000000000.0, 1e100, -1e100}; |
172 | TestNumericCast<double, int32_t>(working_values_double, broken_values_double); |
173 | // string -> int32_t |
174 | vector<string> working_values_str = {"10" , "-10" , "2147483647" , "-2147483647" , "1.3" , "-1.3" , "1e6" }; |
175 | vector<int32_t> expected_values_str = {10, -10, 2147483647, -2147483647, 1, -1, 1000000}; |
176 | vector<string> broken_values_str = { |
177 | "2147483648" , "-2147483648" , "10000000000000000000000000000000000000000000000000000000000000" , |
178 | "aaaa" , "19A" , "" , |
179 | "1.A" , "1e1e1e1" }; |
180 | TestStringCast<int32_t>(working_values_str, expected_values_str, broken_values_str); |
181 | TestExponent<int32_t>(); |
182 | } |
183 | |
184 | TEST_CASE("Test casting to int64_t" , "[cast]" ) { |
185 | // float -> int64_t |
186 | vector<float> working_values_float = {10.0f, |
187 | -10.0f, |
188 | 32767.0f, |
189 | -32767.0f, |
190 | 1.3f, |
191 | -2.7f, |
192 | 2000000000.0f, |
193 | -2000000000.0f, |
194 | 4000000000000000000.0f, |
195 | -4000000000000000000.0f}; |
196 | vector<float> broken_values_float = {20000000000000000000.0f, -20000000000000000000.0f, 1e30f, -1e30f}; |
197 | TestNumericCast<float, int64_t>(working_values_float, broken_values_float); |
198 | // double -> int64_t |
199 | vector<double> working_values_double = { |
200 | 10, -10, 32767, -32767, 1.3, -2.7, 2147483647, -2147483647.0, 4611686018427387904.0, -4611686018427387904.0}; |
201 | vector<double> broken_values_double = {18446744073709551616.0, -18446744073709551616.0, 1e100, -1e100}; |
202 | TestNumericCast<double, int64_t>(working_values_double, broken_values_double); |
203 | // string -> int64_t |
204 | vector<string> working_values_str = { |
205 | "10" , "-10" , "9223372036854775807" , "-9223372036854775807" , "1.3" , "-9223372036854775807.1293813" , |
206 | "1e18" , "1." }; |
207 | vector<int64_t> expected_values_str = { |
208 | 10, -10, 9223372036854775807LL, -9223372036854775807LL, 1, -9223372036854775807LL, 1000000000000000000LL, 1}; |
209 | vector<string> broken_values_str = {"9223372036854775808" , |
210 | "-9223372036854775808" , |
211 | "10000000000000000000000000000000000000000000000000000000000000" , |
212 | "aaaa" , |
213 | "19A" , |
214 | "" , |
215 | "1.A" , |
216 | "1.2382398723A" }; |
217 | TestStringCast<int64_t>(working_values_str, expected_values_str, broken_values_str); |
218 | TestExponent<int64_t>(); |
219 | } |
220 | |
221 | template <class DST> |
222 | static void TestStringCastDouble(vector<string> &working_values, vector<DST> &expected_values, |
223 | vector<string> &broken_values) { |
224 | DST result; |
225 | for (idx_t i = 0; i < working_values.size(); i++) { |
226 | auto &value = working_values[i]; |
227 | auto expected_value = expected_values[i]; |
228 | REQUIRE_NOTHROW(Cast::Operation<string_t, DST>(string_t(value)) == expected_value); |
229 | REQUIRE(TryCast::Operation<string_t, DST>(string_t(value), result)); |
230 | REQUIRE(ApproxEqual(result, expected_value)); |
231 | |
232 | auto to_str_and_back = Cast::Operation<string_t, DST>(string_t(Cast::Operation<DST, string>(expected_value))); |
233 | REQUIRE(ApproxEqual(to_str_and_back, expected_value)); |
234 | } |
235 | for (auto &value : broken_values) { |
236 | REQUIRE_THROWS(Cast::Operation<string_t, DST>(string_t(value))); |
237 | REQUIRE(!TryCast::Operation<string_t, DST>(string_t(value), result)); |
238 | } |
239 | } |
240 | |
241 | TEST_CASE("Test casting to float" , "[cast]" ) { |
242 | // string -> float |
243 | vector<string> working_values = {"1.3" , |
244 | "1.34514" , |
245 | "1e10" , |
246 | "1e-2" , |
247 | "-1e-1" , |
248 | "1.2e12.3" , |
249 | "1.1781237378938173987123987123981723981723981723987123" , |
250 | "1.123456789" , |
251 | "1." }; |
252 | vector<float> expected_values = { |
253 | 1.3f, 1.34514f, 1e10f, 1e-2f, -1e-1f, 1.2e12f, 1.1781237378938173987123987123981723981723981723987123f, |
254 | 1.123456789f, 1.0f}; |
255 | vector<string> broken_values = { |
256 | "-" , "" , "aaa" , |
257 | "12aaa" , "1e10e10" , "1e" , |
258 | "1e-" , "1e10a" , "1.1781237378938173987123987123981723981723981723934834583490587123w" , |
259 | "1.2.3" }; |
260 | TestStringCastDouble<float>(working_values, expected_values, broken_values); |
261 | } |
262 | |
263 | TEST_CASE("Test casting to double" , "[cast]" ) { |
264 | // string -> double |
265 | vector<string> working_values = {"1.3" , |
266 | "1.34514" , |
267 | "1e10" , |
268 | "1e-2" , |
269 | "-1e-1" , |
270 | "1.2e12.3" , |
271 | "1.1781237378938173987123987123981723981723981723987123" , |
272 | "1.123456789" , |
273 | "1." , |
274 | "-1.2" , |
275 | "-1.2e1" , |
276 | " 1.2 " , |
277 | " 1.2e2 " , |
278 | " \t 1.2e2 \t" , |
279 | "1.2e 2" }; |
280 | vector<double> expected_values = { |
281 | 1.3, 1.34514, 1e10, 1e-2, -1e-1, 1.2e12, 1.1781237378938173987123987123981723981723981723987123, |
282 | 1.123456789, 1.0, -1.2, -12, 1.2, 120, 120, |
283 | 120}; |
284 | vector<string> broken_values = { |
285 | "-" , "" , "aaa" , |
286 | "12aaa" , "1e10e10" , "1e" , |
287 | "1e-" , "1e10a" , "1.1781237378938173987123987123981723981723981723934834583490587123w" , |
288 | "1.2.3" , "1.222." , "1.." , |
289 | "1 . 2" , "1. 2" , "1.2 e20" }; |
290 | TestStringCastDouble<double>(working_values, expected_values, broken_values); |
291 | } |
292 | |