2 * Copyright (C) 2012-2014 Red Hat, Inc.
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, see
16 * <http://www.gnu.org/licenses/>.
18 * Author: Daniel P. Berrange <berrange@redhat.com>
25 #include "testutils.h"
32 #include "virstring.h"
34 #define VIR_FROM_THIS VIR_FROM_NONE
36 VIR_LOG_INIT("tests.stringtest");
38 struct testSplitData {
52 static int testSplit(const void *args)
54 const struct testSplitData *data = args;
60 if (!(got = virStringSplit(data->string, data->delim, data->max_tokens))) {
61 VIR_DEBUG("Got no tokens at all");
67 while (*tmp1 && *tmp2) {
68 if (STRNEQ(*tmp1, *tmp2)) {
69 virFilePrintf(stderr, "Mismatch '%s' vs '%s'\n", *tmp1, *tmp2);
76 virFilePrintf(stderr, "Too many pieces returned\n");
80 virFilePrintf(stderr, "Too few pieces returned\n");
86 virStringFreeList(got);
92 static int testJoin(const void *args)
94 const struct testJoinData *data = args;
98 if (!(got = virStringJoin(data->tokens, data->delim))) {
99 VIR_DEBUG("Got no result");
102 if (STRNEQ(got, data->string)) {
103 virFilePrintf(stderr, "Mismatch '%s' vs '%s'\n", got, data->string);
117 testStrdupLookup1(size_t i)
131 testStrdupLookup2(size_t i)
139 testStrdup(const void *data ATTRIBUTE_UNUSED)
141 char *array[] = { NULL, NULL };
148 value = VIR_STRDUP(array[i++], testStrdupLookup1(j++));
150 virFilePrintf(stderr, "unexpected strdup result %d, expected 1\n", value);
154 virFilePrintf(stderr, "unexpected side effects i=%zu, expected 1\n", i);
158 virFilePrintf(stderr, "unexpected side effects j=%zu, expected 1\n", j);
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]));
167 value = VIR_STRNDUP(array[i++], testStrdupLookup1(j++),
168 testStrdupLookup2(k++));
170 virFilePrintf(stderr, "unexpected strdup result %d, expected 0\n", value);
174 virFilePrintf(stderr, "unexpected side effects i=%zu, expected 2\n", i);
178 virFilePrintf(stderr, "unexpected side effects j=%zu, expected 2\n", j);
182 virFilePrintf(stderr, "unexpected side effects k=%zu, expected 1\n", k);
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]));
192 virFilePrintf(stderr, "side effects failed\n");
198 for (i = 0; i < ARRAY_CARDINALITY(array); i++)
204 testStrndupNegative(const void *opaque ATTRIBUTE_UNUSED)
208 const char *src = "Hello world";
211 if ((value = VIR_STRNDUP(dst, src, 5)) != 1) {
212 fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value);
216 if (STRNEQ_NULLABLE(dst, "Hello")) {
217 fprintf(stderr, "unexpected content '%s'", dst);
222 if ((value = VIR_STRNDUP(dst, src, -1)) != 1) {
223 fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value);
227 if (STRNEQ_NULLABLE(dst, src)) {
228 fprintf(stderr, "unexpected content '%s'", dst);
240 testStringSortCompare(const void *opaque ATTRIBUTE_UNUSED)
242 const char *randlist[] = {
243 "tasty", "astro", "goat", "chicken", "turducken",
245 const char *randrlist[] = {
246 "tasty", "astro", "goat", "chicken", "turducken",
248 const char *sortlist[] = {
249 "astro", "chicken", "goat", "tasty", "turducken",
251 const char *sortrlist[] = {
252 "turducken", "tasty", "goat", "chicken", "astro",
257 qsort(randlist, ARRAY_CARDINALITY(randlist), sizeof(randlist[0]),
258 virStringSortCompare);
259 qsort(randrlist, ARRAY_CARDINALITY(randrlist), sizeof(randrlist[0]),
260 virStringSortRevCompare);
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]);
268 if (STRNEQ(randrlist[i], sortrlist[i])) {
269 fprintf(stderr, "sortrlist[%zu] '%s' != randrlist[%zu] '%s'\n",
270 i, sortrlist[i], i, randrlist[i]);
281 struct stringSearchData {
285 size_t expectNMatches;
286 const char **expectMatches;
291 testStringSearch(const void *opaque)
293 const struct stringSearchData *data = opaque;
294 char **matches = NULL;
298 nmatches = virStringSearch(data->str, data->regexp,
299 data->maxMatches, &matches);
301 if (data->expectError) {
302 if (nmatches != -1) {
303 fprintf(stderr, "expected error on %s but got %zd matches\n",
304 data->str, nmatches);
311 fprintf(stderr, "expected %zu matches on %s but got error\n",
312 data->expectNMatches, data->str);
316 if (nmatches != data->expectNMatches) {
317 fprintf(stderr, "expected %zu matches on %s but got %zd\n",
318 data->expectNMatches, data->str, nmatches);
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));
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]);
341 virStringFreeList(matches);
346 struct stringReplaceData {
347 const char *haystack;
348 const char *oldneedle;
349 const char *newneedle;
354 testStringReplace(const void *opaque ATTRIBUTE_UNUSED)
356 const struct stringReplaceData *data = opaque;
360 result = virStringReplace(data->haystack,
364 if (STRNEQ_NULLABLE(data->result, result)) {
365 fprintf(stderr, "Expected '%s' but got '%s'\n",
366 data->result, NULLSTR(result));
378 struct stringToLongData {
381 int si; /* syntax-check doesn't like bare 'i' */
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 */
389 unsigned long long ull;
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));
404 testStringToLong(const void *opaque)
406 const struct stringToLongData *data = opaque;
414 negative = !!memchr(data->str, '-',
415 strlen(data->str) - strlen(data->suffix));
417 negative = !!strchr(data->str, '-');
419 #define TEST_ONE(Str, Suff, Type, Fn, Fmt, Exp, Exp_ret) \
423 end = (char *) "oops"; \
424 result = virStrToLong_ ## Fn(Str, Suff ? &end : NULL, \
426 /* On failure, end is modified, value is unchanged */ \
427 if (result != (Exp_ret)) { \
429 "type " #Fn " returned %d expected %d\n", \
433 if (value != ((Exp_ret) ? 5 : Exp)) { \
435 "type " #Fn " value " Fmt " expected " Fmt "\n", \
436 value, ((Exp_ret) ? 5 : Exp)); \
439 if (Suff && STRNEQ_NULLABLE(Suff, end)) { \
441 "type " #Fn " end '%s' expected '%s'\n", \
442 NULLSTR(end), Suff); \
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);
452 TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u", 0U, -1);
454 TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u",
455 data->ui, data->ui_ret);
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);
466 TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", 0UL, -1);
468 TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", ul,
469 (sizeof(int) == sizeof(long)) ? data->ui_ret : data->ull_ret);
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);
476 TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
479 TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
480 data->ull, data->ull_ret);
493 #define TEST_SPLIT(str, del, max, toks) \
495 struct testSplitData splitData = { \
501 struct testJoinData joinData = { \
506 if (virtTestRun("Split " #str, testSplit, &splitData) < 0) \
508 if (virtTestRun("Join " #str, testJoin, &joinData) < 0) \
512 const char *tokens1[] = { NULL };
513 TEST_SPLIT("", " ", 0, tokens1);
515 const char *tokens2[] = { "", "", NULL };
516 TEST_SPLIT(" ", " ", 0, tokens2);
518 const char *tokens3[] = { "", "", "", NULL };
519 TEST_SPLIT(" ", " ", 0, tokens3);
521 const char *tokens4[] = { "The", "quick", "brown", "fox", NULL };
522 TEST_SPLIT("The quick brown fox", " ", 0, tokens4);
524 const char *tokens5[] = { "The quick ", " fox", NULL };
525 TEST_SPLIT("The quick brown fox", "brown", 0, tokens5);
527 const char *tokens6[] = { "", "The", "quick", "brown", "fox", NULL };
528 TEST_SPLIT(" The quick brown fox", " ", 0, tokens6);
530 const char *tokens7[] = { "The", "quick", "brown", "fox", "", NULL };
531 TEST_SPLIT("The quick brown fox ", " ", 0, tokens7);
533 if (virtTestRun("strdup", testStrdup, NULL) < 0)
536 if (virtTestRun("strdup", testStrndupNegative, NULL) < 0)
539 if (virtTestRun("virStringSortCompare", testStringSortCompare, NULL) < 0)
542 #define TEST_SEARCH(s, r, x, n, m, e) \
544 struct stringSearchData data = { \
548 .expectNMatches = n, \
549 .expectMatches = m, \
552 if (virtTestRun("virStringSearch " s, testStringSearch, &data) < 0) \
556 /* error due to missing () in regexp */
557 TEST_SEARCH("foo", "bar", 10, 0, NULL, true);
559 /* error due to too many () in regexp */
560 TEST_SEARCH("foo", "(b)(a)(r)", 10, 0, NULL, true);
563 TEST_SEARCH("foo", "(bar)", 10, 0, NULL, false);
566 const char *matches1[] = { "foo" };
567 TEST_SEARCH("foo", "(foo)", 10, 1, matches1, false);
570 const char *matches2[] = { "foo", "bar", "eek" };
571 TEST_SEARCH("1foo2bar3eek", "([a-z]+)", 10, 3, matches2, false);
573 /* Multi matches, limited returns */
574 const char *matches3[] = { "foo", "bar" };
575 TEST_SEARCH("1foo2bar3eek", "([a-z]+)", 2, 2, matches3, false);
577 #define TEST_REPLACE(h, o, n, r) \
579 struct stringReplaceData data = { \
585 if (virtTestRun("virStringReplace " h, testStringReplace, &data) < 0) \
590 TEST_REPLACE("foo", "bar", "eek", "foo");
593 TEST_REPLACE("foo", "foo", "bar", "bar");
596 TEST_REPLACE("foobarwizz", "bar", "eek", "fooeekwizz");
599 TEST_REPLACE("foofoofoofoo", "foo", "bar", "barbarbarbar");
602 TEST_REPLACE("fooooofoooo", "foo", "bar", "barooobaroo");
604 /* different length old/new needles */
605 TEST_REPLACE("fooooofoooo", "foo", "barwizzeek", "barwizzeekooobarwizzeekoo");
606 TEST_REPLACE("fooooofoooo", "foooo", "foo", "fooofoo");
608 #define TEST_STRTOL(str, suff, i, i_ret, u, u_ret, \
609 ll, ll_ret, ull, ull_ret) \
611 struct stringToLongData data = { \
612 str, suff, i, i_ret, u, u_ret, ll, ll_ret, ull, ull_ret, \
614 if (virtTestRun("virStringToLong '" str "'", testStringToLong, \
620 TEST_STRTOL("0", NULL, 0, 0, 0U, 0, 0LL, 0, 0ULL, 0);
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);
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);
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);
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);
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,
664 TEST_STRTOL("18446744073709551616", "", 0, -1, 0U, -1,
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,
689 TEST_STRTOL("-18446744073709551616", NULL, 0, -1, 0U, -1,
692 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
695 VIRT_TEST_MAIN(mymain)