200 lines
5.7 KiB
C
200 lines
5.7 KiB
C
#include <inttypes.h>
|
|
#include <math.h>
|
|
|
|
#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
|