From 2a51a9c9ac7d6ab122ab6a8d9ead92b2bba0210c Mon Sep 17 00:00:00 2001 From: Lephe Date: Wed, 17 Jun 2020 16:10:03 +0200 Subject: [PATCH] actual interface for the printf test --- include/gintctl/gint.h | 3 - include/gintctl/libs.h | 3 + src/gint/printf.c | 120 --------------------------- src/gintctl.c | 5 +- src/libs/printf.c | 180 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+), 125 deletions(-) delete mode 100644 src/gint/printf.c create mode 100644 src/libs/printf.c diff --git a/include/gintctl/gint.h b/include/gintctl/gint.h index 2649f39..72887f1 100644 --- a/include/gintctl/gint.h +++ b/include/gintctl/gint.h @@ -49,7 +49,4 @@ void gintctl_gint_grayrender(void); #endif /* FX9860G */ -/* gintctl_gint_printf(): printf() function */ -void gintctl_gint_printf(void); - #endif /* GINTCTL_GINT */ diff --git a/include/gintctl/libs.h b/include/gintctl/libs.h index 8aa01e8..b5fb292 100644 --- a/include/gintctl/libs.h +++ b/include/gintctl/libs.h @@ -8,6 +8,9 @@ /* gintctl_libs_tinymt(): TinyMT32 random number generation */ void gintctl_libs_tinymt(void); +/* gintctl_libs_printf(): printf() function */ +void gintctl_libs_printf(void); + /* gintctl_libs_libimg(): libimg-based rendering and image transform */ void gintctl_libs_libimg(void); diff --git a/src/gint/printf.c b/src/gint/printf.c deleted file mode 100644 index cb7affb..0000000 --- a/src/gint/printf.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -static int passed = 0; -static int total = 0; - -static struct { - char const *format; - char const *expected; -} fails[10]; - -static void check(char const *expected, char const *format, ...) -{ - va_list args; - va_start(args, format); - - char buffer[128]; - vsnprintf(buffer, 128, format, args); - - va_end(args); - - total++; - - if(!strcmp(buffer, expected)) - { - passed++; - } - else if(total - passed <= 10) - { - fails[total - passed - 1].format = format; - fails[total - passed - 1].expected = expected; - } -} - -static void check_all(void) -{ - passed = 0; - total = 0; - - /* Base cases with length and precision */ - check("-849", "%d", -849); - check(" 78372", "%7i", 78372); - check("65536", "%3d", 65536); - check(" 0017", "%6.4d", 17); - check(" -1876", "%6.3d", -1876); - - /* Sign */ - check("+15", "%+i", 15); - check(" 78372", "% 7i", 78372); - check(" 65536", "% d", 65536); - - /* Alignment */ - check("0017 ", "%-6.4d", 17); - check("+0017 ", "%-+6.4i", 17); - - /* Bases */ - check("3255", "%d", 0xcb7); - check("cb7", "%x", 0xcb7); - check("CB7", "%X", 0xcb7); - check("6267", "%o", 0xcb7); - - /* Argument size */ - check("10000000000", "%lld", 10000000000ll); - check("123456789ab", "%llx", 0x123456789abull); - - /* Alternative prefixes */ - check("0x7b", "%#x", 0x7b); - check("0X7B", "%#X", 0x7b); - check("0377", "%#o", 255); - - /* Pointers */ - check("0xa44b0000", "%p", (void *)0xa44b0000); - - /* Characters and strings */ - check("HellWrld!", "%s", "HellWrld!"); - check("Hello ", "%-8.5s", "Hello, World!"); - check("d", "%c", 100); - check(" #", "%6c", '#'); -} - -/* gintctl_gint_printf(): printf() function */ -void gintctl_gint_printf(void) -{ - int key = 0; - while(key != KEY_EXIT) - { - dclear(C_WHITE); - - #ifdef FX9860G - row_print(1, 1, "printf() tests"); - row_print(3, 1, "passed: %d/%d", passed, total); - #endif - - #ifdef FXCG50 - row_title("Unit tests for the printf() family"); - - row_print(1, 1, "Passed: %d/%d", passed, total); - - for(int i = 0; i < 10 && i <= total - passed - 1; i++) - { - int y = 22 + 14 * (i + 2); - dtext(6, y, fails[i].format, C_BLACK, C_NONE); - dtext(86, y, fails[i].expected, C_BLACK, C_NONE); - } - - fkey_button(1, "RUN"); - #endif - - dupdate(); - - key = getkey().key; - if(key == KEY_F1) check_all(); - } -} diff --git a/src/gintctl.c b/src/gintctl.c index 11b5d99..05d3b61 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -53,7 +53,6 @@ struct menu menu_gint = { { "Gray engine", gintctl_gint_gray }, { "Gray rendering", gintctl_gint_grayrender }, #endif - { "printf family", gintctl_gint_printf }, { NULL, NULL }, }}; @@ -72,7 +71,9 @@ struct menu menu_libs = { { "libc: " _("TinyMT32", "TinyMT random number generation"), gintctl_libs_tinymt }, - { "libimg" _(""," image transforms"), + { "libc: " _("printf family", "Formatted printing functions"), + gintctl_libs_printf }, + { "libimg" _("",": Image transforms"), gintctl_libs_libimg }, { NULL, NULL }, }}; diff --git a/src/libs/printf.c b/src/libs/printf.c new file mode 100644 index 0000000..eebba06 --- /dev/null +++ b/src/libs/printf.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define SCROLL_HEIGHT _(8,12) + +struct printf_test { + char const *format; + + /* Type, argument, string, answer, passed are set by macros below */ + enum { TYPE_I32, TYPE_U32, TYPE_STR, TYPE_PTR, TYPE_U64 } type; + union { + int i32; + uint32_t u32; + char const *str; + void *ptr; + uint64_t u64; + }; + char const *argument_as_string; + + char answer[32]; + int passed; + char const *solution; +}; + +#define I32(i) TYPE_I32, { .i32 = i }, #i, "", 0 +#define U32(u) TYPE_U32, { .u32 = u }, #u, "", 0 +#define STR(s) TYPE_STR, { .str = s }, #s, "", 0 +#define PTR(p) TYPE_PTR, { .ptr = (void *)p }, #p, "", 0 +#define U64(u) TYPE_U64, { .u64 = u }, #u, "", 0 + +static struct printf_test tests[] = { + /* Base cases with length and precision */ + { "%d", I32(-849), "-849" }, + { "%7i", I32(78372), " 78372" }, + { "%3d", I32(65536), "65536" }, + { "%6.4d", I32(17), " 0017" }, + { "%6.3d", I32(-1876), " -1876" }, + /* Sign */ + { "%+i", I32(15), "+15" }, + { "% 7i", I32(78372), " 78372" }, + { "% d", I32(65536), " 65536" }, + /* Alignment */ + { "%-6.4d", I32(17), "0017 " }, + { "%-+6.4i", I32(17), "+0017 " }, + /* Bases */ + { "%d", I32(0xcb7), "3255" }, + { "%x", U32(0xcb7), "cb7" }, + { "%X", U32(0xcb7), "CB7" }, + { "%o", U32(0xcb7), "6267" }, + /* Argument size */ + { "%lld", U64(10000000000ll), "10000000000" }, + { "%llx", U64(0x123456789abull), "123456789ab" }, + /* Alternative prefixes */ + { "%#x", U32(0x7b), "0x7b" }, + { "%#X", U32(0x7b), "0X7B" }, + { "%#o", U32(255), "0377" }, + /* Pointers */ + { "%p", PTR(0xa44b0000), "0xa44b0000" }, + /* Characters and strings */ + { "%s", STR("HellWrld!"), "HellWrld!" }, + { "%-8.5s", STR("Hello, World!"), "Hello " }, + { "%c", I32(100), "d" }, + { "%6c", I32('#'), " #", }, + /* NULL terminator */ + { NULL } +}; + +static void run_tests(struct printf_test *tests) +{ + for(int i = 0; tests[i].format; i++) + { + struct printf_test *t = &tests[i]; + + #define run(TYPE, field) case TYPE: \ + snprintf(t->answer, 32, t->format, t->field); \ + break; + + switch(t->type) + { + run(TYPE_I32, i32) + run(TYPE_U32, u32) + run(TYPE_STR, str) + run(TYPE_PTR, ptr) + run(TYPE_U64, u64) + } + + t->passed = !strcmp(t->answer, t->solution); + } +} + +static void draw(struct printf_test const *tests, int offset) +{ + int passed=0, total=0; + for(int i = 0; tests[i].format; i++) + { + passed += (tests[i].passed); + total++; + } + + dclear(C_WHITE); + + #ifdef FX9860G + extern font_t font_hexa; + font_t *old_font = dfont(&font_hexa); + + dprint( 1, 0, C_BLACK, C_NONE, "ID"); + dprint(13, 0, C_BLACK, C_NONE, "Format"); + dprint(43, 0, C_BLACK, C_NONE, "Output"); + dprint(91, 0, C_BLACK, C_NONE, "Valid"); + + for(int i = 0; i < SCROLL_HEIGHT; i++) + { + struct printf_test const *t = &tests[offset+i]; + int y = (i+1) * 6; + dprint( 1, y, C_BLACK, C_NONE, "%d", offset+i+1); + dprint(13, y, C_BLACK, C_NONE, "%s", t->format); + dprint(43, y, C_BLACK, C_NONE, "%s", t->answer); + dprint(91, y, C_BLACK, C_NONE, "%s", t->passed?"Ok":"Err"); + } + + dfont(old_font); + row_print(8, 1, "Passed %d of %d.", passed, total); + #endif + + #ifdef FXCG50 + row_title("libc: Formatted printing functions"); + + row_print(1, 2, "ID"); + row_print(1, 5, "Format"); + row_print(1, 13, "Argument"); + row_print(1, 29, "Answer"); + + for(int i = 0; i < SCROLL_HEIGHT; i++) + { + struct printf_test const *t = &tests[offset+i]; + row_print(i+2, 2, "%d", offset+i+1); + row_print(i+2, 5, "%s", t->format); + row_print(i+2, 13, "%s", t->argument_as_string); + + int fg = t->passed ? C_RGB(0,31,0) : C_RGB(31,0,0); + row_print_color(i+2, 29, fg, C_NONE, "%s", t->solution); + } + + row_print(14, 1, "Passed: %d/%d", passed, total); + #endif + + if(offset > 0) triangle_up(_(7,38)); + if(offset < total - SCROLL_HEIGHT) triangle_down(_(49,192)); + + dupdate(); +} + +/* gintctl_libs_printf(): printf() function */ +void gintctl_libs_printf(void) +{ + key_event_t ev; + int key=0, total=0, offset=0; + for(int i = 0; tests[i].format; i++) total++; + + run_tests(tests); + + while(key != KEY_EXIT) + { + draw(tests, offset); + key = (ev = getkey()).key; + + if(key == KEY_UP && offset > 0) offset--; + if(key == KEY_UP && ev.shift) offset = 0; + if(key == KEY_DOWN && offset < total - SCROLL_HEIGHT) offset++; + if(key == KEY_DOWN && ev.shift) offset = total - SCROLL_HEIGHT; + } +}