#include #include #include #include #include #include "msgpack.h" // fprintf to logfp, but doesn't // move the file position indicator static FILE *logfp; #define logprintf(...) \ do { \ long pos = ftell(logfp); \ fseek(logfp, 0, SEEK_END); \ fprintf(logfp, __VA_ARGS__); \ fseek(logfp, pos, SEEK_SET); \ } while(0) #define _IN " " #define _assert1(c) _assert2(c, ;) #define _assert2(c, b) _assert3(#c, c, b) #define _assert3(n, c, b) \ do { \ if(!(c)) { \ logprintf("Assertion error '%s' in %s:%d\n", n, __FILE__, __LINE__); \ b; \ failed_asserts++; \ } \ } while (0); #define _logvar2(v, fmt) _logvar3(v, v, fmt) #define _logvar3(n, v, fmt) logprintf(_IN #n" = "fmt"\n", v) #define _logbuf3(b, l, fmt) _logbuf4(b, b, l, fmt) #define _logbuf4(n, b, l, fmt) \ do { \ logprintf(_IN #n" = { "fmt, b[0]); \ for(size_t i = 1; i < l; i++) \ logprintf(", "fmt, b[i]); \ logprintf(" }\n"); \ } while(0) #define OVERLOAD_MACRO_4(_1, _2, _3, _4, NAME, ...) NAME #define assert(...) OVERLOAD_MACRO_4(__VA_ARGS__, _, _assert3, _assert2, _assert1) (__VA_ARGS__) #define logvar(...) OVERLOAD_MACRO_4(__VA_ARGS__, _, _logvar3, _logvar2, _) (__VA_ARGS__) #define logbuf(...) OVERLOAD_MACRO_4(__VA_ARGS__, _logbuf4, _logbuf3, _, _) (__VA_ARGS__) #define logbytes(...) logbuf(__VA_ARGS__, "0x%hhx") // copy source fp from its file position indicator // to dest fp using sendfile (logfprintf is for that) static int fsendfile(FILE *dest, FILE *source) { fflush(dest); fflush(source); long cur = ftell(source); fseek(source, 0, SEEK_END); long end = ftell(source); int fd = fileno(source); return sendfile(fileno(dest), fd, &cur, end - cur); } static int passed_test_counter; static int failed_test_counter; static int failed_asserts; #define check_condition(call, body) \ do { \ int prev_failed_asserts = failed_asserts; \ call; \ assert("Failed Test Condition", \ prev_failed_asserts == failed_asserts, \ body); \ } while(0) #define TEST(test) \ do { \ int r = 0; \ if((r = test)) { \ printf("[FAILED] "#test \ " with %d errors\n", r); \ failed_test_counter++; \ } else { \ printf("[PASSED] "#test"\n"); \ passed_test_counter++; \ } \ fsendfile(stdout, logfp) \ ? printf("\n") : 0; \ } while(0) int test_internal(); int test_bool(); int test_int(); int test_float(); int test_raw(); int test_compound(); int main(void) { logfp = tmpfile(); TEST(test_internal()); TEST(test_bool()); TEST(test_int()); TEST(test_float()); TEST(test_raw()); TEST(test_compound()); printf("------------------------------\n"); printf("PASSED %d/%d tests, (%.1f%%)\n", passed_test_counter, failed_test_counter + passed_test_counter, 100.0f * passed_test_counter / (failed_test_counter + passed_test_counter)); fclose(logfp); return 0; } #define BODY_SUCCESS_1(t, type) \ { \ assert(t == type, \ logvar(t, msgpack_type_string[t], "%s")); \ } #define BODY_SUCCESS_2(t, a, type, subtype) \ { \ BODY_SUCCESS_1(t, type); \ assert((int)a == (int)subtype, \ logvar(a, msgpack_type_string[a], "%s")); \ } #define BODY_FAILED_1(t, e, a) \ { \ assert("Failed Call", 0, ;); \ logvar(t, msgpack_type_string[t], "%s"); \ logvar(e, msgpack_error_string[e], "%s"); \ if(e == MSGPACK_ERROR_WRONG_TYPE) \ logvar(a, msgpack_type_string[a], "%s"); \ else logvar(a, "0x%hhx"); \ return; \ } int test_internal() { failed_asserts = 0; return failed_asserts; } void bool_1(uint8_t *buf, size_t size, bool value) { uint8_t b[1] = {0}; bool v; MSGPACK_CHECK2(msgpack_read_bool(&msgpack_init(buf, size, NULL), &v), (t, e, a), BODY_SUCCESS_1(t, MSGPACK_BOOL), BODY_FAILED_1(t, e, a)); assert(v == value, logvar(v, "%d")); MSGPACK_CHECK2(msgpack_write_bool(&msgpack_init(b, size, NULL), &value), (t, e, a), BODY_SUCCESS_1(t, MSGPACK_BOOL), BODY_FAILED_1(t, e, a)); assert(memcmp(buf, b, size) == 0, logbytes(b, size)); } #define bool_template(n, _buf, _value) \ check_condition(bool_##n((_buf), sizeof(_buf), (_value)), \ { \ logbytes(buf, (_buf), sizeof(_buf)); \ logvar(value, (_value), "%d"); \ printf("\n"); \ }); \ int test_bool() { failed_asserts = 0; bool_template(1, (uint8_t []){0xC2}, true); bool_template(1, (uint8_t []){0xC3}, false); return failed_asserts; } void int_1(uint8_t *buf, size_t size, union mp_int value, enum msgpack_type subtype) { uint8_t b[9] = {0}; union mp_int v; MSGPACK_CHECK2(msgpack_read_int(&msgpack_init(buf, size, NULL), &v), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_INT, subtype), BODY_FAILED_1(t, e, a)); assert(v.u == value.u, logvar(v.u, "%"PRIu64)); MSGPACK_CHECK2(msgpack_write_int(&msgpack_init(b, size, NULL), &value, subtype), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_INT, subtype), BODY_FAILED_1(t, e, a)); assert(memcmp(buf, b, size) == 0, logbytes(b, size)); } #define int_template(n, _buf, _value, _subtype) \ check_condition(int_##n((_buf), sizeof(_buf), (_value), (_subtype)), \ { \ logbytes(buf, (_buf), sizeof(_buf)); \ if((_subtype) == MSGPACK_INT_SIGNED) \ logvar(value.i, (_value).i, "%"PRIi64); \ else logvar(value.u, (_value).u, "%"PRIu64); \ logvar(subtype, msgpack_type_string[(_subtype)], "%s"); \ printf("\n"); \ }); \ int test_int() { failed_asserts = 0; int_template(1, ((uint8_t []){0xD3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01}), ((union mp_int){.i=0x0100000000000201}), MSGPACK_INT_SIGNED); int_template(1, ((uint8_t []){0xCF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01}), ((union mp_int){.u=0x0100000000000201}), MSGPACK_INT_UNSIGNED); int_template(1, ((uint8_t []){0xFF}), ((union mp_int){.i=-1}), MSGPACK_INT_SIGNED); return failed_asserts; } // void float_1(uint8_t *buf, size_t size, union mp_float value, enum msgpack_type subtype) // { // uint8_t b[9] = {0}; // union mp_float v; // MSGPACK_CHECK2(msgpack_read_float(&msgpack_init(buf, size, NULL), &v), // (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_FLOAT, subtype), // BODY_FAILED_1(t, e, a)); // if(subtype == MSGPACK_FLOAT_32) { // assert(v.f == value.f, logvar(v.f, "%f")); // } else { // assert(v.d == value.d, logvar(v.d, "%f")); // } // MSGPACK_CHECK2(msgpack_write_float(&msgpack_init(b, size, NULL), &value, subtype), // (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_FLOAT, subtype), // BODY_FAILED_1(t, e, a)); // assert(memcmp(buf, b, size) == 0, logbytes(b, size)); // } // #define float_template(n, _buf, _value, _subtype) \ // check_condition(float_##n((_buf), sizeof(_buf), (_value), (_subtype)), \ // { \ // logbytes(buf, (_buf), sizeof(_buf)); \ // if((_subtype) == MSGPACK_FLOAT_32) \ // logvar(value.f, (_value).f, "%f"); \ // else logvar(value.d, (_value).d, "%f"); \ // logvar(subtype, msgpack_type_string[(_subtype)], "%s"); \ // printf("\n"); \ // }); void float_2(union mp_float value, enum msgpack_type subtype) { uint8_t b[9] = {0}; size_t size = 9; union mp_float v; MSGPACK_CHECK2(msgpack_write_float(&msgpack_init(b, size, NULL), &value, subtype), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_FLOAT, subtype), BODY_FAILED_1(t, e, a)); MSGPACK_CHECK2(msgpack_read_float(&msgpack_init(b, size, NULL), &v), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_FLOAT, subtype), BODY_FAILED_1(t, e, a)); if(subtype == MSGPACK_FLOAT_32) { assert(v.f == value.f, logvar(v.f, "%f")); logbytes(b, 5); } else { assert(v.d == value.d, logvar(v.d, "%f")); logbytes(b, 9); } } #define float_template(n, _value, _subtype) \ check_condition(float_##n((_value), (_subtype)), \ { \ if((_subtype) == MSGPACK_FLOAT_32) \ logvar(value.f, (_value).f, "%f"); \ else logvar(value.d, (_value).d, "%f"); \ logvar(subtype, \ msgpack_type_string[(_subtype)], "%s"); \ }) #include int test_float() { failed_asserts = 0; float_template(2, ((union mp_float){.f=-1.7}), MSGPACK_FLOAT_32); float_template(2, ((union mp_float){.f=FLT_MAX}), MSGPACK_FLOAT_32); float_template(2, ((union mp_float){.f=FLT_MIN}), MSGPACK_FLOAT_32); float_template(2, ((union mp_float){.d=DBL_MAX}), MSGPACK_FLOAT_64); float_template(2, ((union mp_float){.d=DBL_MIN}), MSGPACK_FLOAT_64); return failed_asserts; } void raw_1(uint8_t *bin, size_t size, struct mp_bin r) { uint8_t b[64] = {0}; struct mp_bin v = {0}; MSGPACK_CHECK2(msgpack_read_raw(&msgpack_init(bin, size, NULL), &v), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_RAW, MSGPACK_RAW_STRING), BODY_FAILED_1(t, e, a)); assert(v.size == r.size, logvar(v.size, "%zu")); assert(memcmp(v.bin, r.bin, v.size) == 0, logbytes(v.bin, v.size)); MSGPACK_CHECK2(msgpack_write_raw(&msgpack_init(b, sizeof(b), NULL), &r, MSGPACK_RAW_STRING), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_RAW, MSGPACK_RAW_STRING), BODY_FAILED_1(t, e, a)); assert(memcmp(b, bin, size) == 0, logbytes(b, size)); } int test_raw() { failed_asserts = 0; check_condition(raw_1("\xa5hello", 6, (struct mp_bin){.size = 5, .bin = "hello"}), ); check_condition(raw_1("\xd9\x24hello_______________________________", 38, (struct mp_bin){.size = 36, .bin = "hello_______________________________"}), ); return failed_asserts; } void compound_1() { uint8_t bin[] = {0x0A, 0xCF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01}; msgpack_t pack = msgpack_init(bin, sizeof(bin), NULL); union mp_int v = {0}; MSGPACK_CHECK2(msgpack_read_int(&pack, &v), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_INT, MSGPACK_INT_UNSIGNED), BODY_FAILED_1(t, e, a)); assert(v.i == 10, logvar(v.u, "%"PRIi64)); MSGPACK_CHECK2(msgpack_read_int(&pack, &v), (t, e, a), BODY_SUCCESS_2(t, a, MSGPACK_INT, MSGPACK_INT_UNSIGNED), BODY_FAILED_1(t, e, a)); assert(v.i == 0x0100000000000201, logvar(v.u, "%"PRIi64)); } int test_compound() { failed_asserts = 0; compound_1(); return failed_asserts; }