Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / virstringtest.c
1 /*
2  * Copyright (C) 2012-2014 Red Hat, Inc.
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  * Author: Daniel P. Berrange <berrange@redhat.com>
19  */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24
25 #include "testutils.h"
26 #include "intprops.h"
27 #include "verify.h"
28 #include "virerror.h"
29 #include "viralloc.h"
30 #include "virfile.h"
31 #include "virlog.h"
32 #include "virstring.h"
33
34 #define VIR_FROM_THIS VIR_FROM_NONE
35
36 VIR_LOG_INIT("tests.stringtest");
37
38 struct testSplitData {
39     const char *string;
40     const char *delim;
41     size_t max_tokens;
42     const char **tokens;
43 };
44
45
46 struct testJoinData {
47     const char *string;
48     const char *delim;
49     const char **tokens;
50 };
51
52 static int testSplit(const void *args)
53 {
54     const struct testSplitData *data = args;
55     char **got;
56     char **tmp1;
57     const char **tmp2;
58     int ret = -1;
59
60     if (!(got = virStringSplit(data->string, data->delim, data->max_tokens))) {
61         VIR_DEBUG("Got no tokens at all");
62         return -1;
63     }
64
65     tmp1 = got;
66     tmp2 = data->tokens;
67     while (*tmp1 && *tmp2) {
68         if (STRNEQ(*tmp1, *tmp2)) {
69             virFilePrintf(stderr, "Mismatch '%s' vs '%s'\n", *tmp1, *tmp2);
70             goto cleanup;
71         }
72         tmp1++;
73         tmp2++;
74     }
75     if (*tmp1) {
76         virFilePrintf(stderr, "Too many pieces returned\n");
77         goto cleanup;
78     }
79     if (*tmp2) {
80         virFilePrintf(stderr, "Too few pieces returned\n");
81         goto cleanup;
82     }
83
84     ret = 0;
85  cleanup:
86     virStringFreeList(got);
87
88     return ret;
89 }
90
91
92 static int testJoin(const void *args)
93 {
94     const struct testJoinData *data = args;
95     char *got;
96     int ret = -1;
97
98     if (!(got = virStringJoin(data->tokens, data->delim))) {
99         VIR_DEBUG("Got no result");
100         return -1;
101     }
102     if (STRNEQ(got, data->string)) {
103         virFilePrintf(stderr, "Mismatch '%s' vs '%s'\n", got, data->string);
104         goto cleanup;
105     }
106
107     ret = 0;
108  cleanup:
109     VIR_FREE(got);
110
111     return ret;
112 }
113
114 static bool fail;
115
116 static const char *
117 testStrdupLookup1(size_t i)
118 {
119     switch (i) {
120     case 0:
121         return "hello";
122     case 1:
123         return NULL;
124     default:
125         fail = true;
126         return "oops";
127     }
128 }
129
130 static size_t
131 testStrdupLookup2(size_t i)
132 {
133     if (i)
134         fail = true;
135     return 5;
136 }
137
138 static int
139 testStrdup(const void *data ATTRIBUTE_UNUSED)
140 {
141     char *array[] = { NULL, NULL };
142     size_t i = 0;
143     size_t j = 0;
144     size_t k = 0;
145     int ret = -1;
146     int value;
147
148     value = VIR_STRDUP(array[i++], testStrdupLookup1(j++));
149     if (value != 1) {
150         virFilePrintf(stderr, "unexpected strdup result %d, expected 1\n", value);
151         goto cleanup;
152     }
153     if (i != 1) {
154         virFilePrintf(stderr, "unexpected side effects i=%zu, expected 1\n", i);
155         goto cleanup;
156     }
157     if (j != 1) {
158         virFilePrintf(stderr, "unexpected side effects j=%zu, expected 1\n", j);
159         goto cleanup;
160     }
161     if (STRNEQ_NULLABLE(array[0], "hello") || array[1]) {
162         virFilePrintf(stderr, "incorrect array contents '%s' '%s'\n",
163                       NULLSTR(array[0]), NULLSTR(array[1]));
164         goto cleanup;
165     }
166
167     value = VIR_STRNDUP(array[i++], testStrdupLookup1(j++),
168                         testStrdupLookup2(k++));
169     if (value != 0) {
170         virFilePrintf(stderr, "unexpected strdup result %d, expected 0\n", value);
171         goto cleanup;
172     }
173     if (i != 2) {
174         virFilePrintf(stderr, "unexpected side effects i=%zu, expected 2\n", i);
175         goto cleanup;
176     }
177     if (j != 2) {
178         virFilePrintf(stderr, "unexpected side effects j=%zu, expected 2\n", j);
179         goto cleanup;
180     }
181     if (k != 1) {
182         virFilePrintf(stderr, "unexpected side effects k=%zu, expected 1\n", k);
183         goto cleanup;
184     }
185     if (STRNEQ_NULLABLE(array[0], "hello") || array[1]) {
186         virFilePrintf(stderr, "incorrect array contents '%s' '%s'\n",
187                       NULLSTR(array[0]), NULLSTR(array[1]));
188         goto cleanup;
189     }
190
191     if (fail) {
192         virFilePrintf(stderr, "side effects failed\n");
193         goto cleanup;
194     }
195
196     ret = 0;
197  cleanup:
198     for (i = 0; i < ARRAY_CARDINALITY(array); i++)
199         VIR_FREE(array[i]);
200     return ret;
201 }
202
203 static int
204 testStrndupNegative(const void *opaque ATTRIBUTE_UNUSED)
205 {
206     int ret = -1;
207     char *dst;
208     const char *src = "Hello world";
209     int value;
210
211     if ((value = VIR_STRNDUP(dst, src, 5)) != 1) {
212         fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value);
213         goto cleanup;
214     }
215
216     if (STRNEQ_NULLABLE(dst, "Hello")) {
217         fprintf(stderr, "unexpected content '%s'", dst);
218         goto cleanup;
219     }
220
221     VIR_FREE(dst);
222     if ((value = VIR_STRNDUP(dst, src, -1)) != 1) {
223         fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value);
224         goto cleanup;
225     }
226
227     if (STRNEQ_NULLABLE(dst, src)) {
228         fprintf(stderr, "unexpected content '%s'", dst);
229         goto cleanup;
230     }
231
232     ret = 0;
233  cleanup:
234     VIR_FREE(dst);
235     return ret;
236 }
237
238
239 static int
240 testStringSortCompare(const void *opaque ATTRIBUTE_UNUSED)
241 {
242     const char *randlist[] = {
243         "tasty", "astro", "goat", "chicken", "turducken",
244     };
245     const char *randrlist[] = {
246         "tasty", "astro", "goat", "chicken", "turducken",
247     };
248     const char *sortlist[] = {
249         "astro", "chicken", "goat", "tasty", "turducken",
250     };
251     const char *sortrlist[] = {
252         "turducken", "tasty", "goat", "chicken", "astro",
253     };
254     int ret = -1;
255     size_t i;
256
257     qsort(randlist, ARRAY_CARDINALITY(randlist), sizeof(randlist[0]),
258           virStringSortCompare);
259     qsort(randrlist, ARRAY_CARDINALITY(randrlist), sizeof(randrlist[0]),
260           virStringSortRevCompare);
261
262     for (i = 0; i < ARRAY_CARDINALITY(randlist); i++) {
263         if (STRNEQ(randlist[i], sortlist[i])) {
264             fprintf(stderr, "sortlist[%zu] '%s' != randlist[%zu] '%s'\n",
265                     i, sortlist[i], i, randlist[i]);
266             goto cleanup;
267         }
268         if (STRNEQ(randrlist[i], sortrlist[i])) {
269             fprintf(stderr, "sortrlist[%zu] '%s' != randrlist[%zu] '%s'\n",
270                     i, sortrlist[i], i, randrlist[i]);
271             goto cleanup;
272         }
273     }
274
275     ret = 0;
276  cleanup:
277     return ret;
278 }
279
280
281 struct stringSearchData {
282     const char *str;
283     const char *regexp;
284     size_t maxMatches;
285     size_t expectNMatches;
286     const char **expectMatches;
287     bool expectError;
288 };
289
290 static int
291 testStringSearch(const void *opaque)
292 {
293     const struct stringSearchData *data = opaque;
294     char **matches = NULL;
295     ssize_t nmatches;
296     int ret = -1;
297
298     nmatches = virStringSearch(data->str, data->regexp,
299                                data->maxMatches, &matches);
300
301     if (data->expectError) {
302         if (nmatches != -1) {
303             fprintf(stderr, "expected error on %s but got %zd matches\n",
304                     data->str, nmatches);
305             goto cleanup;
306         }
307     } else {
308         size_t i;
309
310         if (nmatches < 0) {
311             fprintf(stderr, "expected %zu matches on %s but got error\n",
312                     data->expectNMatches, data->str);
313             goto cleanup;
314         }
315
316         if (nmatches != data->expectNMatches) {
317             fprintf(stderr, "expected %zu matches on %s but got %zd\n",
318                     data->expectNMatches, data->str, nmatches);
319             goto cleanup;
320         }
321
322         if (virStringListLength(matches) != nmatches) {
323             fprintf(stderr, "expected %zu matches on %s but got %zd matches\n",
324                     data->expectNMatches, data->str,
325                     virStringListLength(matches));
326             goto cleanup;
327         }
328
329         for (i = 0; i < nmatches; i++) {
330             if (STRNEQ(matches[i], data->expectMatches[i])) {
331                 fprintf(stderr, "match %zu expected '%s' but got '%s'\n",
332                         i, data->expectMatches[i], matches[i]);
333                 goto cleanup;
334             }
335         }
336     }
337
338     ret = 0;
339
340  cleanup:
341     virStringFreeList(matches);
342     return ret;
343 }
344
345
346 struct stringReplaceData {
347     const char *haystack;
348     const char *oldneedle;
349     const char *newneedle;
350     const char *result;
351 };
352
353 static int
354 testStringReplace(const void *opaque ATTRIBUTE_UNUSED)
355 {
356     const struct stringReplaceData *data = opaque;
357     char *result;
358     int ret = -1;
359
360     result = virStringReplace(data->haystack,
361                               data->oldneedle,
362                               data->newneedle);
363
364     if (STRNEQ_NULLABLE(data->result, result)) {
365         fprintf(stderr, "Expected '%s' but got '%s'\n",
366                 data->result, NULLSTR(result));
367         goto cleanup;
368     }
369
370     ret = 0;
371
372  cleanup:
373     VIR_FREE(result);
374     return ret;
375 }
376
377
378 struct stringToLongData {
379     const char *str;
380     const char *suffix;
381     int si; /* syntax-check doesn't like bare 'i' */
382     int si_ret;
383     unsigned int ui;
384     int ui_ret;
385     /* No expected results for long: on 32-bit platforms, it is the
386      * same as int, on 64-bit platforms it is the same as long long */
387     long long ll;
388     int ll_ret;
389     unsigned long long ull;
390     int ull_ret;
391 };
392
393 /* This test makes assumptions about our compilation platform that are
394  * not guaranteed by POSIX.  Good luck to you if you are crazy enough
395  * to try and port libvirt to a platform with 16-bit int.  */
396 verify(sizeof(int) == 4);
397 verify(TYPE_TWOS_COMPLEMENT(int));
398 verify(sizeof(long) == sizeof(int) || sizeof(long) == sizeof(long long));
399 verify(TYPE_TWOS_COMPLEMENT(long));
400 verify(sizeof(long long) == 8);
401 verify(TYPE_TWOS_COMPLEMENT(long long));
402
403 static int
404 testStringToLong(const void *opaque)
405 {
406     const struct stringToLongData *data = opaque;
407     int ret = 0;
408     char *end;
409     long l;
410     unsigned long ul;
411     bool negative;
412
413     if (data->suffix)
414         negative = !!memchr(data->str, '-',
415                             strlen(data->str) - strlen(data->suffix));
416     else
417         negative = !!strchr(data->str, '-');
418
419 #define TEST_ONE(Str, Suff, Type, Fn, Fmt, Exp, Exp_ret)                \
420     do {                                                                \
421         Type value = 5;                                                 \
422         int result;                                                     \
423         end = (char *) "oops";                                          \
424         result = virStrToLong_ ## Fn(Str, Suff ? &end : NULL,           \
425                                      0, &value);                        \
426         /* On failure, end is modified, value is unchanged */           \
427         if (result != (Exp_ret)) {                                      \
428             fprintf(stderr,                                             \
429                     "type " #Fn " returned %d expected %d\n",           \
430                     result, Exp_ret);                                   \
431             ret = -1;                                                   \
432         }                                                               \
433         if (value != ((Exp_ret) ? 5 : Exp)) {                           \
434             fprintf(stderr,                                             \
435                     "type " #Fn " value " Fmt " expected " Fmt "\n",    \
436                     value, ((Exp_ret) ? 5 : Exp));                      \
437             ret = -1;                                                   \
438         }                                                               \
439         if (Suff && STRNEQ_NULLABLE(Suff, end)) {                       \
440             fprintf(stderr,                                             \
441                     "type " #Fn " end '%s' expected '%s'\n",            \
442                     NULLSTR(end), Suff);                                \
443             ret = -1;                                                   \
444         }                                                               \
445     } while (0)
446
447     TEST_ONE(data->str, data->suffix, int, i, "%d",
448              data->si, data->si_ret);
449     TEST_ONE(data->str, data->suffix, unsigned int, ui, "%u",
450              data->ui, data->ui_ret);
451     if (negative)
452         TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u", 0U, -1);
453     else
454         TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u",
455                  data->ui, data->ui_ret);
456
457     /* We hate adding new API with 'long', and prefer 'int' or 'long
458      * long' instead, since platform-specific results are evil */
459     l = (sizeof(int) == sizeof(long)) ? data->si : data->ll;
460     TEST_ONE(data->str, data->suffix, long, l, "%ld",
461              l, (sizeof(int) == sizeof(long)) ? data->si_ret : data->ll_ret);
462     ul = (sizeof(int) == sizeof(long)) ? data->ui : data->ull;
463     TEST_ONE(data->str, data->suffix, unsigned long, ul, "%lu",
464              ul, (sizeof(int) == sizeof(long)) ? data->ui_ret : data->ull_ret);
465     if (negative)
466         TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", 0UL, -1);
467     else
468         TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", ul,
469                  (sizeof(int) == sizeof(long)) ? data->ui_ret : data->ull_ret);
470
471     TEST_ONE(data->str, data->suffix, long long, ll, "%lld",
472              data->ll, data->ll_ret);
473     TEST_ONE(data->str, data->suffix, unsigned long long, ull, "%llu",
474              data->ull, data->ull_ret);
475     if (negative)
476         TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
477                  0ULL, -1);
478     else
479         TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
480                  data->ull, data->ull_ret);
481
482 #undef TEST_ONE
483
484     return ret;
485 }
486
487
488 static int
489 mymain(void)
490 {
491     int ret = 0;
492
493 #define TEST_SPLIT(str, del, max, toks)                                 \
494     do {                                                                \
495         struct testSplitData splitData = {                              \
496             .string = str,                                              \
497             .delim = del,                                               \
498             .max_tokens = max,                                          \
499             .tokens = toks,                                             \
500         };                                                              \
501         struct testJoinData joinData = {                                \
502             .string = str,                                              \
503             .delim = del,                                               \
504             .tokens = toks,                                             \
505         };                                                              \
506         if (virtTestRun("Split " #str, testSplit, &splitData) < 0)      \
507             ret = -1;                                                   \
508         if (virtTestRun("Join " #str, testJoin, &joinData) < 0)         \
509             ret = -1;                                                   \
510     } while (0)
511
512     const char *tokens1[] = { NULL };
513     TEST_SPLIT("", " ", 0, tokens1);
514
515     const char *tokens2[] = { "", "", NULL };
516     TEST_SPLIT(" ", " ", 0, tokens2);
517
518     const char *tokens3[] = { "", "", "", NULL };
519     TEST_SPLIT("  ", " ", 0, tokens3);
520
521     const char *tokens4[] = { "The", "quick", "brown", "fox", NULL };
522     TEST_SPLIT("The quick brown fox", " ", 0, tokens4);
523
524     const char *tokens5[] = { "The quick ", " fox", NULL };
525     TEST_SPLIT("The quick brown fox", "brown", 0, tokens5);
526
527     const char *tokens6[] = { "", "The", "quick", "brown", "fox", NULL };
528     TEST_SPLIT(" The quick brown fox", " ", 0, tokens6);
529
530     const char *tokens7[] = { "The", "quick", "brown", "fox", "", NULL };
531     TEST_SPLIT("The quick brown fox ", " ", 0, tokens7);
532
533     if (virtTestRun("strdup", testStrdup, NULL) < 0)
534         ret = -1;
535
536     if (virtTestRun("strdup", testStrndupNegative, NULL) < 0)
537         ret = -1;
538
539     if (virtTestRun("virStringSortCompare", testStringSortCompare, NULL) < 0)
540         ret = -1;
541
542 #define TEST_SEARCH(s, r, x, n, m, e)                                   \
543     do {                                                                \
544         struct stringSearchData data = {                                \
545             .str = s,                                                   \
546             .maxMatches = x,                                            \
547             .regexp = r,                                                \
548             .expectNMatches = n,                                        \
549             .expectMatches = m,                                         \
550             .expectError = e,                                           \
551         };                                                              \
552         if (virtTestRun("virStringSearch " s, testStringSearch, &data) < 0) \
553             ret = -1;                                                   \
554     } while (0)
555
556     /* error due to missing () in regexp */
557     TEST_SEARCH("foo", "bar", 10, 0, NULL, true);
558
559     /* error due to too many () in regexp */
560     TEST_SEARCH("foo", "(b)(a)(r)", 10, 0, NULL, true);
561
562     /* None matching */
563     TEST_SEARCH("foo", "(bar)", 10, 0, NULL, false);
564
565     /* Full match */
566     const char *matches1[] = { "foo" };
567     TEST_SEARCH("foo", "(foo)", 10, 1, matches1, false);
568
569     /* Multi matches */
570     const char *matches2[] = { "foo", "bar", "eek" };
571     TEST_SEARCH("1foo2bar3eek", "([a-z]+)", 10, 3, matches2, false);
572
573     /* Multi matches, limited returns */
574     const char *matches3[] = { "foo", "bar" };
575     TEST_SEARCH("1foo2bar3eek", "([a-z]+)", 2, 2, matches3, false);
576
577 #define TEST_REPLACE(h, o, n, r)                                        \
578     do {                                                                \
579         struct stringReplaceData data = {                               \
580             .haystack = h,                                              \
581             .oldneedle = o,                                             \
582             .newneedle = n,                                             \
583             .result = r                                                 \
584         };                                                              \
585         if (virtTestRun("virStringReplace " h, testStringReplace, &data) < 0) \
586             ret = -1;                                                   \
587     } while (0)
588
589     /* no matches */
590     TEST_REPLACE("foo", "bar", "eek", "foo");
591
592     /* complete match */
593     TEST_REPLACE("foo", "foo", "bar", "bar");
594
595     /* middle match */
596     TEST_REPLACE("foobarwizz", "bar", "eek", "fooeekwizz");
597
598     /* many matches */
599     TEST_REPLACE("foofoofoofoo", "foo", "bar", "barbarbarbar");
600
601     /* many matches */
602     TEST_REPLACE("fooooofoooo", "foo", "bar", "barooobaroo");
603
604     /* different length old/new needles */
605     TEST_REPLACE("fooooofoooo", "foo", "barwizzeek", "barwizzeekooobarwizzeekoo");
606     TEST_REPLACE("fooooofoooo", "foooo", "foo", "fooofoo");
607
608 #define TEST_STRTOL(str, suff, i, i_ret, u, u_ret,                      \
609                     ll, ll_ret, ull, ull_ret)                           \
610     do {                                                                \
611         struct stringToLongData data = {                                \
612             str, suff, i, i_ret, u, u_ret, ll, ll_ret, ull, ull_ret,    \
613         };                                                              \
614         if (virtTestRun("virStringToLong '" str "'", testStringToLong,  \
615                         &data) < 0)                                     \
616             ret = -1;                                                   \
617     } while (0)
618
619     /* Start simple */
620     TEST_STRTOL("0", NULL, 0, 0, 0U, 0, 0LL, 0, 0ULL, 0);
621
622     /* All your base are belong to us */
623     TEST_STRTOL("0x0", NULL, 0, 0, 0U, 0, 0LL, 0, 0ULL, 0);
624     TEST_STRTOL("0XaB", NULL, 171, 0, 171U, 0, 171LL, 0, 171ULL, 0);
625     TEST_STRTOL("010", NULL, 8, 0, 8U, 0, 8LL, 0, 8ULL, 0);
626
627     /* Suffix handling */
628     TEST_STRTOL("42", NULL, 42, 0, 42U, 0, 42LL, 0, 42ULL, 0);
629     TEST_STRTOL("42", "",  42, 0, 42U, 0, 42LL, 0, 42ULL, 0);
630     TEST_STRTOL("42.", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
631     TEST_STRTOL("42.", ".",  42, 0, 42U, 0, 42LL, 0, 42ULL, 0);
632
633     /* Blatant invalid input */
634     TEST_STRTOL("", "", 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
635     TEST_STRTOL("", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
636     TEST_STRTOL("  ", "  ", 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
637     TEST_STRTOL("  ", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
638     TEST_STRTOL("  -", "  -", 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
639     TEST_STRTOL("  -", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
640     TEST_STRTOL("a", "a", 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
641     TEST_STRTOL("a", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
642
643     /* Not a hex number, but valid when suffix expected */
644     TEST_STRTOL("  0x", NULL, 0, -1, 0U, -1, 0LL, -1, 0ULL, -1);
645     TEST_STRTOL("  0x", "x", 0, 0, 0U, 0, 0LL, 0, 0ULL, 0);
646
647     /* Upper bounds */
648     TEST_STRTOL("2147483647", NULL, 2147483647, 0, 2147483647U, 0,
649                 2147483647LL, 0, 2147483647ULL, 0);
650     TEST_STRTOL("2147483648", NULL, 0, -1, 2147483648U, 0,
651                 2147483648LL, 0, 2147483648ULL, 0);
652     TEST_STRTOL("4294967295", NULL, 0, -1, 4294967295U, 0,
653                 4294967295LL, 0, 4294967295ULL, 0);
654     TEST_STRTOL("4294967296", NULL, 0, -1, 0U, -1,
655                 4294967296LL, 0, 4294967296ULL, 0);
656     TEST_STRTOL("9223372036854775807", NULL, 0, -1, 0U, -1,
657                 9223372036854775807LL, 0, 9223372036854775807ULL, 0);
658     TEST_STRTOL("9223372036854775808", NULL, 0, -1, 0U, -1,
659                 0LL, -1, 9223372036854775808ULL, 0);
660     TEST_STRTOL("18446744073709551615", NULL, 0, -1, 0U, -1,
661                 0LL, -1, 18446744073709551615ULL, 0);
662     TEST_STRTOL("18446744073709551616", NULL, 0, -1, 0U, -1,
663                 0LL, -1, 0ULL, -1);
664     TEST_STRTOL("18446744073709551616", "", 0, -1, 0U, -1,
665                 0LL, -1, 0ULL, -1);
666
667     /* Negative bounds */
668     TEST_STRTOL("-0", NULL, 0, 0, 0U, 0, 0LL, 0, 0ULL, 0);
669     TEST_STRTOL("-1", "", -1, 0, 4294967295U, 0,
670                 -1LL, 0, 18446744073709551615ULL, 0);
671     TEST_STRTOL("-2147483647", NULL, -2147483647, 0, 2147483649U, 0,
672                 -2147483647LL, 0, 18446744071562067969ULL, 0);
673     TEST_STRTOL("-2147483648", NULL, INT32_MIN, 0, 2147483648U, 0,
674                 -2147483648LL, 0, 18446744071562067968ULL, 0);
675     TEST_STRTOL("-2147483649", NULL, 0, -1, 2147483647U, 0,
676                 -2147483649LL, 0, 18446744071562067967ULL, 0);
677     TEST_STRTOL("-4294967295", NULL, 0, -1, 1U, 0,
678                 -4294967295LL, 0, 18446744069414584321ULL, 0);
679     TEST_STRTOL("-4294967296", NULL, 0, -1, 0U, -1,
680                 -4294967296LL, 0, 18446744069414584320ULL, 0);
681     TEST_STRTOL("-9223372036854775807", NULL, 0, -1, 0U, -1,
682                 -9223372036854775807LL, 0, 9223372036854775809ULL, 0);
683     TEST_STRTOL("-9223372036854775808", NULL, 0, -1, 0U, -1,
684                 INT64_MIN, 0, 9223372036854775808ULL, 0);
685     TEST_STRTOL("-9223372036854775809", NULL, 0, -1, 0U, -1,
686                 0LL, -1, 9223372036854775807ULL, 0);
687     TEST_STRTOL("-18446744073709551615", NULL, 0, -1, 0U, -1,
688                 0LL, -1, 1ULL, 0);
689     TEST_STRTOL("-18446744073709551616", NULL, 0, -1, 0U, -1,
690                 0LL, -1, 0ULL, -1);
691
692     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
693 }
694
695 VIRT_TEST_MAIN(mymain)