msvcrt: Fix strtof() error reporting for values out of float range.
[wine.git] / dlls / ucrtbase / tests / string.c
blob734dd68db76f6cc0b3eec7455e27d04bd43b8b3e
1 /*
2 * Copyright 2015 Martin Storsjo
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <wchar.h>
23 #include <stdio.h>
24 #include <locale.h>
25 #include <mbctype.h>
26 #include <mbstring.h>
28 #include <windef.h>
29 #include <winbase.h>
30 #include "wine/test.h"
32 #include <math.h>
34 #define DEFINE_EXPECT(func) \
35 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
37 #define SET_EXPECT(func) \
38 expect_ ## func = TRUE
40 #define CHECK_EXPECT2(func) \
41 do { \
42 ok(expect_ ##func, "unexpected call " #func "\n"); \
43 called_ ## func = TRUE; \
44 }while(0)
46 #define CHECK_EXPECT(func) \
47 do { \
48 CHECK_EXPECT2(func); \
49 expect_ ## func = FALSE; \
50 }while(0)
52 #define CHECK_CALLED(func) \
53 do { \
54 ok(called_ ## func, "expected " #func "\n"); \
55 expect_ ## func = called_ ## func = FALSE; \
56 }while(0)
58 DEFINE_EXPECT(invalid_parameter_handler);
60 static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
61 const wchar_t *function, const wchar_t *file,
62 unsigned line, uintptr_t arg)
64 CHECK_EXPECT(invalid_parameter_handler);
65 ok(expression == NULL, "expression is not NULL\n");
66 ok(function == NULL, "function is not NULL\n");
67 ok(file == NULL, "file is not NULL\n");
68 ok(line == 0, "line = %u\n", line);
69 ok(arg == 0, "arg = %lx\n", (UINT_PTR)arg);
72 _ACRTIMP int __cdecl _o_tolower(int);
73 _ACRTIMP int __cdecl _o_toupper(int);
75 static BOOL local_isnan(double d)
77 return d != d;
80 #define test_strtod_str_errno(string, value, length, err) _test_strtod_str(__LINE__, string, value, length, err)
81 #define test_strtod_str(string, value, length) _test_strtod_str(__LINE__, string, value, length, 0)
82 static void _test_strtod_str(int line, const char* string, double value, int length, int err)
84 char *end;
85 double d;
86 errno = 0xdeadbeef;
87 d = strtod(string, &end);
88 if(!err)
89 ok_(__FILE__, line)(errno == 0xdeadbeef, "errno = %d\n", errno);
90 else
91 ok_(__FILE__, line)(errno == err, "errno = %d\n", errno);
92 if (local_isnan(value))
93 ok_(__FILE__, line)(local_isnan(d), "d = %.16le (\"%s\")\n", d, string);
94 else
95 ok_(__FILE__, line)(d == value, "d = %.16le (\"%s\")\n", d, string);
96 ok_(__FILE__, line)(end == string + length, "incorrect end (%d, \"%s\")\n", (int)(end - string), string);
99 static void test_strtod(void)
101 test_strtod_str("infinity", INFINITY, 8);
102 test_strtod_str("INFINITY", INFINITY, 8);
103 test_strtod_str("InFiNiTy", INFINITY, 8);
104 test_strtod_str("INF", INFINITY, 3);
105 test_strtod_str("-inf", -INFINITY, 4);
106 test_strtod_str("inf42", INFINITY, 3);
107 test_strtod_str("inffoo", INFINITY, 3);
108 test_strtod_str("infini", INFINITY, 3);
109 test_strtod_str("input", 0, 0);
110 test_strtod_str("-input", 0, 0);
111 test_strtod_str_errno("1.7976931348623159e+308", INFINITY, 23, ERANGE);
112 test_strtod_str_errno("-1.7976931348623159e+308", -INFINITY, 24, ERANGE);
114 test_strtod_str("NAN", NAN, 3);
115 test_strtod_str("nan", NAN, 3);
116 test_strtod_str("NaN", NAN, 3);
118 test_strtod_str("0x42", 66, 4);
119 test_strtod_str("0X42", 66, 4);
120 test_strtod_str("-0x42", -66, 5);
121 test_strtod_str("0x1p1", 2, 5);
122 test_strtod_str("0x1P1", 2, 5);
123 test_strtod_str("0x1p+1", 2, 6);
124 test_strtod_str("0x2p-1", 1, 6);
125 test_strtod_str("0xA", 10, 3);
126 test_strtod_str("0xa", 10, 3);
127 test_strtod_str("0xABCDEF", 11259375, 8);
128 test_strtod_str("0Xabcdef", 11259375, 8);
130 test_strtod_str("0x1.1", 1.0625, 5);
131 test_strtod_str("0x1.1p1", 2.125, 7);
132 test_strtod_str("0x1.A", 1.625, 5);
133 test_strtod_str("0x1p1a", 2, 5);
134 test_strtod_str("0xp3", 0, 1);
135 test_strtod_str("0x.", 0, 1);
136 test_strtod_str("0x.8", 0.5, 4);
137 test_strtod_str("0x.8p", 0.5, 4);
138 test_strtod_str("0x0p10000000000000000000000000", 0, 30);
139 test_strtod_str("0x1p-1026", 1.3906711615670009e-309, 9);
141 test_strtod_str("0x1ffffffffffffe.80000000000000000000", 9007199254740990.0, 37);
142 test_strtod_str("0x1ffffffffffffe.80000000000000000001", 9007199254740991.0, 37);
143 test_strtod_str("0x1fffffffffffff.80000000000000000000", 9007199254740992.0, 37);
144 test_strtod_str("0x1fffffffffffff.80000000000000000001", 9007199254740992.0, 37);
146 test_strtod_str("4.0621786324484881721115322e-53", 4.0621786324484881721115322e-53, 31);
147 test_strtod_str("1.8905590910042396899370942", 1.8905590910042396899370942, 27);
148 test_strtod_str("1.7976931348623158e+308", 1.7976931348623158e+308, 23);
149 test_strtod_str("2.2250738585072014e-308", 2.2250738585072014e-308, 23);
150 test_strtod_str("4.9406564584124654e-324", 4.9406564584124654e-324, 23);
151 test_strtod_str("2.48e-324", 4.9406564584124654e-324, 9);
152 test_strtod_str_errno("2.47e-324", 0, 9, ERANGE);
155 static void test_strtof(void)
157 static const struct {
158 const char *str;
159 int len;
160 float ret;
161 int err;
162 } tests[] = {
163 { "12.1", 4, 12.1f },
164 { "-13.721", 7, -13.721f },
165 { "1.e40", 5, INFINITY, ERANGE },
166 { "-1.e40", 6, -INFINITY, ERANGE },
167 { "0.0", 3, 0.0f },
168 { "-0.0", 4, 0.0f },
169 { "1.4e-45", 7, 1.4e-45f },
170 { "-1.4e-45", 8, -1.4e-45f },
171 { "1.e-60", 6, 0, ERANGE },
172 { "-1.e-60", 7, 0, ERANGE },
175 char *end;
176 float f;
177 int i;
179 for (i=0; i<ARRAY_SIZE(tests); i++)
181 errno = 0xdeadbeef;
182 f = strtof(tests[i].str, &end);
183 ok(f == tests[i].ret, "%d) f = %.16e\n", i, f);
184 ok(end == tests[i].str + tests[i].len, "%d) len = %d\n",
185 i, (int)(end - tests[i].str));
186 ok(errno == tests[i].err || (!tests[i].err && errno == 0xdeadbeef),
187 "%d) errno = %d\n", i, errno);
191 static void test__memicmp(void)
193 static const char *s1 = "abc";
194 static const char *s2 = "aBd";
195 int ret;
197 ret = _memicmp(NULL, NULL, 0);
198 ok(!ret, "got %d\n", ret);
200 SET_EXPECT(invalid_parameter_handler);
201 errno = 0xdeadbeef;
202 ret = _memicmp(NULL, NULL, 1);
203 ok(ret == _NLSCMPERROR, "got %d\n", ret);
204 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
205 CHECK_CALLED(invalid_parameter_handler);
207 SET_EXPECT(invalid_parameter_handler);
208 errno = 0xdeadbeef;
209 ret = _memicmp(s1, NULL, 1);
210 ok(ret == _NLSCMPERROR, "got %d\n", ret);
211 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
212 CHECK_CALLED(invalid_parameter_handler);
214 SET_EXPECT(invalid_parameter_handler);
215 errno = 0xdeadbeef;
216 ret = _memicmp(NULL, s2, 1);
217 ok(ret == _NLSCMPERROR, "got %d\n", ret);
218 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
219 CHECK_CALLED(invalid_parameter_handler);
221 ret = _memicmp(s1, s2, 2);
222 ok(!ret, "got %d\n", ret);
224 ret = _memicmp(s1, s2, 3);
225 ok(ret == -1, "got %d\n", ret);
228 static void test__memicmp_l(void)
230 static const char *s1 = "abc";
231 static const char *s2 = "aBd";
232 int ret;
234 ret = _memicmp_l(NULL, NULL, 0, NULL);
235 ok(!ret, "got %d\n", ret);
237 SET_EXPECT(invalid_parameter_handler);
238 errno = 0xdeadbeef;
239 ret = _memicmp_l(NULL, NULL, 1, NULL);
240 ok(ret == _NLSCMPERROR, "got %d\n", ret);
241 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
242 CHECK_CALLED(invalid_parameter_handler);
244 SET_EXPECT(invalid_parameter_handler);
245 errno = 0xdeadbeef;
246 ret = _memicmp_l(s1, NULL, 1, NULL);
247 ok(ret == _NLSCMPERROR, "got %d\n", ret);
248 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
249 CHECK_CALLED(invalid_parameter_handler);
251 SET_EXPECT(invalid_parameter_handler);
252 errno = 0xdeadbeef;
253 ret = _memicmp_l(NULL, s2, 1, NULL);
254 ok(ret == _NLSCMPERROR, "got %d\n", ret);
255 ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
256 CHECK_CALLED(invalid_parameter_handler);
258 ret = _memicmp_l(s1, s2, 2, NULL);
259 ok(!ret, "got %d\n", ret);
261 ret = _memicmp_l(s1, s2, 3, NULL);
262 ok(ret == -1, "got %d\n", ret);
266 static void test___strncnt(void)
268 static const struct
270 const char *str;
271 size_t size;
272 size_t ret;
274 strncnt_tests[] =
276 { "a", 0, 0 },
277 { "a", 1, 1 },
278 { "a", 10, 1 },
279 { "abc", 1, 1 },
281 unsigned int i;
282 size_t ret;
284 for (i = 0; i < ARRAY_SIZE(strncnt_tests); ++i)
286 ret = __strncnt(strncnt_tests[i].str, strncnt_tests[i].size);
287 ok(ret == strncnt_tests[i].ret, "%u: unexpected return value %u.\n", i, (int)ret);
290 if (0) /* crashes */
292 ret = __strncnt(NULL, 0);
293 ret = __strncnt(NULL, 1);
297 static void test_C_locale(void)
299 int i, j;
300 wint_t ret, exp;
301 _locale_t locale;
302 static const char *locales[] = { NULL, "C" };
304 /* C locale only converts case for [a-zA-Z] */
305 setlocale(LC_ALL, "C");
306 for (i = 0; i <= 0xffff; i++)
308 ret = tolower(i);
309 if (i >= 'A' && i <= 'Z')
311 exp = i + 'a' - 'A';
312 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
314 else
315 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
317 ret = _tolower(i);
318 exp = i + 'a' - 'A';
319 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
321 ret = _o_tolower(i);
322 if (i >= 'A' && i <= 'Z')
324 exp = i + 'a' - 'A';
325 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
327 else
328 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
330 ret = towlower(i);
331 if (i >= 'A' && i <= 'Z')
333 exp = i + 'a' - 'A';
334 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
336 else
337 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
339 ret = toupper(i);
340 if (i >= 'a' && i <= 'z')
342 exp = i + 'A' - 'a';
343 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
345 else
346 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
348 ret = _toupper(i);
349 exp = i + 'A' - 'a';
350 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
352 ret = _o_toupper(i);
353 if (i >= 'a' && i <= 'z')
355 exp = i + 'A' - 'a';
356 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
358 else
359 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
361 ret = towupper(i);
362 if (i >= 'a' && i <= 'z')
364 exp = i + 'A' - 'a';
365 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
367 else
368 ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
371 for (i = 0; i < ARRAY_SIZE(locales); i++) {
372 locale = locales[i] ? _create_locale(LC_ALL, locales[i]) : NULL;
374 for (j = 0; j <= 0xffff; j++) {
375 ret = _towlower_l(j, locale);
376 if (j >= 'A' && j <= 'Z')
378 exp = j + 'a' - 'A';
379 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
381 else
382 ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
384 ret = _towupper_l(j, locale);
385 if (j >= 'a' && j <= 'z')
387 exp = j + 'A' - 'a';
388 ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
390 else
391 ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
394 _free_locale(locale);
398 static void test_mbsspn( void)
400 unsigned char str1[] = "cabernet";
401 unsigned char str2[] = "shiraz";
402 unsigned char set[] = "abc";
403 unsigned char empty[] = "";
404 unsigned char mbstr[] = " 2019\x94\x4e" "6\x8c\x8e" "29\x93\xfa";
405 unsigned char mbset1[] = "0123456789 \x94\x4e";
406 unsigned char mbset2[] = " \x94\x4e\x8c\x8e";
407 unsigned char mbset3[] = "\x8e";
408 int ret, cp = _getmbcp();
410 ret = _mbsspn(str1, set);
411 ok(ret == 3, "_mbsspn returns %d should be 3\n", ret);
412 ret = _mbsspn(str2, set);
413 ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
414 ret = _mbsspn(str1, empty);
415 ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
417 _setmbcp(932);
418 ret = _mbsspn(mbstr, mbset1);
419 ok(ret == 8, "_mbsspn returns %d should be 8\n", ret);
420 ret = _mbsspn(mbstr, mbset2);
421 ok(ret == 1, "_mbsspn returns %d should be 1\n", ret);
422 ret = _mbsspn(mbstr+8, mbset1);
423 ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
424 ret = _mbsspn(mbstr+8, mbset2);
425 ok(ret == 2, "_mbsspn returns %d should be 2\n", ret);
426 ret = _mbsspn(mbstr, mbset3);
427 ok(ret == 14, "_mbsspn returns %d should be 14\n", ret);
429 _setmbcp(cp);
432 static void test_wcstok(void)
434 static const wchar_t *input = L"two words";
435 wchar_t buffer[16];
436 wchar_t *token;
437 wchar_t *next;
439 next = NULL;
440 wcscpy(buffer, input);
441 token = wcstok(buffer, L" ", &next);
442 ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
443 ok(next == token + 4, "expected %p, got %p\n", token + 4, next);
444 token = wcstok(NULL, L" ", &next);
445 ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
446 ok(next == token + 5, "expected %p, got %p\n", token + 5, next);
447 token = wcstok(NULL, L" ", &next);
448 ok(!token, "expected NULL, got %p\n", token);
450 wcscpy(buffer, input);
451 token = wcstok(buffer, L" ", NULL);
452 ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
453 token = wcstok(NULL, L" ", NULL);
454 ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
455 token = wcstok(NULL, L" ", NULL);
456 ok(!token, "expected NULL, got %p\n", token);
458 next = NULL;
459 wcscpy(buffer, input);
460 token = wcstok(buffer, L"=", &next);
461 ok(!wcscmp(token, input), "expected \"%ls\", got \"%ls\"\n", input, token);
462 ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
463 token = wcstok(NULL, L"=", &next);
464 ok(!token, "expected NULL, got \"%ls\"\n", token);
465 ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
467 next = NULL;
468 wcscpy(buffer, L"");
469 token = wcstok(buffer, L"=", &next);
470 ok(token == NULL, "expected NULL, got \"%ls\"\n", token);
471 ok(next == buffer, "expected %p, got %p\n", buffer, next);
472 token = wcstok(NULL, L"=", &next);
473 ok(!token, "expected NULL, got \"%ls\"\n", token);
474 ok(next == buffer, "expected %p, got %p\n", buffer, next);
477 static void test__strnicmp(void)
479 static const char str1[] = "TEST";
480 static const char str2[] = "test";
481 int ret;
483 SET_EXPECT(invalid_parameter_handler);
484 errno = 0xdeadbeef;
485 ret = _strnicmp(str1, str2, -1);
486 todo_wine CHECK_CALLED(invalid_parameter_handler);
487 todo_wine ok(ret == _NLSCMPERROR, "got %d.\n", ret);
488 todo_wine ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
490 ret = _strnicmp(str1, str2, 0x7fffffff);
491 ok(!ret, "got %d.\n", ret);
494 static void test_SpecialCasing(void)
496 int i;
497 wint_t ret, exp;
498 _locale_t locale;
499 struct test {
500 const char *lang;
501 wint_t ch;
502 wint_t exp;
505 struct test ucases[] = {
506 {"English", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
507 {"English", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
509 {"Turkish", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
510 {"Turkish", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
512 struct test lcases[] = {
513 {"English", 'i', 'I'}, /* LATIN SMALL LETTER I */
514 {"English", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
516 {"Turkish", 'i', 'I'}, /* LATIN SMALL LETTER I */
517 {"Turkish", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
520 for (i = 0; i < ARRAY_SIZE(ucases); i++) {
521 if (!setlocale(LC_ALL, ucases[i].lang)) {
522 win_skip("skipping special case tests for %s\n", ucases[i].lang);
523 continue;
526 ret = towlower(ucases[i].ch);
527 exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
528 ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
531 for (i = 0; i < ARRAY_SIZE(lcases); i++) {
532 if (!setlocale(LC_ALL, lcases[i].lang)) {
533 win_skip("skipping special case tests for %s\n", lcases[i].lang);
534 continue;
537 ret = towupper(lcases[i].ch);
538 exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
539 ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
542 setlocale(LC_ALL, "C");
544 /* test _towlower_l creating locale */
545 for (i = 0; i < ARRAY_SIZE(ucases); i++) {
546 if (!(locale = _create_locale(LC_ALL, ucases[i].lang))) {
547 win_skip("locale %s not available. skipping\n", ucases[i].lang);
548 continue;
551 ret = _towlower_l(ucases[i].ch, locale);
552 exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
553 ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
555 _free_locale(locale);
558 /* test _towupper_l creating locale */
559 for (i = 0; i < ARRAY_SIZE(lcases); i++) {
560 if (!(locale = _create_locale(LC_ALL, lcases[i].lang))) {
561 win_skip("locale %s not available. skipping\n", lcases[i].lang);
562 continue;
565 ret = _towupper_l(lcases[i].ch, locale);
566 exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
567 ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
569 _free_locale(locale);
573 static void test__mbbtype_l(void)
575 int expected, ret;
576 unsigned int c;
578 _setmbcp(_MB_CP_LOCALE);
579 for (c = 0; c < 256; ++c)
581 expected = _mbbtype(c, 0);
582 ret = _mbbtype_l(c, 0, NULL);
583 ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
585 expected = _mbbtype(c, 1);
586 ret = _mbbtype_l(c, 1, NULL);
587 ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
591 START_TEST(string)
593 ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
594 "Invalid parameter handler was already set\n");
596 test_strtod();
597 test_strtof();
598 test__memicmp();
599 test__memicmp_l();
600 test___strncnt();
601 test_C_locale();
602 test_mbsspn();
603 test_wcstok();
604 test__strnicmp();
605 test_SpecialCasing();
606 test__mbbtype_l();