Index: ossp-pkg/str/str_test.c RCS File: /v/ossp/cvs/ossp-pkg/str/str_test.c,v co -q -kk -p'1.20' '/v/ossp/cvs/ossp-pkg/str/str_test.c,v' | diff -u /dev/null - -L'ossp-pkg/str/str_test.c' 2>/dev/null --- ossp-pkg/str/str_test.c +++ - 2024-05-19 11:06:50.946191753 +0200 @@ -0,0 +1,500 @@ +/* +** Str - String Library +** Copyright (c) 1999-2000 Ralf S. Engelschall +** +** This file is part of Str, a string handling and manipulation +** library which can be found at http://www.engelschall.com/sw/str/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** str_test.c: test suite +*/ + +#include +#include + +#include "str.h" +#include "str_config.h" + +#define LONG_STRING 1024 + +/* + * Test String Length + */ + +static void test_length(int *ok, int *fail) +{ + if (str_len(NULL) == 0) + (*ok)++; + else + (*fail)++; + + if (str_len("") == 0) + (*ok)++; + else + (*fail)++; + + if (str_len("a") == 1) + (*ok)++; + else + (*fail)++; + + if (str_len("foo bar quux") == 12) + (*ok)++; + else + (*fail)++; + return; +} + +/* + * Test String Locating + */ + +struct { + char *s; str_size_t n; char *p; int o; +} loctab[] = { + { "foo bar quux", 0, "", 0 }, + { "foo bar quux", 0, "foo", 0 }, + { "foo bar quux", 0, "bar", 4 }, + { "foo bar quux", 0, "quux", 8 }, + { "foo bar quux", 0, "x", 11 }, + { "foo bar quux", 3, "foo", 0 }, + { "foo bar quux", 4, "x", -1 }, + { "foo bar quux", 5, "bar", -1 }, + { "foo bar", 0, "foo bar", 0 }, + { "foo bar", 0, "foo bar quux", -1 }, + { NULL, 0, NULL, 0 } +}; + +static void test_locate(int *ok, int *fail) +{ + int i; + char *rv; + + for (i = 0; loctab[i].s != NULL; i++) { + rv = str_locate(loctab[i].s, loctab[i].n, loctab[i].p); + printf("str_locate(\"%s\", %d, \"%s\") = \"%s\"\n", + loctab[i].s, loctab[i].n, loctab[i].p, rv == NULL ? "[NULL]" : rv); + if ((rv-loctab[i].s == loctab[i].o) || (rv == NULL && loctab[i].o == -1)) + (*ok)++; + else { + fprintf(stderr, "ERROR: result was \"%s\", expected \"%s\"\n", + rv, loctab[i].s+loctab[i].o); + (*fail)++; + } + } + return; +} + +/* + * Test String Spanning + */ + +struct { + char *s; str_size_t n; char *cs; int m; int o; +} spantab[] = { + { "foo bar quux", 0, "", 0, 0 }, + { "foo bar quux", 0, "xyz", 0, 0 }, + { "foo bar quux", 0, "fo ", 0, 4 }, + { "foo bar quux", 0, "b", STR_COMPLEMENT, 4 }, + { "foo bar quux", 0, "", STR_COMPLEMENT, 12 }, + { "foo bar quux", 0, "", STR_RIGHT, 11 }, + { "foo bar quux", 0, "abc", STR_RIGHT, 11 }, + { "foo bar quux", 0, "qux ", STR_RIGHT, 6 }, + { "foo bar quux", 0, "r", STR_RIGHT|STR_COMPLEMENT, 6 }, + { "foo bar quux", 0, "", STR_RIGHT|STR_COMPLEMENT, 0 }, + { "", 0, "", STR_COMPLEMENT, 0 }, + { "", 0, "", STR_RIGHT|STR_COMPLEMENT, 0 }, + { NULL, 0, NULL, 0, 0 } +}; + +static void test_span(int *ok, int *fail) +{ + int i; + char *rv; + + for (i = 0; spantab[i].s != NULL; i++) { + rv = str_span(spantab[i].s, spantab[i].n, spantab[i].cs, spantab[i].m); + printf("str_span(\"%s\", %d, \"%s\", %d) = \"%s\"\n", + spantab[i].s, spantab[i].n, spantab[i].cs, spantab[i].m, rv); + if (rv-spantab[i].s == spantab[i].o) + (*ok)++; + else { + fprintf(stderr, "ERROR: result was \"%s\", expected \"%s\"\n", + rv, spantab[i].s+spantab[i].o); + (*fail)++; + } + } + return; +} + +/* + * Test String Tokenization + */ + +struct { + char *s; char *d; char *q; char *c; int f; char *r[4]; +} toktab[] = { + { "foo bar quux", " \t", "\"'", "#", 0, { "foo", "bar", "quux", NULL } }, + { " foo \t \"bar \t b'az\" quux#vwxyz", " \t", "\"'", "#", STR_STRIPQUOTES, { "foo", "bar \t b'az", "quux", NULL } }, + { NULL, NULL, NULL, NULL, 0, { NULL, NULL, NULL, NULL } } +}; + +static char *prstr_tab[200]; +static int prstr_idx = 0; + +static char *prstr(char *s) +{ + char *cp; + char *p, *q; + + if (s == NULL) + return "NULL"; + if ((cp = malloc(strlen(s)+20)) == NULL) + return "ERROR"; + prstr_tab[prstr_idx++] = cp; + q = cp; + p = s; + *q++ = '"'; + while (*p != NUL) { + switch (*p) { + case '\t': *q++ = '\\'; *q++ = 't'; p++; break; + case '\n': *q++ = '\\'; *q++ = 'n'; p++; break; + case '\r': *q++ = '\\'; *q++ = 'r'; p++; break; + case '"': *q++ = '\\'; *q++ = '"'; p++; break; + default: *q++ = *p++; + } + } + *q++ = '"'; + *q = NUL; + return cp; +} + +static void prstr_free(void) +{ + while (prstr_idx > 0) + free(prstr_tab[--prstr_idx]); + return; +} + +static void test_tokenize(int *ok, int *fail) +{ + char *cp; + char *cp2; + char *cp3; + char *rc; + int i, j; + + for (i = 0; toktab[i].s != NULL; i++) { + fprintf(stderr, "Testing tokenization of %s\n", prstr(toktab[i].s)), prstr_free(); + cp2 = cp = strdup(toktab[i].s); + for (j = 0; j < 4; j++) { + cp3 = strdup(cp); + rc = str_token(&cp, toktab[i].d, toktab[i].q, toktab[i].c, toktab[i].f); + fprintf(stderr, "str_token(&%s, %s, %s, %s, %d) = %s\n", + prstr(cp3), prstr(toktab[i].d), + prstr(toktab[i].q), prstr(toktab[i].c), + toktab[i].f, prstr(rc)), prstr_free(); + free(cp3); + if (!( (rc == NULL && toktab[i].r[j] == NULL) + || (rc != NULL && toktab[i].r[j] != NULL && strcmp(rc, toktab[i].r[j]) == 0))) { + fprintf(stderr, "ERROR: expected result is %s\n", prstr(toktab[i].r[j])), prstr_free(); + } + } + free(cp2); + fprintf(stderr, "\n"); + } + return; +} + +/* + * Test String Parsing + */ + +struct { + char *s; char *p; char *r1; char *r2; char *r3; char *r4; int rv; +} test2_tab[] = { + { "foobar", "foobar", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "m/^foobar$/", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "foobarquux", NULL, NULL, NULL, NULL, 0 }, + { "foobar", "foo", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "?", NULL, NULL, NULL, NULL, -1 }, + { "foobar", "m/(foo|bar)(bar|foo)/", "foo", "bar", NULL, NULL, 1 }, + { "foobar", "m&(?:foo|bar)(?:bar|foo)&", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "m/(?:foo|bar)(?:bar|foo)/o", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "m/(?:FOO|BAR)(?:bar|foo)/io", NULL, NULL, NULL, NULL, 1 }, + { "foobar", "((f(.)\\3)(b.*))", "foobar", "foo", "o", "bar", 1 }, + { "foobar", "s/((f(.)\\3)(b.*))/$2-$4/io", "foo-bar", NULL, NULL, NULL, 1 }, + { "foobar", "s/((f(.)\\3)(b.*))/$2-%s-$4/io", "foo-quux-bar", "quux", NULL, NULL, 1 }, + { "foobar", "s/((f(.)\\3)(b.*))/$2-%s-%s-%s-$4/io", "foo-quux-baz-0815-bar", "quux", "baz", "0815", 1 }, + { "foo:bar", "m/^(f[^:]+):(.*)$/", "foo", "bar", NULL, NULL, 1 }, + { "foo:bar", "s/^([^:]+):(.*)$/$1-%s-$2/o", "foo-quux-bar", "quux", NULL, NULL, 1 }, + { NULL, NULL, NULL, NULL, NULL, NULL, 0 } +}; + +static void test_parsing(int *ok, int *fail) +{ + int i; + int rv; + char *r1, *r2, *r3, *r4; + + for (i = 0; test2_tab[i].s != NULL; i++) { + fprintf(stderr, "%d. str_parse(\"%s\", \"%s\", ...)\n", i, test2_tab[i].s, test2_tab[i].p); + if (*(test2_tab[i].p) == 's') { + r1 = NULL; + r2 = test2_tab[i].r2; + r3 = test2_tab[i].r3; + r4 = test2_tab[i].r4; + rv = str_parse(test2_tab[i].s, test2_tab[i].p, &r1, r2, r3, r4); + } + else { + r1 = r2 = r3 = r4 = NULL; + rv = str_parse(test2_tab[i].s, test2_tab[i].p, &r1, &r2, &r3, &r4); + } + fprintf(stderr, "%d. str_parse(\"%s\", \"%s\", ...) = %d + <%s><%s><%s><%s>\n", + i, test2_tab[i].s, test2_tab[i].p, rv, + r1 == NULL ? "NULL" : r1, r2 == NULL ? "NULL" : r2, + r3 == NULL ? "NULL" : r3, r4 == NULL ? "NULL" : r4); + if (rv != test2_tab[i].rv || + ((r1 == NULL && test2_tab[i].r1 != NULL) || + (r1 != NULL && test2_tab[i].r1 == NULL) || + (r1 != NULL && test2_tab[i].r1 != NULL && strcmp(r1, test2_tab[i].r1) != 0)) || + ((r2 == NULL && test2_tab[i].r2 != NULL) || + (r2 != NULL && test2_tab[i].r2 == NULL) || + (r2 != NULL && test2_tab[i].r2 != NULL && strcmp(r2, test2_tab[i].r2) != 0)) || + ((r3 == NULL && test2_tab[i].r3 != NULL) || + (r3 != NULL && test2_tab[i].r3 == NULL) || + (r3 != NULL && test2_tab[i].r3 != NULL && strcmp(r3, test2_tab[i].r3) != 0)) || + ((r4 == NULL && test2_tab[i].r4 != NULL) || + (r4 != NULL && test2_tab[i].r4 == NULL) || + (r4 != NULL && test2_tab[i].r4 != NULL && strcmp(r4, test2_tab[i].r4) != 0))) { + fprintf(stderr, " ERROR: expected result: %d + <%s><%s><%s><%s>\n", + test2_tab[i].rv, + test2_tab[i].r1 == NULL ? "NULL" : test2_tab[i].r1, + test2_tab[i].r2 == NULL ? "NULL" : test2_tab[i].r2, + test2_tab[i].r3 == NULL ? "NULL" : test2_tab[i].r3, + test2_tab[i].r4 == NULL ? "NULL" : test2_tab[i].r4); + (*fail)++; + } + else + (*ok)++; + } + return; +} + +/* + * Test String Formatting + */ + +static void test_formatting(int *ok, int *fail) +{ + char buf1[LONG_STRING]; + char buf2[LONG_STRING]; + char *fp_fmt[] = { + "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", + "%+22.9f", "%+4.9f", "%01.3f", "%4f", + "%3.1f", "%3.2f", "%.0f", "%.1f", + NULL + }; + double fp_nums[] = { + -1.5, 134.21, 91340.2, 341.1234, 0203.9, + 0.96, 0.996, 0.9996, 1.996, 4.136, + 0 + }; + char *int_fmt[] = { + "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", + "% 10.5d", "%+22.33d", "%01.3d", "%4d", +#if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0) + "%12qd", +#endif + NULL + }; +#if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0) + long long +#else + long +#endif + int_nums[] = { + -1, 134, 91340, 341, 0203, + 4294967290UL, /* less than 2^32 */ +#if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0) + 4294967297ULL, /* more than 2^32 (actually 2^32 + 1) */ +#endif + 0 + }; + int x, y; + int len; + + fprintf(stderr, "\n** Testing str_format format codes against vendor sprintf **\n\n"); + + for (x = 0; fp_fmt[x] != NULL; x++) { + fprintf(stderr, "testing \"%s\"\n", fp_fmt[x]); + for (y = 0; fp_nums[y] != 0; y++) { + len = str_format(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); + sprintf(buf2, fp_fmt[x], fp_nums[y]); + if (strcmp(buf1, buf2) != 0) { + fprintf(stderr, " mismatch:\n"); + fprintf(stderr, " str_format: \"%s\"\n" + " sprintf: \"%s\"\n", buf1, buf2); + (*fail)++; + } + else { + fprintf(stderr, " ok: %d \"%s\" (%d)\n", len, buf1, (int)strlen(buf1)); + (*ok)++; + } + } + } + + for (x = 0; int_fmt[x] != NULL; x++) { + fprintf(stderr, "testing \"%s\"\n", int_fmt[x]); + for (y = 0; int_nums[y] != 0; y++) { + len = str_format(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); + sprintf(buf2, int_fmt[x], int_nums[y]); + if (strcmp(buf1, buf2) != 0) { + fprintf(stderr, " mismatch:\n"); + fprintf(stderr, " str_format: \"%s\"\n" + " sprintf: \"%s\"\n", buf1, buf2); + (*fail)++; + } + else { + fprintf(stderr, " ok: %d \"%s\" (%d)\n", len, buf1, (int)strlen(buf1)); + (*ok)++; + } + } + } + return; +} + +static void test_base64_do(unsigned char *ucp, int ulen, int mode, int *ok, int *fail) +{ + unsigned char ucp2[1024]; + char cp[1024]; + int n1, n2, n3, n4; + int i; + int fine; + + n1 = str_base64(NULL, 0, ucp, ulen, STR_BASE64_ENCODE|mode); + n2 = str_base64(cp, sizeof(cp), ucp, ulen, STR_BASE64_ENCODE|mode); + if (n1 != n2) { + fprintf(stderr, " ERROR: encoding length mismatch: %d vs. %d\n", n1, n2); + (*fail)++; + } + else + (*ok)++; + n3 = str_base64(cp, n2, NULL, 0, STR_BASE64_DECODE|mode); + if (n3 != ulen) { + fprintf(stderr, " ERROR: decoding check length mismatch: %d vs. %d\n", n3, ulen); + (*fail)++; + } + else + (*ok)++; + n4 = str_base64(cp, n2, ucp2, ulen, STR_BASE64_DECODE|mode); + if (n3 != n4) { + fprintf(stderr, " ERROR: decoding length mismatch: %d vs. %d\n", n3, n4); + (*fail)++; + } + else + (*ok)++; + fine = TRUE; + for (i = 0; i < 256; i++) { + if (ucp[i] != ucp2[i]) { + fine = FALSE; + break; + } + } + if (!fine) { + fprintf(stderr, " ERROR: decoding mismatch\n"); + (*fail)++; + } + else + (*ok)++; + return; +} + +static void test_base64(int *ok, int *fail) +{ + unsigned char ucp[256]; + int i; + + fprintf(stderr, "\n** Testing str_base64 **\n\n"); + + fprintf(stderr, "1. Encode/Decode of 0 bytes\n"); + for (i = 0; i < 256; i++) + ucp[i] = 0x55; + test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + + fprintf(stderr, "2. Encode/Decode of increasing bytes\n"); + for (i = 0; i < 256; i++) + ucp[i] = i; + test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + + fprintf(stderr, "3. Encode/Decode of distributed bytes\n"); + for (i = 0; i < 256; i++) + ucp[i] = i*31; + test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + + return; +} + +/* + * Main Test Driver Program + */ + +struct { + char *name; + void (*func)(int *, int *); + int ok; + int fail; +} tests[] = { + { "Length", test_length, 0, 0 }, + { "Locating", test_locate, 0, 0 }, + { "Spanning", test_span, 0, 0 }, + { "Tokenizing", test_tokenize, 0, 0 }, + { "Parsing", test_parsing, 0, 0 }, + { "Formatting", test_formatting, 0, 0 }, + { "Base64", test_base64, 0, 0 }, + { NULL, NULL, 0,0 } +}; + +int main(int argc, char *argv[]) +{ + int i; + int fail; + int ok; + + ok = 0; + fail = 0; + fprintf(stderr, "\n"); + fprintf(stderr, "String Library Test Suite\n"); + fprintf(stderr, "________________________________________\n\n"); + for (i = 0; tests[i].name != NULL; i++) { + fprintf(stderr, "==== Testing %s ====\n", tests[i].name); + tests[i].ok = tests[i].fail = 0; + tests[i].func(&tests[i].ok, &tests[i].fail); + fprintf(stderr, "==== Tests failed %d/%d ====\n", tests[i].fail, tests[i].ok+tests[i].fail); + fprintf(stderr, "\n"); + ok += tests[i].ok; + fail += tests[i].fail; + } + fprintf(stderr, "________________________________________\n\n"); + fprintf(stderr, "TOTAL: failed %d/%d\n", fail, fail+ok); + fprintf(stderr, "\n"); + return fail; +} +