1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tests/test_printf.c Fri Dec 29 17:27:14 2023 +0100 1.3 @@ -0,0 +1,305 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2023 Mike Becker, Olaf Wintermann All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "cx/test.h" 1.33 +#include "util_allocator.h" 1.34 + 1.35 +#include "cx/printf.h" 1.36 +#include "cx/buffer.h" 1.37 + 1.38 +#define ASSERT_ZERO_TERMINATED(str) CX_TEST_ASSERTM((str).ptr[(str).length] == '\0', \ 1.39 + #str " is not zero terminated") 1.40 + 1.41 +static size_t test_printf_write_func( 1.42 + void const *src, 1.43 + size_t esize, 1.44 + size_t ecount, 1.45 + void *target 1.46 +) { 1.47 + memcpy(target, src, esize * ecount); 1.48 + return esize * ecount; 1.49 +} 1.50 + 1.51 +CX_TEST(test_bprintf) { 1.52 + CxTestingAllocator talloc; 1.53 + cx_testing_allocator_init(&talloc); 1.54 + CxAllocator *alloc = &talloc.base; 1.55 + CX_TEST_DO { 1.56 + CxBuffer buf; 1.57 + cxBufferInit(&buf, NULL, 64, alloc, 0); 1.58 + size_t r = cx_bprintf(&buf, "This %s aged %u years in a %2XSK.", "Test", 10, 0xca); 1.59 + CX_TEST_ASSERT(r == 34); 1.60 + CX_TEST_ASSERT(buf.size == 34); 1.61 + buf.space[r] = '\0'; 1.62 + CX_TEST_ASSERT(0 == strcmp(buf.space, "This Test aged 10 years in a CASK.")); 1.63 + cxBufferDestroy(&buf); 1.64 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 1.65 + } 1.66 + cx_testing_allocator_destroy(&talloc); 1.67 +} 1.68 + 1.69 +CX_TEST(test_bprintf_large_string) { 1.70 + CxTestingAllocator talloc; 1.71 + cx_testing_allocator_init(&talloc); 1.72 + CxAllocator *alloc = &talloc.base; 1.73 + char *aaa = malloc(512); 1.74 + char *bbb = malloc(512); 1.75 + char *expected = malloc(1040); 1.76 + memset(aaa, 'a', 511); 1.77 + aaa[511] = 0; 1.78 + memset(bbb, 'b', 511); 1.79 + bbb[511] = 0; 1.80 + sprintf(expected, "After %s comes %s.", aaa, bbb); 1.81 + CX_TEST_DO { 1.82 + CxBuffer buf; 1.83 + cxBufferInit(&buf, NULL, 64, alloc, CX_BUFFER_AUTO_EXTEND); 1.84 + size_t r = cx_bprintf(&buf, "After %s comes %s.", aaa, bbb); 1.85 + CX_TEST_ASSERT(r == 1036); 1.86 + CX_TEST_ASSERT(buf.size == 1036); 1.87 + cxBufferPut(&buf, 0); 1.88 + CX_TEST_ASSERT(0 == strcmp(expected, buf.space)); 1.89 + cxBufferDestroy(&buf); 1.90 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 1.91 + } 1.92 + free(aaa); 1.93 + free(bbb); 1.94 + free(expected); 1.95 + cx_testing_allocator_destroy(&talloc); 1.96 +} 1.97 + 1.98 +CX_TEST(test_bprintf_nocap) { 1.99 + CxTestingAllocator talloc; 1.100 + cx_testing_allocator_init(&talloc); 1.101 + CxAllocator *alloc = &talloc.base; 1.102 + char space[20]; 1.103 + memset(space, 'a', 20); 1.104 + CX_TEST_DO { 1.105 + CxBuffer buf; 1.106 + cxBufferInit(&buf, space, 16, alloc, 0); 1.107 + size_t r = cx_bprintf(&buf, "Hello %s with more than %d chars.", "string", 16); 1.108 + CX_TEST_ASSERT(r == 16); 1.109 + CX_TEST_ASSERT(buf.size == 16); 1.110 + CX_TEST_ASSERT(0 == memcmp(space, "Hello string witaaaa", 20)); 1.111 + cxBufferDestroy(&buf); 1.112 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 1.113 + } 1.114 + cx_testing_allocator_destroy(&talloc); 1.115 +} 1.116 + 1.117 +CX_TEST(test_fprintf) { 1.118 + char const *h = "Hello"; 1.119 + char buf[32]; 1.120 + size_t r; 1.121 + CX_TEST_DO { 1.122 + r = cx_fprintf(buf, test_printf_write_func, "teststring"); 1.123 + CX_TEST_ASSERT(r == 10); 1.124 + CX_TEST_ASSERT(0 == memcmp(buf, "teststring", r)); 1.125 + 1.126 + r = cx_fprintf(buf, test_printf_write_func, "[%10s]", h); 1.127 + CX_TEST_ASSERT(r == 12); 1.128 + CX_TEST_ASSERT(0 == memcmp(buf, "[ Hello]", r)); 1.129 + 1.130 + r = cx_fprintf(buf, test_printf_write_func, "[%-10s]", h); 1.131 + CX_TEST_ASSERT(r == 12); 1.132 + CX_TEST_ASSERT(0 == memcmp(buf, "[Hello ]", r)); 1.133 + 1.134 + r = cx_fprintf(buf, test_printf_write_func, "[%*s]", 10, h); 1.135 + CX_TEST_ASSERT(r == 12); 1.136 + CX_TEST_ASSERT(0 == memcmp(buf, "[ Hello]", r)); 1.137 + 1.138 + r = cx_fprintf(buf, test_printf_write_func, "[%-10.*s]", 4, h); 1.139 + CX_TEST_ASSERT(r == 12); 1.140 + CX_TEST_ASSERT(0 == memcmp(buf, "[Hell ]", r)); 1.141 + 1.142 + r = cx_fprintf(buf, test_printf_write_func, "[%-*.*s]", 10, 4, h); 1.143 + CX_TEST_ASSERT(r == 12); 1.144 + CX_TEST_ASSERT(0 == memcmp(buf, "[Hell ]", r)); 1.145 + 1.146 + r = cx_fprintf(buf, test_printf_write_func, "%c", 'A'); 1.147 + CX_TEST_ASSERT(r == 1); 1.148 + CX_TEST_ASSERT(0 == memcmp(buf, "A", r)); 1.149 + 1.150 + r = cx_fprintf(buf, test_printf_write_func, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4); 1.151 + CX_TEST_ASSERT(r == 19); 1.152 + CX_TEST_ASSERT(0 == memcmp(buf, "1 2 000003 0 +4 -4", r)); 1.153 + 1.154 + r = cx_fprintf(buf, test_printf_write_func, "%x %x %X %#x", 5, 10, 10, 6); 1.155 + CX_TEST_ASSERT(r == 9); 1.156 + CX_TEST_ASSERT(0 == memcmp(buf, "5 a A 0x6", r)); 1.157 + 1.158 + r = cx_fprintf(buf, test_printf_write_func, "%o %#o %#o", 10, 10, 4); 1.159 + CX_TEST_ASSERT(r == 9); 1.160 + CX_TEST_ASSERT(0 == memcmp(buf, "12 012 04", r)); 1.161 + 1.162 + r = cx_fprintf(buf, test_printf_write_func, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5); 1.163 + CX_TEST_ASSERT(r == 16); 1.164 + CX_TEST_ASSERT(0 == memcmp(buf, "01.50 1.50 1.50", r)); 1.165 + 1.166 + r = cx_fprintf(buf, test_printf_write_func, "'%*c'", 5, 'x'); 1.167 + CX_TEST_ASSERT(r == 7); 1.168 + CX_TEST_ASSERT(0 == memcmp(buf, "' x'", r)); 1.169 + 1.170 + r = cx_fprintf(buf, test_printf_write_func, "'%*c'", -5, 'x'); 1.171 + CX_TEST_ASSERT(r == 7); 1.172 + CX_TEST_ASSERT(0 == memcmp(buf, "'x '", r)); 1.173 + } 1.174 +} 1.175 + 1.176 +CX_TEST(test_asprintf) { 1.177 + CxTestingAllocator talloc; 1.178 + cx_testing_allocator_init(&talloc); 1.179 + CxAllocator *alloc = &talloc.base; 1.180 + 1.181 + char const *h = "Hello"; 1.182 + 1.183 + int const specimen_count = 13; 1.184 + cxmutstr r[specimen_count]; 1.185 + int specimen = 0; 1.186 + 1.187 + CX_TEST_DO { 1.188 + r[specimen] = cx_asprintf_a(alloc, "teststring"); 1.189 + CX_TEST_ASSERT(r[specimen].length == 10); 1.190 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.191 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "teststring")); 1.192 + specimen++; 1.193 + 1.194 + r[specimen] = cx_asprintf_a(alloc, "[%10s]", h); 1.195 + CX_TEST_ASSERT(r[specimen].length == 12); 1.196 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.197 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[ Hello]")); 1.198 + specimen++; 1.199 + 1.200 + r[specimen] = cx_asprintf_a(alloc, "[%-10s]", h); 1.201 + CX_TEST_ASSERT(r[specimen].length == 12); 1.202 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.203 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hello ]")); 1.204 + specimen++; 1.205 + 1.206 + r[specimen] = cx_asprintf_a(alloc, "[%*s]", 10, h); 1.207 + CX_TEST_ASSERT(r[specimen].length == 12); 1.208 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.209 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[ Hello]")); 1.210 + specimen++; 1.211 + 1.212 + r[specimen] = cx_asprintf_a(alloc, "[%-10.*s]", 4, h); 1.213 + CX_TEST_ASSERT(r[specimen].length == 12); 1.214 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.215 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hell ]")); 1.216 + specimen++; 1.217 + 1.218 + r[specimen] = cx_asprintf_a(alloc, "[%-*.*s]", 10, 4, h); 1.219 + CX_TEST_ASSERT(r[specimen].length == 12); 1.220 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.221 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "[Hell ]")); 1.222 + specimen++; 1.223 + 1.224 + r[specimen] = cx_asprintf_a(alloc, "%c", 'A'); 1.225 + CX_TEST_ASSERT(r[specimen].length == 1); 1.226 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.227 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "A")); 1.228 + specimen++; 1.229 + 1.230 + r[specimen] = cx_asprintf_a(alloc, "%i %d %.6i %i %.0i %+i %i", 1, 2, 3, 0, 0, 4, -4); 1.231 + CX_TEST_ASSERT(r[specimen].length == 19); 1.232 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.233 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "1 2 000003 0 +4 -4")); 1.234 + specimen++; 1.235 + 1.236 + r[specimen] = cx_asprintf_a(alloc, "%x %x %X %#x", 5, 10, 10, 6); 1.237 + CX_TEST_ASSERT(r[specimen].length == 9); 1.238 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.239 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "5 a A 0x6")); 1.240 + specimen++; 1.241 + 1.242 + r[specimen] = cx_asprintf_a(alloc, "%o %#o %#o", 10, 10, 4); 1.243 + CX_TEST_ASSERT(r[specimen].length == 9); 1.244 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.245 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "12 012 04")); 1.246 + specimen++; 1.247 + 1.248 + r[specimen] = cx_asprintf_a(alloc, "%05.2f %.2f %5.2f", 1.5, 1.5, 1.5); 1.249 + CX_TEST_ASSERT(r[specimen].length == 16); 1.250 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.251 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "01.50 1.50 1.50")); 1.252 + specimen++; 1.253 + 1.254 + r[specimen] = cx_asprintf_a(alloc, "'%*c'", 5, 'x'); 1.255 + CX_TEST_ASSERT(r[specimen].length == 7); 1.256 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.257 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "' x'")); 1.258 + specimen++; 1.259 + 1.260 + r[specimen] = cx_asprintf_a(alloc, "'%*c'", -5, 'x'); 1.261 + CX_TEST_ASSERT(r[specimen].length == 7); 1.262 + ASSERT_ZERO_TERMINATED(r[specimen]); 1.263 + CX_TEST_ASSERT(0 == strcmp(r[specimen].ptr, "'x '")); 1.264 + specimen++; 1.265 + 1.266 + CX_TEST_ASSERT(specimen == specimen_count); // self-test 1.267 + 1.268 + for (int i = 0; i < specimen_count; i++) { 1.269 + cx_strfree_a(alloc, &r[i]); 1.270 + } 1.271 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 1.272 + } 1.273 + cx_testing_allocator_destroy(&talloc); 1.274 +} 1.275 + 1.276 +CX_TEST(test_asprintf_large_string) { 1.277 + char *aaa = malloc(512); 1.278 + char *bbb = malloc(512); 1.279 + char *expected = malloc(1040); 1.280 + memset(aaa, 'a', 511); 1.281 + aaa[511] = 0; 1.282 + memset(bbb, 'b', 511); 1.283 + bbb[511] = 0; 1.284 + sprintf(expected, "After %s comes %s.", aaa, bbb); 1.285 + CX_TEST_DO { 1.286 + cxmutstr r = cx_asprintf("After %s comes %s.", aaa, bbb); 1.287 + CX_TEST_ASSERT(r.length == 1036); 1.288 + ASSERT_ZERO_TERMINATED(r); 1.289 + CX_TEST_ASSERT(0 == strcmp(r.ptr, expected)); 1.290 + cx_strfree(&r); 1.291 + } 1.292 + free(aaa); 1.293 + free(bbb); 1.294 + free(expected); 1.295 +} 1.296 + 1.297 +CxTestSuite *cx_test_suite_printf(void) { 1.298 + CxTestSuite *suite = cx_test_suite_new("printf"); 1.299 + 1.300 + cx_test_register(suite, test_bprintf); 1.301 + cx_test_register(suite, test_bprintf_large_string); 1.302 + cx_test_register(suite, test_bprintf_nocap); 1.303 + cx_test_register(suite, test_fprintf); 1.304 + cx_test_register(suite, test_asprintf); 1.305 + cx_test_register(suite, test_asprintf_large_string); 1.306 + 1.307 + return suite; 1.308 +}