From 8e8c97c80acfe52838f208e5441f3013db0f76fb Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 9 Sep 2020 18:22:26 +0100 Subject: Improved testing --- .gitignore | 2 ++ Makefile | 6 ++++ test_gen.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unpack_test.c | 96 ++++++++++--------------------------------------- 4 files changed, 141 insertions(+), 77 deletions(-) create mode 100644 test_gen.c diff --git a/.gitignore b/.gitignore index 64c75c2..981c059 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.o *_test +*.inc +*_gen diff --git a/Makefile b/Makefile index 40e1cff..d8037f6 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,9 @@ # Copyright (C) 2020 Tomasz Kramkowski # SPDX-License-Identifier: MIT unpack_test: unpack_test.o unpack.o common.o trace.o +unpack_test.o: unpack_test.c pack.h trace.h common.h unpack_test.inc +trace.o: trace.c trace.h +common.o: common.c common.h +unpack_test.inc: test_gen + ./$< >$@ +test_gen: test_gen.o diff --git a/test_gen.c b/test_gen.c new file mode 100644 index 0000000..ca46672 --- /dev/null +++ b/test_gen.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020 Tomasz Kramkowski + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include +#include + +struct { + enum endian { BIG, LITTLE } e; + char *prefix; +} endian[] = { + { BIG, "" }, + { BIG, ">" }, + { LITTLE, "<" }, +}; + +char cchar(char c) +{ + if (c == '\0') return c; + if (isalnum(c)) return c; + return '_'; +} + +const char *cname(const char *s) +{ + static char ret[100]; + for (int i = 0; i < 99; i++) { + ret[i] = cchar(s[i]); + if (s[i] == '\0') break; + } + return ret; +} + +const char *u2bytes(enum endian e, int n, uintmax_t v) +{ + static char b[100]; + char *p = b; + + assert(n > 0 && n <= 8); + + for (int i = 0; i < n; i++) { + p += snprintf(p, b + sizeof(b) - p, "%s0x%x", i == 0 ? "" : ", ", + (v >> (e == LITTLE ? i : n - i - 1) * 8) & 0xff); + assert(p < b + sizeof(b)); + } + + return b; +} + +uintmax_t i2u(int n, intmax_t v) +{ + if (v >= 0) + return v; + + return (UINTMAX_MAX >> (sizeof (uintmax_t) * CHAR_BIT - n * 8)) + v + 1; +} + +const char *i2bytes(enum endian e, int n, intmax_t v) +{ + return u2bytes(e, n, i2u(n, v)); +} + +void generate_simple(FILE *out, char fmt, const char *type, intmax_t min, uintmax_t max, int size) +{ + unsigned char data[8]; + char *prefix; + bool sign; + + sign = islower(fmt); + prefix = sign ? "signed" : "unsigned"; + + assert(size <= sizeof data); + + fprintf(out, "TEST(%s_%s)\n", prefix, cname(type)); + fprintf(out, "{\n"); + fprintf(out, "\t%s %s %c = __LINE__;\n", prefix, type, fmt); + for (size_t e = 0; e < sizeof endian / sizeof endian[0]; e++) { + for (int i = sign ? -1 : 0; i <= 1; i++) { + fprintf(out, "\tCHECK_UNPACK(DATA(%s), \"%s%c\", &%c);\n", + i2bytes(endian[e].e, size, i), endian[e].prefix, fmt, fmt); + fprintf(out, "\tCHECK_EQUAL(PRIdMAX, (intmax_t)%c, INTMAX_C(%d));\n", fmt, i); + } + if (sign) { + fprintf(out, "\tCHECK_UNPACK(DATA(%s), \"%s%c\", &%c);\n", + i2bytes(endian[e].e, size, min), endian[e].prefix, fmt, fmt); + fprintf(out, "\tCHECK_EQUAL(PRIdMAX, (intmax_t)%c, INTMAX_C(%" PRIdMAX "));\n", fmt, min); + } + fprintf(out, "\tCHECK_UNPACK(DATA(%s), \"%s%c\", &%c);\n", + u2bytes(endian[e].e, size, max), endian[e].prefix, fmt, fmt); + fprintf(out, "\tCHECK_EQUAL(PRIuMAX, (uintmax_t)%c, UINTMAX_C(%" PRIuMAX "));\n", fmt, max); + } + fprintf(out, "\treturn true;\n"); + fprintf(out, "}\n"); +} + +int main(void) +{ + FILE *out = stdout; + generate_simple(out, 'b', "char", INTMAX_C( -128), UINTMAX_C( 127), 1); + generate_simple(out, 'B', "char", INTMAX_C( 0), UINTMAX_C( 255), 1); + generate_simple(out, 'h', "short", INTMAX_C( -32768), UINTMAX_C( 32767), 2); + generate_simple(out, 'H', "short", INTMAX_C( 0), UINTMAX_C( 65535), 2); + generate_simple(out, 'i', "int", INTMAX_C( -32768), UINTMAX_C( 32767), 2); + generate_simple(out, 'I', "int", INTMAX_C( 0), UINTMAX_C( 65535), 2); + generate_simple(out, 'l', "long", INTMAX_C( -2147483648), UINTMAX_C( 2147483647), 4); + generate_simple(out, 'L', "long", INTMAX_C( 0), UINTMAX_C( 4294967295), 4); + generate_simple(out, 'q', "long long", -INTMAX_C(9223372036854775807)-1, UINTMAX_C( 9223372036854775807), 8); + generate_simple(out, 'Q', "long long", INTMAX_C( 0), UINTMAX_C(18446744073709551615), 8); +} diff --git a/unpack_test.c b/unpack_test.c index 1dbc4ac..f89cd62 100644 --- a/unpack_test.c +++ b/unpack_test.c @@ -2,6 +2,8 @@ * Copyright (C) 2020 Tomasz Kramkowski * SPDX-License-Identifier: MIT */ +#include +#include #include #include @@ -21,91 +23,31 @@ struct test { #define CHECK(test) if (!(test)) { puts("! " #test); return false; } #define CHECK_UNPACK(data, fmt, ...) do { \ - enum pack_status s = unpack(data, fmt, __VA_ARGS__); \ - if (s != PACK_OK) { \ - printf(__FILE__ ":%d unpack(" #data ", " #fmt ", ...) -> %s (%d)\n", __LINE__, pack_strerror(s), s); \ + enum pack_status CHECK_UNPACK_s = unpack(data, fmt, __VA_ARGS__); \ + if (CHECK_UNPACK_s != PACK_OK) { \ + printf(__FILE__ ":%d unpack(" #data ", " #fmt ", ...) -> %s (%d)\n", __LINE__, pack_strerror(CHECK_UNPACK_s), CHECK_UNPACK_s); \ return false; \ } \ } while (0) -#define CHECK_EQUAL(a, b) if (a != b) { printf(__FILE__ ":%d %d != %d\n", __LINE__, a, b); return false; } +#define CHECK_EQUAL(f, a, b) if (a != b) { printf(__FILE__ ":%d %"f" != %"f"\n", __LINE__, a, b); return false; } -TEST(schar) -{ - signed char c = __LINE__; - fprintf(stderr, "Address of c: %p\n", (void *)&c); - CHECK_UNPACK(DATA(0), "b", &c); - CHECK_EQUAL(c, 0); - CHECK_UNPACK(DATA(1), "b", &c); - CHECK_EQUAL(c, 1); - CHECK_UNPACK(DATA(127), "b", &c); - CHECK_EQUAL(c, 127); - CHECK_UNPACK(DATA(255), "b", &c); - CHECK_EQUAL(c, -1); - CHECK_UNPACK(DATA(128), "b", &c); - CHECK_EQUAL(c, -128); - return true; -} - -TEST(uchar) -{ - unsigned char c = __LINE__; - fprintf(stderr, "Address of c: %p\n", (void *)&c); - CHECK_UNPACK(DATA(0), "B", &c); - CHECK_EQUAL(c, 0); - CHECK_UNPACK(DATA(1), "B", &c); - CHECK_EQUAL(c, 1); - CHECK_UNPACK(DATA(255), "B", &c); - CHECK_EQUAL(c, 255); - return true; -} - -TEST(sshort) -{ - short s = __LINE__; - fprintf(stderr, "Address of s: %p\n", (void *)&s); - CHECK_UNPACK(DATA(0, 0), "h", &s); - CHECK_EQUAL(s, 0); - CHECK_UNPACK(DATA(0, 0), ">h", &s); - CHECK_EQUAL(s, 0); - CHECK_UNPACK(DATA(0, 0), "h", &s); - CHECK_EQUAL(s, 1); - CHECK_UNPACK(DATA(1, 0), "h", &s); - CHECK_EQUAL(s, 32767); - CHECK_UNPACK(DATA(0xff, 0x7f), "h", &s); - CHECK_EQUAL(s, -1); - CHECK_UNPACK(DATA(0xff, 0xff), "h", &s); - CHECK_EQUAL(s, -32768); - CHECK_UNPACK(DATA(0x00, 0x80), "