/* t-strlist.c - Check strlist functions * Copyright (C) 2015, 2025 g10 Code GmbH * * This file is part of Libgpg-error. * * Libgpg-error is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgpg-error is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #ifdef HAVE_STAT # include #endif #include #ifdef HAVE_PWD_H # include #endif #include #ifdef HAVE_W32_SYSTEM # include #endif #define PGM "t-strutils" #include "t-common.h" static const char * my_strusage (int level) { const char *p; switch (level) { case 9: p = "LGPL-2.1-or-later"; break; case 11: p = PGM; break; default: p = NULL; } return p; } static void check_strlist_rev (void) { gpgrt_strlist_t s = NULL; enter_test_function (); /* Reversing an empty list should yield the empty list. */ if (! (gpgrt_strlist_rev (&s) == NULL)) fail ("reversing an empty list does not yield an empty list"); gpgrt_strlist_add (&s, "1", 0); gpgrt_strlist_add (&s, "2", 0); gpgrt_strlist_add (&s, "3", 0); if (strcmp (s->d, "3") != 0) fail ("failed at %d", __LINE__); if (strcmp (s->next->d, "2") != 0) fail ("failed at %d", __LINE__); if (strcmp (s->next->next->d, "1") != 0) fail ("failed at %d", __LINE__); if (s->next->next->next) fail ("failed at %d", __LINE__); gpgrt_strlist_rev (&s); if (strcmp (s->d, "1") != 0) fail ("failed at %d", __LINE__); if (strcmp (s->next->d, "2") != 0) fail ("failed at %d", __LINE__); if (strcmp (s->next->next->d, "3") != 0) fail ("failed at %d", __LINE__); if (s->next->next->next) fail ("failed at %d", __LINE__); gpgrt_strlist_free (s); leave_test_function (); } static void check_tokenize_to_strlist (void) { struct { const char *s; const char *delim; int error_expected; const char *items_expected[10]; } tv[] = { { "", ":", 1, { NULL } }, { "a", ":", 0, { "a", NULL } }, { ":", ":", 1, { NULL } }, { "::", ":", 1, { NULL } }, { "a:b:c", ":", 0, { "a", "b", "c", NULL } }, { "a:b:", ":", 0, { "a", "b", NULL } }, { "a:b", ":", 0, { "a", "b", NULL } }, { "aa:b:cd", ":", 0, { "aa", "b", "cd", NULL } }, { "aa::b:cd", ":", 0, { "aa", "b", "cd", NULL } }, { "::b:cd", ":", 0, { "b", "cd", NULL } }, { "aa: : b:cd ", ":", 0, { "aa", "b", "cd", NULL } }, { " aa: : b: cd ", ":", 0, { "aa", "b", "cd", NULL } }, { " :", ":", 1, { NULL } }, { " : ", ":", 1, { NULL } }, { ": ", ":", 1, { NULL } }, { ": x ", ":", 0, { "x", NULL } }, { "a:bc:cde:fghi:jklmn::foo:", ":", 0, { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL } }, { ",a,bc,,def,", ",", 0, { "a", "bc", "def", NULL } }, { " a ", " ", 0, { "a", NULL } }, { " ", " ", 1, { NULL } }, { "a:bc:c de:fg hi:jklmn::foo :", ":", 0, { "a", "bc", "c de", "fg hi", "jklmn", "foo", NULL } }, { "", " ", 1, { NULL } } }; const char *prefixes[3] = { "abc", "bcd", "efg" }; int tidx; int nprefixes; /* Number of items in already in the list. */ gpgrt_strlist_t list = NULL; enter_test_function (); for (nprefixes = 0; nprefixes < DIM (prefixes); nprefixes++) for (tidx = 0; tidx < DIM(tv); tidx++) { int item_count_expected; int i; gpgrt_strlist_t sl, newitems; for (item_count_expected = 0; tv[tidx].items_expected[item_count_expected]; item_count_expected++) ; /* printf ("np=%d testing %d \"%s\" delim=\"%s\"\n", */ /* nprefixes, tidx, tv[tidx].s, tv[tidx].delim); */ for (i=0; i < nprefixes; i++) gpgrt_strlist_add (&list, prefixes[i], GPGRT_STRLIST_APPEND); newitems = gpgrt_strlist_tokenize (&list, tv[tidx].s, tv[tidx].delim, 0); if (!newitems) { if (gpg_err_code_from_syserror () == GPG_ERR_ENOENT && tv[tidx].error_expected) { /* Good. But need to check the prefixes. */ for (sl=list, i=0; i < nprefixes; i++, sl=sl->next) { if (!sl || strcmp (prefixes[i], sl->d)) { show ("for item %d prefix item %d, expected '%s'\n", tidx, i, prefixes[i]); fail ("error at index %d, line %d", tidx * 1000 + 40 + i + 1, __LINE__); } } } else fail ("error at index %d, line %d", tidx * 1000, __LINE__); } else if (tv[tidx].error_expected) { show ("got items:"); for (sl = list; sl; sl = sl->next) show (" \"%s\"", sl->d); fail ("error at index %d, line %d", tidx * 1000, __LINE__); } else { if (gpgrt_strlist_count (list) != nprefixes + item_count_expected) fail ("error at index %d, line %d", tidx * 1000, __LINE__); else { for (sl=list, i=0; i < nprefixes; i++, sl=sl->next) { if (!sl || strcmp (prefixes[i], sl->d)) { show ("for item %d prefix item %d, expected '%s'\n", tidx, i, prefixes[i]); fail ("error at index %d, line %d", tidx * 1000 + 50 + i + 1, __LINE__); } } for (i=0; i < item_count_expected; i++, sl=sl->next) { if (!sl) { show ("no item at item index %d\n", i); fail ("error at index %d, line %d", tidx * 1000 + i + 0, __LINE__); break; } if (strcmp (tv[tidx].items_expected[i], sl->d)) { show ("for item %d, expected '%s', but got '%s'\n", i, tv[tidx].items_expected[i], sl->d); fail ("error at index %d, line %d", tidx * 1000 + 10 + i + 1, __LINE__); } } } } gpgrt_strlist_free (list); list = NULL; } leave_test_function (); } int main (int argc, char **argv) { gpgrt_opt_t opts[] = { ARGPARSE_x ('v', "verbose", NONE, 0, "Print more diagnostics"), ARGPARSE_s_n('d', "debug", "Flyswatter"), ARGPARSE_end() }; gpgrt_argparse_t pargs = { &argc, &argv, 0 }; gpgrt_set_strusage (my_strusage); gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX); while (gpgrt_argparse (NULL, &pargs, opts)) { switch (pargs.r_opt) { case 'v': verbose++; break; case 'd': debug++; break; default : pargs.err = ARGPARSE_PRINT_ERROR; break; } } gpgrt_argparse (NULL, &pargs, NULL); show ("testing strlist functions\n"); check_strlist_rev (); check_tokenize_to_strlist (); show ("testing strlist functions finished\n"); return !!errorcount; }