#include #include #include "test.h" #include "apfl.h" #include "encode.h" #define HEXDUMP_FMT "%02X%02X%02X%02X%02X%02X%02X%02X" #define HEXDUMP_ARGS(b) \ (unsigned int)((b)[0]), \ (unsigned int)((b)[1]), \ (unsigned int)((b)[2]), \ (unsigned int)((b)[3]), \ (unsigned int)((b)[4]), \ (unsigned int)((b)[5]), \ (unsigned int)((b)[6]), \ (unsigned int)((b)[7]) static void test_u64(testctx t, void (*fn)(testctx, uint_least64_t, unsigned char[8])) { fn(t, 0, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); fn(t, 1, (unsigned char[8]) {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); fn(t, 42, (unsigned char[8]) {0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); fn(t, 666, (unsigned char[8]) {0x9A,0x02,0x00,0x00,0x00,0x00,0x00,0x00}); fn(t, 0x1122334455667788, (unsigned char[8]) {0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11}); fn(t, 0xFFFFFFFFFFFFFFFF, (unsigned char[8]) {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}); } static void u64_encode_callback(testctx t, uint_least64_t n, unsigned char bytes[8]) { struct apfl_allocator allocator = test_allocator(t); struct apfl_string_builder sb = apfl_string_builder_init(allocator); struct apfl_io_writer w = apfl_io_string_writer(&sb); if (!apfl_encode_u64(w, n)) { test_failf(t, "Could not encode u64 0x%" PRIxLEAST64, n); return; } struct apfl_string have = apfl_string_builder_move_string(&sb); if (have.len != 8) { test_failf(t, "Encoded length is incorrect. Got %d", (int)have.len); return; } struct apfl_string_view want = { .bytes = bytes, .len = 8, }; if (!apfl_string_eq(want, have)) { test_failf( t, "Encoding for 0x%" PRIxLEAST64 " is wrong. have " HEXDUMP_FMT ", want " HEXDUMP_FMT, n, HEXDUMP_ARGS(have.bytes), HEXDUMP_ARGS(bytes) ); return; } apfl_string_deinit(allocator, &have); } static void u64_decode_callback(testctx t, uint_least64_t want, unsigned char bytes[8]) { struct apfl_string_view input = { .bytes = bytes, .len = 8, }; struct apfl_io_string_reader_data reader_data = apfl_io_string_reader_create(input); struct apfl_io_reader r = apfl_io_string_reader(&reader_data); uint_least64_t have; if (!apfl_decode_u64(r, &have)) { test_failf(t, "Could not decode u64 0x%" PRIxLEAST64, want); return; } if (want != have) { test_failf( t, "Decoding failed, have 0x%" PRIxLEAST64 ", want 0x%" PRIxLEAST64 ".", have, want ); return; } } TEST(encode_u64, t) { test_u64(t, u64_encode_callback); } TEST(decode_u64, t) { test_u64(t, u64_decode_callback); } static void test_double(testctx t, void (*fn)(testctx, double, unsigned char[8])) { fn(t, 0, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}); fn(t, 1, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x3F}); fn(t, 42, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40}); fn(t, -2.75, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xC0}); fn(t, 1337.42, (unsigned char[8]) {0x48,0xE1,0x7A,0x14,0xAE,0xE5,0x94,0x40}); fn(t, 1E+50, (unsigned char[8]) {0x9A,0x64,0x7E,0xC5,0x0E,0x1B,0x51,0x4A}); fn(t, 1E-12, (unsigned char[8]) {0x11,0xEA,0x2D,0x81,0x99,0x97,0x71,0x3D}); fn(t, NAN, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x7F}); fn(t, -NAN, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF}); fn(t, INFINITY, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x7F}); fn(t, -INFINITY, (unsigned char[8]) {0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF}); } static void double_encode_callback(testctx t, double d, unsigned char bytes[8]) { struct apfl_allocator allocator = test_allocator(t); struct apfl_string_builder sb = apfl_string_builder_init(allocator); struct apfl_io_writer w = apfl_io_string_writer(&sb); if (!apfl_encode_double(w, d)) { test_failf(t, "Could not encode double %a", d); return; } struct apfl_string have = apfl_string_builder_move_string(&sb); if (have.len != 8) { test_failf(t, "Encoded length is incorrect. Got %d", (int)have.len); return; } struct apfl_string_view want = { .bytes = bytes, .len = 8, }; if (!apfl_string_eq(want, have)) { test_failf( t, "Encoding for %a is wrong. have " HEXDUMP_FMT ", want " HEXDUMP_FMT, d, HEXDUMP_ARGS(have.bytes), HEXDUMP_ARGS(bytes) ); return; } apfl_string_deinit(allocator, &have); } static bool cmpdouble(double a, double b) { if (isnan(a)) { return isnan(b) && signbit(a) == signbit(b); } else { return a == b; } } static void double_decode_callback(testctx t, double want, unsigned char bytes[8]) { struct apfl_string_view input = { .bytes = bytes, .len = 8, }; struct apfl_io_string_reader_data reader_data = apfl_io_string_reader_create(input); struct apfl_io_reader r = apfl_io_string_reader(&reader_data); double have; if (!apfl_decode_double(r, &have)) { test_failf(t, "Could not decode double %a", want); return; } if (!cmpdouble(want, have)) { test_failf( t, "Decoding failed, have %a, want %a.", have, want ); return; } } TEST(encode_double, t) { test_double(t, double_encode_callback); } TEST(decode_double, t) { test_double(t, double_decode_callback); } TESTS_BEGIN ADDTEST(encode_u64), ADDTEST(decode_u64), ADDTEST(encode_double), ADDTEST(decode_double), TESTS_END