From 14a6924d2fe27083556e323ec7efdee7567d3a4f Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 26 Aug 2026 21:02:53 +0300 Subject: add simple string buffer + Has short-string optimization, which seems to trigger an erroneous warning about out-of-bounds writes to unions. Should probably report upstream. --- tests/sp.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/sp.c (limited to 'tests/sp.c') diff --git a/tests/sp.c b/tests/sp.c new file mode 100644 index 0000000..369e376 --- /dev/null +++ b/tests/sp.c @@ -0,0 +1,134 @@ +#include "test.h" + +/* all optional */ +#define SP_MALLOC mallocc +#define SP_REALLOC reallocc +#define SP_FREE free +#include + +/* including default name is fine */ +#include + +/* separate string type, can be defined in addition to the default type. The + * default type can be included multiple times, but specially-named types + * cannot. */ +#define SP_NAME second +#define SP_MALLOC mallocc +#define SP_REALLOC reallocc +#define SP_FREE free +#include + +int main() +{ +#if defined(COVERAGE) + assert(!covsrv_init()); + atexit(covsrv_destroy); +#endif + + struct sp sp = sp_create(); + + /* should be in static buffer, cannot fail + * (though the user should probably assume that appending can always + * fail) */ + assert(!sp_append_str(&sp, "123")); + + /* don't use sp.b directly, prefer sp_str, but this is fine for testing */ + assert(strcmp(sp.b, "123") == 0); + + /* test static iteration */ + foreach(sp, c, &sp) { + switch (c.i) { + case 0: assert(*c.p == '1'); break; + case 1: assert(*c.p == '2'); break; + case 2: assert(*c.p == '3'); break; + default: assert(0 && "weird iteration"); + } + } + + /* now we should switch over to the dynamic buffer, as we have more + * characters than can fit in any regular pointer type (3 for 32bit, 7 + * for 64 bit, 15 for stuff like Cheri), might fail */ + if (sp_append_str(&sp, "4567890ABCDEFG")) { + fprintf(stderr, "failed appending to string buffer"); + sp_destroy(&sp); + return -1; + } + + /* same deal, check that we're using the dynamic buffer */ + assert(strcmp(sp.p, "1234567890ABCDEFG") == 0); + + /* test dynamic iteration */ + foreach(sp, c, &sp) { + switch (c.i) { + case 0: assert(*c.p == '1'); break; + case 1: assert(*c.p == '2'); break; + case 2: assert(*c.p == '3'); break; + case 3: assert(*c.p == '4'); break; + case 4: assert(*c.p == '5'); break; + case 5: assert(*c.p == '6'); break; + case 6: assert(*c.p == '7'); break; + case 7: assert(*c.p == '8'); break; + case 8: assert(*c.p == '9'); break; + case 9: assert(*c.p == '0'); break; + case 10: assert(*c.p == 'A'); break; + case 11: assert(*c.p == 'B'); break; + case 12: assert(*c.p == 'C'); break; + case 13: assert(*c.p == 'D'); break; + case 14: assert(*c.p == 'E'); break; + case 15: assert(*c.p == 'F'); break; + case 16: assert(*c.p == 'G'); break; + case 17: assert(*c.p == 'H'); break; + default: assert(0 && "weird iteration"); + } + } + + /* 'reset' string */ + sp_destroy(&sp); + + /* test formatting functions */ + sp = sp_create(); + + /* static formatting */ + for (int i = 1; i < 4; ++i) + assert(!sp_append_fmt(&sp, "%d", i)); + + assert(strcmp(sp.b, "123") == 0); + + /* dynamic formatting */ + for (int i = 4; i < 15; ++i) + if (sp_append_fmt(&sp, "%d", i)) { + fprintf(stderr, "failed formatting input\n"); + sp_destroy(&sp); + return -1; + } + + assert(strcmp(sp.p, "1234567891011121314") == 0); + sp_destroy(&sp); + + /* do some benchmarking, oh yeah! */ + struct second sec = second_create(); + for (int i = 0; i < ITER; ++i) + if (second_append_str(&sec, "BENCHMARK, FUCK YEAH\n")) { + fprintf(stderr, "failed when stressing append\n"); + second_destroy(&sec); + return -1; + } + + /* hmm, come to think of it, foreach_line or something along those lines + * might be pretty neat? */ + + second_destroy(&sec); + + sec = second_create(); + for (int i = 0; i < ITER; ++i) + if (second_append_fmt(&sec, "I'm in iteration %d!\n", i)) { + fprintf(stderr, "failed when stressing fmt\n"); + second_destroy(&sec); + return -1; + } + + second_destroy(&sec); + + /* all done! */ + return 0; +} -- cgit v1.3