tests/test_printf.c

Tue, 16 Jan 2024 23:13:01 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 16 Jan 2024 23:13:01 +0100
changeset 810
85859399a0cc
parent 805
26500fc24058
child 849
edb9f875b7f9
permissions
-rw-r--r--

add cx_sprintf() variants - fixes #353

     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 len = cx_sprintf_a(alloc, &buf, 16, "Test %d %s", 47, "string");
   305         CX_TEST_ASSERT(oldbuf == buf);
   306         CX_TEST_ASSERT(len == 14);
   307         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15));
   308         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   309     }
   310     cx_testing_allocator_destroy(&talloc);
   311     free(buf);
   312 }
   314 CX_TEST(test_sprintf_realloc) {
   315     CxTestingAllocator talloc;
   316     cx_testing_allocator_init(&talloc);
   317     CxAllocator *alloc = &talloc.base;
   318     char *buf = cxMalloc(alloc, 8);
   319     CX_TEST_DO {
   320         size_t len = cx_sprintf_a(alloc, &buf, 8, "Test %d %s", 47, "foobar");
   321         CX_TEST_ASSERT(len == 14);
   322         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 foobar", 15));
   323         cxFree(alloc, buf);
   324         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   325     }
   326     cx_testing_allocator_destroy(&talloc);
   327 }
   329 CX_TEST(test_sprintf_realloc_to_fit_terminator) {
   330     CxTestingAllocator talloc;
   331     cx_testing_allocator_init(&talloc);
   332     CxAllocator *alloc = &talloc.base;
   333     // make it so that only the zero-terminator does not fit
   334     char *buf = cxMalloc(alloc, 14);
   335     CX_TEST_DO {
   336         size_t len = cx_sprintf_a(alloc, &buf, 14, "Test %d %s", 13, "string");
   337         CX_TEST_ASSERT(len == 14);
   338         CX_TEST_ASSERT(0 == memcmp(buf, "Test 13 string", 15));
   339         cxFree(alloc, buf);
   340         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   341     }
   342     cx_testing_allocator_destroy(&talloc);
   343 }
   345 CX_TEST(test_sprintf_s_no_alloc) {
   346     char buf[16];
   347     CxTestingAllocator talloc;
   348     cx_testing_allocator_init(&talloc);
   349     CxAllocator *alloc = &talloc.base;
   350     CX_TEST_DO {
   351         char *str;
   352         size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Test %d %s", 47, "string");
   353         CX_TEST_ASSERT(str == buf);
   354         CX_TEST_ASSERT(len == 14);
   355         CX_TEST_ASSERT(0 == memcmp(buf, "Test 47 string", 15));
   356         CX_TEST_ASSERT(0 == memcmp(str, "Test 47 string", 15));
   357         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   358     }
   359     cx_testing_allocator_destroy(&talloc);
   360 }
   362 CX_TEST(test_sprintf_s_alloc) {
   363     char buf[16];
   364     memcpy(buf, "0123456789abcdef", 16);
   365     CxTestingAllocator talloc;
   366     cx_testing_allocator_init(&talloc);
   367     CxAllocator *alloc = &talloc.base;
   368     CX_TEST_DO {
   369         char *str;
   370         size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Hello %d %s", 4711, "larger string");
   371         CX_TEST_ASSERT(str != buf);
   372         CX_TEST_ASSERT(len == 24);
   373         CX_TEST_ASSERT(0 == memcmp(str, "Hello 4711 larger string", 25));
   374         cxFree(alloc, str);
   375         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   376     }
   377     cx_testing_allocator_destroy(&talloc);
   378 }
   380 CX_TEST(test_sprintf_s_alloc_to_fit_terminator) {
   381     char buf[16];
   382     memcpy(buf, "0123456789abcdef", 16);
   383     CxTestingAllocator talloc;
   384     cx_testing_allocator_init(&talloc);
   385     CxAllocator *alloc = &talloc.base;
   386     CX_TEST_DO {
   387         char *str;
   388         size_t len = cx_sprintf_sa(alloc, buf, 16, &str, "Hello %d %s", 112, "string");
   389         CX_TEST_ASSERT(str != buf);
   390         CX_TEST_ASSERT(len == 16);
   391         CX_TEST_ASSERT(0 == memcmp(str, "Hello 112 string", 17)); // include terminator
   392         cxFree(alloc, str);
   393         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
   394     }
   395     cx_testing_allocator_destroy(&talloc);
   396 }
   398 CxTestSuite *cx_test_suite_printf(void) {
   399     CxTestSuite *suite = cx_test_suite_new("printf");
   401     cx_test_register(suite, test_bprintf);
   402     cx_test_register(suite, test_bprintf_large_string);
   403     cx_test_register(suite, test_bprintf_nocap);
   404     cx_test_register(suite, test_fprintf);
   405     cx_test_register(suite, test_asprintf);
   406     cx_test_register(suite, test_asprintf_large_string);
   407     cx_test_register(suite, test_sprintf_no_realloc);
   408     cx_test_register(suite, test_sprintf_realloc);
   409     cx_test_register(suite, test_sprintf_realloc_to_fit_terminator);
   410     cx_test_register(suite, test_sprintf_s_no_alloc);
   411     cx_test_register(suite, test_sprintf_s_alloc);
   412     cx_test_register(suite, test_sprintf_s_alloc_to_fit_terminator);
   414     return suite;
   415 }

mercurial