| 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 | |