tests/test_printf.c

Fri, 12 Apr 2024 21:48:12 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 12 Apr 2024 21:48:12 +0200
changeset 849
edb9f875b7f9
parent 810
85859399a0cc
permissions
-rw-r--r--

improves interface of cx_sprintf() variants

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2023 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include "cx/test.h"
    30 #include "util_allocator.h"
    32 #include "cx/printf.h"
    33 #include "cx/buffer.h"
    35 #define ASSERT_ZERO_TERMINATED(str) CX_TEST_ASSERTM((str).ptr[(str).length] == '\0', \
    36     #str " is not zero terminated")
    38 static size_t test_printf_write_func(
    39         void const *src,
    40         size_t esize,
    41         size_t ecount,
    42         void *target
    43 ) {
    44     memcpy(target, src, esize * ecount);
    45     return esize * ecount;
    46 }
    48 CX_TEST(test_bprintf) {
    49     CxTestingAllocator talloc;
    50     cx_testing_allocator_init(&talloc);
    51     CxAllocator *alloc = &talloc.base;
    52     CX_TEST_DO {
    53         CxBuffer buf;
    54         cxBufferInit(&buf, NULL, 64, alloc, 0);
    55         size_t r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca);
    56         CX_TEST_ASSERT(r == 34);
    57         CX_TEST_ASSERT(buf.size == 34);
    58         buf.space[r] = '\0';
    59         CX_TEST_ASSERT(0 == strcmp(buf.space, "This Test aged 10 years in a CASK."));
    60         cxBufferDestroy(&buf);
    61         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    62     }
    63     cx_testing_allocator_destroy(&talloc);
    64 }
    66 CX_TEST(test_bprintf_large_string) {
    67     unsigned len = cx_printf_sbo_size;
    68     CxTestingAllocator talloc;
    69     cx_testing_allocator_init(&talloc);
    70     CxAllocator *alloc = &talloc.base;
    71     char *aaa = malloc(len);
    72     char *bbb = malloc(len);
    73     char *expected = malloc(2*len+16);
    74     memset(aaa, 'a', len-1);
    75     aaa[len-1] = 0;
    76     memset(bbb, 'b', len-1);
    77     bbb[len-1] = 0;
    78     sprintf(expected, "After %s comes %s.", aaa, bbb);
    79     CX_TEST_DO {
    80         CxBuffer buf;
    81         cxBufferInit(&buf, NULL, 64, alloc, CX_BUFFER_AUTO_EXTEND);
    82         size_t r = cx_bprintf(&buf, "After %s comes %s.", aaa, bbb);
    83         size_t er = 2*len-2+14;
    84         CX_TEST_ASSERT(r == er);
    85         CX_TEST_ASSERT(buf.size == er);
    86         cxBufferPut(&buf, 0);
    87         CX_TEST_ASSERT(0 == strcmp(expected, buf.space));
    88         cxBufferDestroy(&buf);
    89         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
    90     }
    91     free(aaa);
    92     free(bbb);
    93     free(expected);
    94     cx_testing_allocator_destroy(&talloc);
    95 }
    97 CX_TEST(test_bprintf_nocap) {
    98     CxTestingAllocator talloc;
    99     cx_testing_allocator_init(&talloc);
   100     CxAllocator *alloc = &talloc.base;
   101     char space[20];
   102     memset(space, 'a', 20);
   103     CX_TEST_DO {
   104         CxBuffer buf;
   105         cxBufferInit(&buf, space, 16, alloc, 0);
   106         size_t r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16);
   107         CX_TEST_ASSERT(r == 16);
   108         CX_TEST_ASSERT(buf.size == 16);
   109         CX_TEST_ASSERT(0 == memcmp(space, "Hello string witaaaa", 20));
   110         cxBufferDestroy(&buf);
   111         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   112     }
   113     cx_testing_allocator_destroy(&talloc);
   114 }
   116 CX_TEST(test_fprintf) {
   117     char const *h = "Hello";
   118     char buf[32];
   119     size_t r;
   120     CX_TEST_DO {
   121         r = cx_fprintf(buf, test_printf_write_func, "teststring");
   122         CX_TEST_ASSERT(r == 10);
   123         CX_TEST_ASSERT(0 == memcmp(buf, "teststring", r));
   125         r = cx_fprintf(buf, test_printf_write_func, "[%10s]", h);
   126         CX_TEST_ASSERT(r == 12);
   127         CX_TEST_ASSERT(0 == memcmp(buf, "[     Hello]", r));
   129         r = cx_fprintf(buf, test_printf_write_func, "[%-10s]", h);
   130         CX_TEST_ASSERT(r == 12);
   131         CX_TEST_ASSERT(0 == memcmp(buf, "[Hello     ]", r));
   133         r = cx_fprintf(buf, test_printf_write_func, "[%*s]", 10, h);
   134         CX_TEST_ASSERT(r == 12);
   135         CX_TEST_ASSERT(0 == memcmp(buf, "[     Hello]", r));
   137         r = cx_fprintf(buf, test_printf_write_func, "[%-10.*s]", 4, h);
   138         CX_TEST_ASSERT(r == 12);
   139         CX_TEST_ASSERT(0 == memcmp(buf, "[Hell      ]", r));
   141         r = cx_fprintf(buf, test_printf_write_func, "[%-*.*s]", 10, 4, h);
   142         CX_TEST_ASSERT(r == 12);
   143         CX_TEST_ASSERT(0 == memcmp(buf, "[Hell      ]", r));
   145         r = cx_fprintf(buf, test_printf_write_func, "%c", 'A');
   146         CX_TEST_ASSERT(r == 1);
   147         CX_TEST_ASSERT(0 == memcmp(buf, "A", r));
   149         r = cx_fprintf(buf, test_printf_write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
   150         CX_TEST_ASSERT(r == 19);
   151         CX_TEST_ASSERT(0 == memcmp(buf, "1 2 000003 0  +4 -4", r));
   153         r = cx_fprintf(buf, test_printf_write_func, "%x %x %X %#x", 5, 10, 10, 6);
   154         CX_TEST_ASSERT(r == 9);
   155         CX_TEST_ASSERT(0 == memcmp(buf, "5 a A 0x6", r));
   157         r = cx_fprintf(buf, test_printf_write_func, "%o %#o %#o", 10, 10, 4);
   158         CX_TEST_ASSERT(r == 9);
   159         CX_TEST_ASSERT(0 == memcmp(buf, "12 012 04", r));
   161         r = cx_fprintf(buf, test_printf_write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
   162         CX_TEST_ASSERT(r == 16);
   163         CX_TEST_ASSERT(0 == memcmp(buf, "01.50 1.50  1.50", r));
   165         r = cx_fprintf(buf, test_printf_write_func, "'%*c'", 5, 'x');
   166         CX_TEST_ASSERT(r == 7);
   167         CX_TEST_ASSERT(0 == memcmp(buf, "'    x'", r));
   169         r = cx_fprintf(buf, test_printf_write_func, "'%*c'", -5, 'x');
   170         CX_TEST_ASSERT(r == 7);
   171         CX_TEST_ASSERT(0 == memcmp(buf, "'x    '", r));
   172     }
   173 }
   175 CX_TEST(test_asprintf) {
   176     CxTestingAllocator talloc;
   177     cx_testing_allocator_init(&talloc);
   178     CxAllocator *alloc = &talloc.base;
   180     char const *h = "Hello";
   182     int const specimen_count = 13;
   183     cxmutstr r[specimen_count];
   184     int specimen = 0;
   186     CX_TEST_DO {
   187         r[specimen] = cx_asprintf_a(alloc, "teststring");
   188         CX_TEST_ASSERT(r[specimen].length == 10);
   189         ASSERT_ZERO_TERMINATED(r[specimen]);
   190         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "teststring"));
   191         specimen++;
   193         r[specimen] = cx_asprintf_a(alloc, "[%10s]", h);
   194         CX_TEST_ASSERT(r[specimen].length == 12);
   195         ASSERT_ZERO_TERMINATED(r[specimen]);
   196         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[     Hello]"));
   197         specimen++;
   199         r[specimen] = cx_asprintf_a(alloc, "[%-10s]", h);
   200         CX_TEST_ASSERT(r[specimen].length == 12);
   201         ASSERT_ZERO_TERMINATED(r[specimen]);
   202         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hello     ]"));
   203         specimen++;
   205         r[specimen] = cx_asprintf_a(alloc, "[%*s]", 10, h);
   206         CX_TEST_ASSERT(r[specimen].length == 12);
   207         ASSERT_ZERO_TERMINATED(r[specimen]);
   208         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[     Hello]"));
   209         specimen++;
   211         r[specimen] = cx_asprintf_a(alloc, "[%-10.*s]", 4, h);
   212         CX_TEST_ASSERT(r[specimen].length == 12);
   213         ASSERT_ZERO_TERMINATED(r[specimen]);
   214         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hell      ]"));
   215         specimen++;
   217         r[specimen] = cx_asprintf_a(alloc, "[%-*.*s]", 10, 4, h);
   218         CX_TEST_ASSERT(r[specimen].length == 12);
   219         ASSERT_ZERO_TERMINATED(r[specimen]);
   220         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hell      ]"));
   221         specimen++;
   223         r[specimen] = cx_asprintf_a(alloc, "%c", 'A');
   224         CX_TEST_ASSERT(r[specimen].length == 1);
   225         ASSERT_ZERO_TERMINATED(r[specimen]);
   226         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "A"));
   227         specimen++;
   229         r[specimen] = cx_asprintf_a(alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4);
   230         CX_TEST_ASSERT(r[specimen].length == 19);
   231         ASSERT_ZERO_TERMINATED(r[specimen]);
   232         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "1 2 000003 0  +4 -4"));
   233         specimen++;
   235         r[specimen] = cx_asprintf_a(alloc, "%x %x %X %#x", 5, 10, 10, 6);
   236         CX_TEST_ASSERT(r[specimen].length == 9);
   237         ASSERT_ZERO_TERMINATED(r[specimen]);
   238         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "5 a A 0x6"));
   239         specimen++;
   241         r[specimen] = cx_asprintf_a(alloc, "%o %#o %#o", 10, 10, 4);
   242         CX_TEST_ASSERT(r[specimen].length == 9);
   243         ASSERT_ZERO_TERMINATED(r[specimen]);
   244         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "12 012 04"));
   245         specimen++;
   247         r[specimen] = cx_asprintf_a(alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5);
   248         CX_TEST_ASSERT(r[specimen].length == 16);
   249         ASSERT_ZERO_TERMINATED(r[specimen]);
   250         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "01.50 1.50  1.50"));
   251         specimen++;
   253         r[specimen] = cx_asprintf_a(alloc, "'%*c'", 5, 'x');
   254         CX_TEST_ASSERT(r[specimen].length == 7);
   255         ASSERT_ZERO_TERMINATED(r[specimen]);
   256         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "'    x'"));
   257         specimen++;
   259         r[specimen] = cx_asprintf_a(alloc, "'%*c'", -5, 'x');
   260         CX_TEST_ASSERT(r[specimen].length == 7);
   261         ASSERT_ZERO_TERMINATED(r[specimen]);
   262         CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "'x    '"));
   263         specimen++;
   265         CX_TEST_ASSERT(specimen == specimen_count); // self-test
   267         for (int i = 0; i < specimen_count; i++) {
   268             cx_strfree_a(alloc, &r[i]);
   269         }
   270         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   271     }
   272     cx_testing_allocator_destroy(&talloc);
   273 }
   275 CX_TEST(test_asprintf_large_string) {
   276     unsigned len = cx_printf_sbo_size;
   277     char *aaa = malloc(len);
   278     char *bbb = malloc(len);
   279     char *expected = malloc(2*len+16);
   280     memset(aaa, 'a', len-1);
   281     aaa[len-1] = 0;
   282     memset(bbb, 'b', len-1);
   283     bbb[len-1] = 0;
   284     sprintf(expected, "After %s comes %s.", aaa, bbb);
   285     CX_TEST_DO {
   286         cxmutstr r = cx_asprintf("After %s comes %s.", aaa, bbb);
   287         CX_TEST_ASSERT(r.length == 2*len-2+14);
   288         ASSERT_ZERO_TERMINATED(r);
   289         CX_TEST_ASSERT(0 == strcmp(r.ptr, expected));
   290         cx_strfree(&r);
   291     }
   292     free(aaa);
   293     free(bbb);
   294     free(expected);
   295 }
   297 CX_TEST(test_sprintf_no_realloc) {
   298     char *buf = malloc(16);
   299     CxTestingAllocator talloc;
   300     cx_testing_allocator_init(&talloc);
   301     CxAllocator *alloc = &talloc.base;
   302     CX_TEST_DO {
   303         char *oldbuf = buf;
   304         size_t buflen = 16;
   305         size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 47, "string");
   306         CX_TEST_ASSERT(oldbuf == buf);
   307         CX_TEST_ASSERT(len == 14);
   308         CX_TEST_ASSERT(buflen == 16);
   309         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15));
   310         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   311     }
   312     cx_testing_allocator_destroy(&talloc);
   313     free(buf);
   314 }
   316 CX_TEST(test_sprintf_realloc) {
   317     CxTestingAllocator talloc;
   318     cx_testing_allocator_init(&talloc);
   319     CxAllocator *alloc = &talloc.base;
   320     char *buf = cxMalloc(alloc, 8);
   321     CX_TEST_DO {
   322         size_t buflen = 8;
   323         size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 47, "foobar");
   324         CX_TEST_ASSERT(len == 14);
   325         CX_TEST_ASSERT(buflen == 15);
   326         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 foobar", 15));
   327         cxFree(alloc, buf);
   328         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   329     }
   330     cx_testing_allocator_destroy(&talloc);
   331 }
   333 CX_TEST(test_sprintf_realloc_to_fit_terminator) {
   334     CxTestingAllocator talloc;
   335     cx_testing_allocator_init(&talloc);
   336     CxAllocator *alloc = &talloc.base;
   337     // make it so that only the zero-terminator does not fit
   338     char *buf = cxMalloc(alloc, 14);
   339     CX_TEST_DO {
   340         size_t buflen = 14;
   341         size_t len = cx_sprintf_a(alloc, &buf, &buflen, "Test %d %s", 13, "string");
   342         CX_TEST_ASSERT(len == 14);
   343         CX_TEST_ASSERT(buflen == 15);
   344         CX_TEST_ASSERT(0 == memcmp(buf, "Test 13 string", 15));
   345         cxFree(alloc, buf);
   346         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   347     }
   348     cx_testing_allocator_destroy(&talloc);
   349 }
   351 CX_TEST(test_sprintf_s_no_alloc) {
   352     char buf[16];
   353     CxTestingAllocator talloc;
   354     cx_testing_allocator_init(&talloc);
   355     CxAllocator *alloc = &talloc.base;
   356     CX_TEST_DO {
   357         char *str;
   358         size_t buflen = 16;
   359         size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str, "Test %d %s", 47, "string");
   360         CX_TEST_ASSERT(str == buf);
   361         CX_TEST_ASSERT(buflen == 16);
   362         CX_TEST_ASSERT(len == 14);
   363         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15));
   364         CX_TEST_ASSERT(0 == memcmp(str, "Test 47 string", 15));
   365         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   366     }
   367     cx_testing_allocator_destroy(&talloc);
   368 }
   370 CX_TEST(test_sprintf_s_alloc) {
   371     char buf[16];
   372     memcpy(buf, "0123456789abcdef", 16);
   373     CxTestingAllocator talloc;
   374     cx_testing_allocator_init(&talloc);
   375     CxAllocator *alloc = &talloc.base;
   376     CX_TEST_DO {
   377         char *str;
   378         size_t buflen = 16;
   379         size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str, "Hello %d %s", 4711, "larger string");
   380         CX_TEST_ASSERT(str != buf);
   381         CX_TEST_ASSERT(buflen == 25);
   382         CX_TEST_ASSERT(len == 24);
   383         CX_TEST_ASSERT(0 == memcmp(str, "Hello 4711 larger string", 25));
   384         cxFree(alloc, str);
   385         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   386     }
   387     cx_testing_allocator_destroy(&talloc);
   388 }
   390 CX_TEST(test_sprintf_s_alloc_to_fit_terminator) {
   391     char buf[16];
   392     memcpy(buf, "0123456789abcdef", 16);
   393     CxTestingAllocator talloc;
   394     cx_testing_allocator_init(&talloc);
   395     CxAllocator *alloc = &talloc.base;
   396     CX_TEST_DO {
   397         char *str;
   398         size_t buflen = 16;
   399         size_t len = cx_sprintf_sa(alloc, buf,&buflen, &str, "Hello %d %s", 112, "string");
   400         CX_TEST_ASSERT(str != buf);
   401         CX_TEST_ASSERT(len == 16);
   402         CX_TEST_ASSERT(buflen == 17);
   403         CX_TEST_ASSERT(0 == memcmp(str, "Hello 112 string", 17)); // include terminator
   404         cxFree(alloc, str);
   405         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   406     }
   407     cx_testing_allocator_destroy(&talloc);
   408 }
   410 CxTestSuite *cx_test_suite_printf(void) {
   411     CxTestSuite *suite = cx_test_suite_new("printf");
   413     cx_test_register(suite, test_bprintf);
   414     cx_test_register(suite, test_bprintf_large_string);
   415     cx_test_register(suite, test_bprintf_nocap);
   416     cx_test_register(suite, test_fprintf);
   417     cx_test_register(suite, test_asprintf);
   418     cx_test_register(suite, test_asprintf_large_string);
   419     cx_test_register(suite, test_sprintf_no_realloc);
   420     cx_test_register(suite, test_sprintf_realloc);
   421     cx_test_register(suite, test_sprintf_realloc_to_fit_terminator);
   422     cx_test_register(suite, test_sprintf_s_no_alloc);
   423     cx_test_register(suite, test_sprintf_s_alloc);
   424     cx_test_register(suite, test_sprintf_s_alloc_to_fit_terminator);
   426     return suite;
   427 }

mercurial