1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#include <locale>
19#include <stdexcept>
20#include <string>
21
22#include <gtest/gtest.h>
23
24#include "arrow/type.h"
25#include "arrow/util/parsing.h"
26
27namespace arrow {
28
29using internal::StringConverter;
30
31template <typename ConverterType, typename C_TYPE>
32void AssertConversion(ConverterType& converter, const std::string& s, C_TYPE expected) {
33 typename ConverterType::value_type out;
34 ASSERT_TRUE(converter(s.data(), s.length(), &out))
35 << "Conversion failed for '" << s << "' (expected to return " << expected << ")";
36 ASSERT_EQ(out, expected) << "Conversion failed for '" << s << "'";
37}
38
39template <typename ConverterType>
40void AssertConversionFails(ConverterType& converter, const std::string& s) {
41 typename ConverterType::value_type out;
42 ASSERT_FALSE(converter(s.data(), s.length(), &out))
43 << "Conversion should have failed for '" << s << "' (returned " << out << ")";
44}
45
46class LocaleGuard {
47 public:
48 explicit LocaleGuard(const char* new_locale) : global_locale_(std::locale()) {
49 try {
50 std::locale::global(std::locale(new_locale));
51 } catch (std::runtime_error&) {
52 // Locale unavailable, ignore
53 }
54 }
55
56 ~LocaleGuard() { std::locale::global(global_locale_); }
57
58 protected:
59 std::locale global_locale_;
60};
61
62TEST(StringConversion, ToBoolean) {
63 StringConverter<BooleanType> converter;
64
65 AssertConversion(converter, "true", true);
66 AssertConversion(converter, "tRuE", true);
67 AssertConversion(converter, "FAlse", false);
68 AssertConversion(converter, "false", false);
69 AssertConversion(converter, "1", true);
70 AssertConversion(converter, "0", false);
71
72 AssertConversionFails(converter, "");
73}
74
75TEST(StringConversion, ToFloat) {
76 StringConverter<FloatType> converter;
77
78 AssertConversion(converter, "1.5", 1.5f);
79 AssertConversion(converter, "0", 0.0f);
80 // XXX ASSERT_EQ doesn't distinguish signed zeros
81 AssertConversion(converter, "-0.0", -0.0f);
82 AssertConversion(converter, "-1e20", -1e20f);
83
84 AssertConversionFails(converter, "");
85 AssertConversionFails(converter, "e");
86}
87
88TEST(StringConversion, ToDouble) {
89 StringConverter<DoubleType> converter;
90
91 AssertConversion(converter, "1.5", 1.5);
92 AssertConversion(converter, "0", 0);
93 // XXX ASSERT_EQ doesn't distinguish signed zeros
94 AssertConversion(converter, "-0.0", -0.0);
95 AssertConversion(converter, "-1e100", -1e100);
96
97 AssertConversionFails(converter, "");
98 AssertConversionFails(converter, "e");
99}
100
101TEST(StringConversion, ToFloatLocale) {
102 // French locale uses the comma as decimal point
103 LocaleGuard locale_guard("fr_FR.UTF-8");
104
105 StringConverter<FloatType> converter;
106 AssertConversion(converter, "1.5", 1.5f);
107}
108
109TEST(StringConversion, ToDoubleLocale) {
110 // French locale uses the comma as decimal point
111 LocaleGuard locale_guard("fr_FR.UTF-8");
112
113 StringConverter<DoubleType> converter;
114 AssertConversion(converter, "1.5", 1.5f);
115}
116
117TEST(StringConversion, ToInt8) {
118 StringConverter<Int8Type> converter;
119
120 AssertConversion(converter, "0", 0);
121 AssertConversion(converter, "127", 127);
122 AssertConversion(converter, "0127", 127);
123 AssertConversion(converter, "-128", -128);
124 AssertConversion(converter, "-00128", -128);
125
126 // Non-representable values
127 AssertConversionFails(converter, "128");
128 AssertConversionFails(converter, "-129");
129
130 AssertConversionFails(converter, "");
131 AssertConversionFails(converter, "-");
132 AssertConversionFails(converter, "0.0");
133 AssertConversionFails(converter, "e");
134}
135
136TEST(StringConversion, ToUInt8) {
137 StringConverter<UInt8Type> converter;
138
139 AssertConversion(converter, "0", 0);
140 AssertConversion(converter, "26", 26);
141 AssertConversion(converter, "255", 255);
142 AssertConversion(converter, "0255", 255);
143
144 // Non-representable values
145 AssertConversionFails(converter, "-1");
146 AssertConversionFails(converter, "256");
147 AssertConversionFails(converter, "260");
148 AssertConversionFails(converter, "1234");
149
150 AssertConversionFails(converter, "");
151 AssertConversionFails(converter, "-");
152 AssertConversionFails(converter, "0.0");
153 AssertConversionFails(converter, "e");
154}
155
156TEST(StringConversion, ToInt16) {
157 StringConverter<Int16Type> converter;
158
159 AssertConversion(converter, "0", 0);
160 AssertConversion(converter, "32767", 32767);
161 AssertConversion(converter, "032767", 32767);
162 AssertConversion(converter, "-32768", -32768);
163 AssertConversion(converter, "-0032768", -32768);
164
165 // Non-representable values
166 AssertConversionFails(converter, "32768");
167 AssertConversionFails(converter, "-32769");
168
169 AssertConversionFails(converter, "");
170 AssertConversionFails(converter, "-");
171 AssertConversionFails(converter, "0.0");
172 AssertConversionFails(converter, "e");
173}
174
175TEST(StringConversion, ToUInt16) {
176 StringConverter<UInt16Type> converter;
177
178 AssertConversion(converter, "0", 0);
179 AssertConversion(converter, "6660", 6660);
180 AssertConversion(converter, "65535", 65535);
181 AssertConversion(converter, "065535", 65535);
182
183 // Non-representable values
184 AssertConversionFails(converter, "-1");
185 AssertConversionFails(converter, "65536");
186 AssertConversionFails(converter, "123456");
187
188 AssertConversionFails(converter, "");
189 AssertConversionFails(converter, "-");
190 AssertConversionFails(converter, "0.0");
191 AssertConversionFails(converter, "e");
192}
193
194TEST(StringConversion, ToInt32) {
195 StringConverter<Int32Type> converter;
196
197 AssertConversion(converter, "0", 0);
198 AssertConversion(converter, "2147483647", 2147483647);
199 AssertConversion(converter, "02147483647", 2147483647);
200 AssertConversion(converter, "-2147483648", -2147483648LL);
201 AssertConversion(converter, "-002147483648", -2147483648LL);
202
203 // Non-representable values
204 AssertConversionFails(converter, "2147483648");
205 AssertConversionFails(converter, "-2147483649");
206
207 AssertConversionFails(converter, "");
208 AssertConversionFails(converter, "-");
209 AssertConversionFails(converter, "0.0");
210 AssertConversionFails(converter, "e");
211}
212
213TEST(StringConversion, ToUInt32) {
214 StringConverter<UInt32Type> converter;
215
216 AssertConversion(converter, "0", 0);
217 AssertConversion(converter, "432198765", 432198765UL);
218 AssertConversion(converter, "4294967295", 4294967295UL);
219 AssertConversion(converter, "04294967295", 4294967295UL);
220
221 // Non-representable values
222 AssertConversionFails(converter, "-1");
223 AssertConversionFails(converter, "4294967296");
224 AssertConversionFails(converter, "12345678901");
225
226 AssertConversionFails(converter, "");
227 AssertConversionFails(converter, "-");
228 AssertConversionFails(converter, "0.0");
229 AssertConversionFails(converter, "e");
230}
231
232TEST(StringConversion, ToInt64) {
233 StringConverter<Int64Type> converter;
234
235 AssertConversion(converter, "0", 0);
236 AssertConversion(converter, "9223372036854775807", 9223372036854775807LL);
237 AssertConversion(converter, "09223372036854775807", 9223372036854775807LL);
238 AssertConversion(converter, "-9223372036854775808", -9223372036854775807LL - 1);
239 AssertConversion(converter, "-009223372036854775808", -9223372036854775807LL - 1);
240
241 // Non-representable values
242 AssertConversionFails(converter, "9223372036854775808");
243 AssertConversionFails(converter, "-9223372036854775809");
244
245 AssertConversionFails(converter, "");
246 AssertConversionFails(converter, "-");
247 AssertConversionFails(converter, "0.0");
248 AssertConversionFails(converter, "e");
249}
250
251TEST(StringConversion, ToUInt64) {
252 StringConverter<UInt64Type> converter;
253
254 AssertConversion(converter, "0", 0);
255 AssertConversion(converter, "18446744073709551615", 18446744073709551615ULL);
256
257 // Non-representable values
258 AssertConversionFails(converter, "-1");
259 AssertConversionFails(converter, "18446744073709551616");
260
261 AssertConversionFails(converter, "");
262 AssertConversionFails(converter, "-");
263 AssertConversionFails(converter, "0.0");
264 AssertConversionFails(converter, "e");
265}
266
267TEST(StringConversion, ToTimestamp1) {
268 {
269 StringConverter<TimestampType> converter(timestamp(TimeUnit::SECOND));
270
271 AssertConversion(converter, "1970-01-01", 0);
272 AssertConversion(converter, "1989-07-14", 616377600);
273 AssertConversion(converter, "2000-02-29", 951782400);
274 AssertConversion(converter, "3989-07-14", 63730281600LL);
275 AssertConversion(converter, "1900-02-28", -2203977600LL);
276
277 AssertConversionFails(converter, "");
278 AssertConversionFails(converter, "1970");
279 AssertConversionFails(converter, "19700101");
280 AssertConversionFails(converter, "1970/01/01");
281 AssertConversionFails(converter, "1970-01-01 ");
282 AssertConversionFails(converter, "1970-01-01Z");
283
284 // Invalid dates
285 AssertConversionFails(converter, "1970-00-01");
286 AssertConversionFails(converter, "1970-13-01");
287 AssertConversionFails(converter, "1970-01-32");
288 AssertConversionFails(converter, "1970-02-29");
289 AssertConversionFails(converter, "2100-02-29");
290 }
291 {
292 StringConverter<TimestampType> converter(timestamp(TimeUnit::MILLI));
293
294 AssertConversion(converter, "1970-01-01", 0);
295 AssertConversion(converter, "1989-07-14", 616377600000LL);
296 AssertConversion(converter, "3989-07-14", 63730281600000LL);
297 AssertConversion(converter, "1900-02-28", -2203977600000LL);
298 }
299 {
300 StringConverter<TimestampType> converter(timestamp(TimeUnit::MICRO));
301
302 AssertConversion(converter, "1970-01-01", 0);
303 AssertConversion(converter, "1989-07-14", 616377600000000LL);
304 AssertConversion(converter, "3989-07-14", 63730281600000000LL);
305 AssertConversion(converter, "1900-02-28", -2203977600000000LL);
306 }
307 {
308 StringConverter<TimestampType> converter(timestamp(TimeUnit::NANO));
309
310 AssertConversion(converter, "1970-01-01", 0);
311 AssertConversion(converter, "1989-07-14", 616377600000000000LL);
312 AssertConversion(converter, "2018-11-13", 1542067200000000000LL);
313 AssertConversion(converter, "1900-02-28", -2203977600000000000LL);
314 }
315}
316
317TEST(StringConversion, ToTimestamp2) {
318 {
319 StringConverter<TimestampType> converter(timestamp(TimeUnit::SECOND));
320
321 AssertConversion(converter, "1970-01-01 00:00:00", 0);
322 AssertConversion(converter, "2018-11-13 17:11:10", 1542129070);
323 AssertConversion(converter, "2018-11-13T17:11:10", 1542129070);
324 AssertConversion(converter, "2018-11-13 17:11:10Z", 1542129070);
325 AssertConversion(converter, "2018-11-13T17:11:10Z", 1542129070);
326 AssertConversion(converter, "1900-02-28 12:34:56", -2203932304LL);
327
328 // Invalid dates
329 AssertConversionFails(converter, "1970-02-29 00:00:00");
330 AssertConversionFails(converter, "2100-02-29 00:00:00");
331 // Invalid times
332 AssertConversionFails(converter, "1970-01-01 24:00:00");
333 AssertConversionFails(converter, "1970-01-01 00:60:00");
334 AssertConversionFails(converter, "1970-01-01 00:00:60");
335 }
336 {
337 StringConverter<TimestampType> converter(timestamp(TimeUnit::MILLI));
338
339 AssertConversion(converter, "2018-11-13 17:11:10", 1542129070000LL);
340 AssertConversion(converter, "2018-11-13T17:11:10Z", 1542129070000LL);
341 AssertConversion(converter, "3989-07-14T11:22:33Z", 63730322553000LL);
342 AssertConversion(converter, "1900-02-28 12:34:56", -2203932304000LL);
343 }
344 {
345 StringConverter<TimestampType> converter(timestamp(TimeUnit::MICRO));
346
347 AssertConversion(converter, "2018-11-13 17:11:10", 1542129070000000LL);
348 AssertConversion(converter, "2018-11-13T17:11:10Z", 1542129070000000LL);
349 AssertConversion(converter, "3989-07-14T11:22:33Z", 63730322553000000LL);
350 AssertConversion(converter, "1900-02-28 12:34:56", -2203932304000000LL);
351 }
352 {
353 StringConverter<TimestampType> converter(timestamp(TimeUnit::NANO));
354
355 AssertConversion(converter, "2018-11-13 17:11:10", 1542129070000000000LL);
356 AssertConversion(converter, "2018-11-13T17:11:10Z", 1542129070000000000LL);
357 AssertConversion(converter, "1900-02-28 12:34:56", -2203932304000000000LL);
358 }
359}
360
361} // namespace arrow
362