diff options
author | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
commit | fcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch) | |
tree | 51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/ur/tests.c |
claude is gud
Diffstat (limited to 'vere/pkg/ur/tests.c')
-rw-r--r-- | vere/pkg/ur/tests.c | 1862 |
1 files changed, 1862 insertions, 0 deletions
diff --git a/vere/pkg/ur/tests.c b/vere/pkg/ur/tests.c new file mode 100644 index 0000000..e0516b6 --- /dev/null +++ b/vere/pkg/ur/tests.c @@ -0,0 +1,1862 @@ +/// @file + +#include "ur.h" + +#include <assert.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* +** initialize helper for bitstream-writer tests. +*/ +static void +_bsw_reinit(ur_bsw_t *bsw, uint64_t prev, uint64_t size) +{ + bsw->prev = prev; + bsw->size = size; + bsw->bits = 0; + bsw->fill = 0; + bsw->off = 0; + + free(bsw->bytes); + bsw->bytes = calloc(size, 1); +} + +/* +** check bitstream-writer test invariants. +*/ +static int +_bsw_bit_check(const char* cap, ur_bsw_t *bsw, uint8_t byt, uint8_t off) +{ + int ret = 1; + + if ( !ur_bsw_sane(bsw) ) { + fprintf(stderr, "%s: insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, bsw->off, bsw->fill, bsw->bits); + ret = 0; + } + + if ( byt != bsw->bytes[0] ) { + fprintf(stderr, "%s: bytes fail (%u, %u)\r\n", cap, byt, bsw->bytes[0]); + ret = 0; + } + + if ( off != bsw->off ) { + fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsw->off); + ret = 0; + } + + return ret; +} + +/* +** test 8 sequential writes of a set bit. +*/ +static int +_test_bsw_bit_ones(void) +{ + int ret = 1; + ur_bsw_t bsw = {0}; + _bsw_reinit(&bsw, 1, 1); + + ret &= _bsw_bit_check("bsw ones init", &bsw, 0x0, 0); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones a", &bsw, 0x1, 1); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones b", &bsw, 0x3, 2); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones c", &bsw, 0x7, 3); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones d", &bsw, 0xf, 4); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones e", &bsw, 0x1f, 5); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones f", &bsw, 0x3f, 6); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones g", &bsw, 0x7f, 7); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw ones h", &bsw, 0xff, 0); + + if ( bsw.size != 2 ) { + fprintf(stderr, "bsw ones grow: fail\r\n"); + ret = 0; + } + + free(bsw.bytes); + + return ret; +} + +/* +** test 8 sequential writes of 1 null bit. +*/ +static int +_test_bsw_bit_zeros(void) +{ + int ret = 1; + ur_bsw_t bsw = {0}; + _bsw_reinit(&bsw, 1, 1); + + ret &= _bsw_bit_check("bsw zeros init", &bsw, 0x0, 0); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros a", &bsw, 0x0, 1); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros b", &bsw, 0x0, 2); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros c", &bsw, 0x0, 3); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros d", &bsw, 0x0, 4); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros e", &bsw, 0x0, 5); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros f", &bsw, 0x0, 6); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros g", &bsw, 0x0, 7); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw zeros h", &bsw, 0x0, 0); + + if ( bsw.size != 2 ) { + fprintf(stderr, "bsw zeros grow: fail\r\n"); + ret = 0; + } + + free(bsw.bytes); + + return ret; +} + +/* +** test 8 sequential writes of alternating bits. +*/ +static int +_test_bsw_bit_alt(void) +{ + int ret = 1; + ur_bsw_t bsw = {0}; + _bsw_reinit(&bsw, 1, 1); + + ret &= _bsw_bit_check("bsw alt init", &bsw, 0x0, 0); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw alt a", &bsw, 0x0, 1); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw alt b", &bsw, 0x2, 2); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw alt c", &bsw, 0x2, 3); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw alt d", &bsw, 0xa, 4); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw alt e", &bsw, 0xa, 5); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw alt f", &bsw, 0x2a, 6); + + ur_bsw_bit(&bsw, 0); + ret &= _bsw_bit_check("bsw alt g", &bsw, 0x2a, 7); + + ur_bsw_bit(&bsw, 1); + ret &= _bsw_bit_check("bsw alt h", &bsw, 0xaa, 0); + + if ( bsw.size != 2 ) { + fprintf(stderr, "bsw alt grow: fail\r\n"); + ret = 0; + } + + free(bsw.bytes); + + return ret; +} + +static int +_test_bsw_bit(void) +{ + return _test_bsw_bit_ones() + & _test_bsw_bit_zeros() + & _test_bsw_bit_alt(); +} + +/* +** subsequents bitstream-writer tests assume the correctnesss of +** ur_bsw_bit(), and compare the output of a bit-at-a-time +** "golden master" with that of the relevant, higher-level operation. +** +** XX the "golden" master implementations shouldn't be in bitstream module, +** as we don't intend to run them, but it's kind of weird implement them +** in the test itself. +** +*/ +static int +_bsw_cmp_check(const char* cap, uint8_t val, uint8_t off, uint8_t len, ur_bsw_t *a, ur_bsw_t *b) +{ + int ret = 1; + + if ( !ur_bsw_sane(a) ) { + fprintf(stderr, "%s: val 0x%02x off %u, len %u: a insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, val, off, len, a->off, a->fill, a->bits); + ret = 0; + } + if ( !ur_bsw_sane(b) ) { + fprintf(stderr, "%s: val 0x%02x off %u len %u: b insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, val, off, len, b->off, b->fill, b->bits); + ret = 0; + } + + if ( a->off != b->off ) { + fprintf(stderr, "%s: val 0x%02x off %u len %u: offset fail (%u, %u)\r\n", + cap, val, off, len, a->off, b->off); + ret = 0; + } + + if ( a->fill != b->fill ) { + fprintf(stderr, "%s: val 0x%02x off %u len %u: fill fail (%" PRIu64 ", %" PRIu64 ")\r\n", + cap, val, off, len, a->fill, b->fill); + ret = 0; + } + + { + uint64_t k, len_byt = a->fill + !!a->off; + + if ( memcmp(a->bytes, b->bytes, len_byt) ) { + fprintf(stderr, "%s: val 0x%02x off %u, len %u not equal off=%u fill=%" PRIu64 "\r\n", + cap, val, off, len, b->off, b->fill); + fprintf(stderr, " a: { "); + for ( k = 0; k < len_byt; k++ ) { + fprintf(stderr, "%02x, ", a->bytes[k]); + } + fprintf(stderr, "}\r\n"); + fprintf(stderr, " b: { "); + for ( k = 0; k < len_byt; k++ ) { + fprintf(stderr, "%02x, ", b->bytes[k]); + } + fprintf(stderr, "}\r\n"); + ret = 0; + } + } + + return ret; +} + +/* +** ur_bsw8 golden master +*/ +static void +_bsw8_slow(ur_bsw_t *bsw, uint8_t len, uint8_t byt) +{ + len = ur_min(8, len); + + while ( len ) { + ur_bsw_bit(bsw, byt); + byt >>= 1; + len--; + } +} + +/* +** at varying offsets, write varying numbers of bits via +** ur_bsw8 and master, comparing the result each time. +*/ +static int +_test_bsw8_loop(const char* cap, uint8_t val) +{ + int ret = 1; + ur_bsw_t a = {0}; + ur_bsw_t b = {0}; + uint8_t i, j; + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 8; j++ ) { + _bsw_reinit(&a, 1, 1); + _bsw_reinit(&b, 1, 1); + a.off = a.bits = b.off = b.bits = i; + + _bsw8_slow(&a, j, val); + ur_bsw8(&b, j, val); + + ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); + } + } + + return ret; +} + +static int +_test_bsw8(void) +{ + return _test_bsw8_loop("bsw bits ones", 0xff) + & _test_bsw8_loop("bsw bits zeros", 0x0) + & _test_bsw8_loop("bsw bits alt 1", 0xaa) + & _test_bsw8_loop("bsw bits alt 2", 0x55); +} + +/* +** ur_bsw32 golden master +*/ +static void +_bsw32_slow(ur_bsw_t *bsw, uint8_t len, uint32_t val) +{ + len = ur_min(32, len); + + while ( len ) { + ur_bsw_bit(bsw, val & 0xff); + val >>= 1; + len--; + } +} + +/* +** at varying offsets, write varying numbers of bits via +** ur_bsw32 and master, comparing the result each time. +*/ +static int +_test_bsw32_loop(const char* cap, uint32_t val) +{ + int ret = 1; + ur_bsw_t a = {0}; + ur_bsw_t b = {0}; + uint8_t i, j; + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 32; j++ ) { + _bsw_reinit(&a, 1, 1); + _bsw_reinit(&b, 1, 1); + a.off = a.bits = b.off = b.bits = i; + + _bsw32_slow(&a, j, val); + ur_bsw32(&b, j, val); + + ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); + } + } + + return ret; +} + +static int +_test_bsw32(void) +{ + return _test_bsw32_loop("bsw 32 ones", 0xffffffff) + & _test_bsw32_loop("bsw 32 zeros", 0x0) + & _test_bsw32_loop("bsw 32 alt 1", 0xaaaaaaaa) + & _test_bsw32_loop("bsw 32 alt 2", 0x55555555); +} + +/* +** ur_bsw64 golden master +*/ +static void +_bsw64_slow(ur_bsw_t *bsw, uint8_t len, uint64_t val) +{ + len = ur_min(64, len); + + while ( len ) { + ur_bsw_bit(bsw, val & 0xff); + val >>= 1; + len--; + } +} + +/* +** at varying offsets, write varying numbers of bits via +** ur_bsw64 and master, comparing the result each time. +*/ +static int +_test_bsw64_loop(const char* cap, uint64_t val) +{ + int ret = 1; + ur_bsw_t a = {0}; + ur_bsw_t b = {0}; + uint8_t i, j; + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 64; j++ ) { + _bsw_reinit(&a, 1, 1); + _bsw_reinit(&b, 1, 1); + a.off = a.bits = b.off = b.bits = i; + + _bsw64_slow(&a, j, val); + ur_bsw64(&b, j, val); + + ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); + } + } + + return ret; +} + +static int +_test_bsw64(void) +{ + return _test_bsw64_loop("bsw 64 ones", 0xffffffffffffffffULL) + & _test_bsw64_loop("bsw 64 zeros", 0x0ULL) + & _test_bsw64_loop("bsw 64 alt 1", 0xaaaaaaaaaaaaaaaaULL) + & _test_bsw64_loop("bsw 64 alt 2", 0x5555555555555555ULL); +} + +/* +** ur_bsw_bytes() golden master +*/ +static void +_bsw_bytes_slow(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) +{ + uint64_t i, len_byt = len >> 3; + + for ( i = 0; i < len_byt; i++ ) { + _bsw8_slow(bsw, 8, byt[i]); + len -= 8; + } + + _bsw8_slow(bsw, len, byt[len_byt]); +} + +/* +** at varying offsets, write varying numbers of bits via +** ur_bsw_bytes and master, comparing the result each time. +*/ +static int +_test_bsw_bytes_loop(const char* cap, uint64_t len, uint8_t val) +{ + int ret = 1; + ur_bsw_t a = {0}; + ur_bsw_t b = {0}; + uint8_t i, j, *byt; + uint64_t len_bit = len << 3; + + byt = malloc(len); + memset(byt, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j < len_bit; j++ ) { + _bsw_reinit(&a, 1, 1); + _bsw_reinit(&b, 1, 1); + a.off = a.bits = b.off = b.bits = i; + + _bsw_bytes_slow(&a, j, byt); + ur_bsw_bytes(&b, j, byt); + + ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); + } + } + + free(byt); + + return ret; +} + +static int +_test_bsw_bytes(void) +{ + return _test_bsw_bytes_loop("bsw bytes nought", 0, 0x0) + & _test_bsw_bytes_loop("bsw bytes ones odd", 3, 0xff) + & _test_bsw_bytes_loop("bsw bytes ones even", 4, 0xff) + & _test_bsw_bytes_loop("bsw bytes zeros odd", 5, 0x0) + & _test_bsw_bytes_loop("bsw bytes zeros even", 6, 0x0) + & _test_bsw_bytes_loop("bsw bytes alt 1 odd", 7, 0xaa) + & _test_bsw_bytes_loop("bsw bytes alt 1 even", 8, 0xaa) + & _test_bsw_bytes_loop("bsw bytes alt 2 odd", 9, 0x55) + & _test_bsw_bytes_loop("bsw bytes alt 2 even", 10, 0x55); +} + +/* +** ur_bsw_bex golden master +*/ +static void +_bsw_bex_slow(ur_bsw_t *bsw, uint8_t n) +{ + while ( n >= 64 ) { + _bsw64_slow(bsw, 64, 0); + n -= 64; + } + + _bsw64_slow(bsw, n + 1, 1ULL << n); +} + +/* +** at varying offsets, write varying numbers of bits via +** ur_bsw_bex and master, comparing the result each time. +*/ +static int +_test_bsw_bex() +{ + int ret = 1; + ur_bsw_t a = {0}; + ur_bsw_t b = {0}; + uint8_t i; + uint32_t j; + + for ( i = 0; i < 8; i++) { + for ( j = 0; j < 256; j++ ) { + _bsw_reinit(&a, 1, 1); + _bsw_reinit(&b, 1, 1); + a.off = a.bits = b.off = b.bits = i; + + _bsw_bex_slow(&a, j); + ur_bsw_bex(&b, j); + + ret &= _bsw_cmp_check("bsw bex", j, i, j + 1, &a, &b); + } + } + + return ret; +} + +static int +_test_bsw(void) +{ + return _test_bsw_bit() + & _test_bsw8() + & _test_bsw32() + & _test_bsw64() + & _test_bsw_bytes() + & _test_bsw_bex(); +} + +/* +** check bitstream-reader test invariants. +*/ +static int +_bsr_bit_check(const char *cap, + ur_bsr_t *bsr, + uint8_t off, + uint64_t bits, + uint8_t exp, + uint8_t val, + ur_cue_res_e ser, + ur_cue_res_e res) +{ + int ret = 1; + + if ( !ur_bsr_sane(bsr) ) { + fprintf(stderr, "%s: insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, bsr->off, bsr->left, bsr->bits); + ret = 0; + } + + if ( ser != res ) { + fprintf(stderr, "%s: res not equal (%s, %s) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, (ur_cue_good == ser) ? "good" : "gone", + (ur_cue_good == res) ? "good" : "gone", + bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); + ret = 0; + } + + if ( (ur_cue_good == res) && (exp != val) ) { + fprintf(stderr, "%s: val not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, exp, val, bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); + ret = 0; + } + + if ( off != bsr->off ) { + fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsr->off); + ret = 0; + } + + if ( bits != bsr->bits ) { + fprintf(stderr, "%s: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", cap, bits, bsr->bits); + ret = 0; + } + + return ret; +} + +/* +** read a bit 8 times from a bitstream initialized to all ones, +** checking invariants and result after each read. +*/ +static int +_test_bsr_bit_ones(void) +{ + int ret = 1; + uint8_t ones[1] = { 0xff }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + ur_cue_res_e res; + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); + + return ret; +} + +/* +** read a bit 8 times from a bitstream initialized to all zeros, +** checking invariants and result after each read. +*/ +static int +_test_bsr_bit_zeros(void) +{ + int ret = 1; + uint8_t ones[1] = { 0x0 }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + ur_cue_res_e res; + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); + + return ret; +} + +/* +** read a bit 8 times from a bitstream initialized to alternating zeros and ones, +** checking invariants and result after each read. +*/ +static int +_test_bsr_bit_alt(void) +{ + int ret = 1; + uint8_t ones[1] = { 0xaa }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + ur_cue_res_e res; + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 0, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 1, out); + + res = ur_bsr_bit(&bsr, &out); + ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); + + return ret; +} + +static int +_test_bsr_bit(void) +{ + return _test_bsr_bit_ones() + & _test_bsr_bit_zeros() + & _test_bsr_bit_alt(); +} + +/* +** check bitstream-reader test invariants, after (maybe) reading +** of the end of the stream. +*/ +static int +_bsr_bit_any_check(const char* cap, ur_bsr_t *bsr, uint8_t off, uint64_t bits, uint8_t exp, uint8_t val) +{ + int ret = 1; + + if ( !ur_bsr_sane(bsr) ) { + fprintf(stderr, "%s: insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, bsr->off, bsr->left, bsr->bits); + ret = 0; + } + + if ( exp != val ) { + fprintf(stderr, "%s: not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, exp, val, bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); + ret = 0; + } + + if ( off != bsr->off ) { + fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsr->off); + ret = 0; + } + + if ( bits != bsr->bits ) { + fprintf(stderr, "%s: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", cap, bits, bsr->bits); + ret = 0; + } + + return ret; +} + +/* +** read a bit 17 times from a bitstream initialized to 8 ones, +** checking invariants and result after each read. +*/ +static int +_test_bsr_bit_any_ones(void) +{ + int ret = 1; + uint8_t ones[1] = { 0xff }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + + ret &= _bsr_bit_any_check("bsr bit-any ones init", &bsr, 0, 0, 0, 0); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 1", &bsr, 1, 1, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 2", &bsr, 2, 2, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 3", &bsr, 3, 3, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 4", &bsr, 4, 4, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 5", &bsr, 5, 5, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 6", &bsr, 6, 6, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 7", &bsr, 7, 7, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones 8", &bsr, 0, 8, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 9", &bsr, 0, 9, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 10", &bsr, 0, 10, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 11", &bsr, 0, 11, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 12", &bsr, 0, 12, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 13", &bsr, 0, 13, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 14", &bsr, 0, 14, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 15", &bsr, 0, 15, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 16", &bsr, 0, 16, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any ones off 17", &bsr, 0, 17, 0, out); + + return ret; +} + +/* +** read a bit 17 times from a bitstream initialized to 8 zeros, +** checking invariants and result after each read. +*/ +static int +_test_bsr_bit_any_zeros(void) +{ + int ret = 1; + uint8_t ones[1] = { 0x0 }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + + ret &= _bsr_bit_any_check("bsr bit-any zeros init", &bsr, 0, 0, 0, 0); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 1", &bsr, 1, 1, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 2", &bsr, 2, 2, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 3", &bsr, 3, 3, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 4", &bsr, 4, 4, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 5", &bsr, 5, 5, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 6", &bsr, 6, 6, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 7", &bsr, 7, 7, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros 8", &bsr, 0, 8, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 9", &bsr, 0, 9, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 10", &bsr, 0, 10, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 11", &bsr, 0, 11, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 12", &bsr, 0, 12, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 13", &bsr, 0, 13, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 14", &bsr, 0, 14, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 15", &bsr, 0, 15, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 16", &bsr, 0, 16, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any zeros off 17", &bsr, 0, 17, 0, out); + + return ret; +} + +/* +** read a bit 17 times from a bitstream initialized to 8 bits of alternating, +** ones and zeros, checking invariants and result after each read. +*/ +static int +_test_bsr_bit_any_alt(void) +{ + int ret = 1; + uint8_t ones[1] = { 0xaa }; + ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; + uint8_t out; + + ret &= _bsr_bit_any_check("bsr bit-any alt init", &bsr, 0, 0, 0, 0); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 1", &bsr, 1, 1, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 2", &bsr, 2, 2, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 3", &bsr, 3, 3, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 4", &bsr, 4, 4, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 5", &bsr, 5, 5, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 6", &bsr, 6, 6, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 7", &bsr, 7, 7, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt 8", &bsr, 0, 8, 1, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 9", &bsr, 0, 9, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 10", &bsr, 0, 10, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 11", &bsr, 0, 11, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 12", &bsr, 0, 12, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 13", &bsr, 0, 13, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 14", &bsr, 0, 14, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 15", &bsr, 0, 15, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 16", &bsr, 0, 16, 0, out); + + out = ur_bsr_bit_any(&bsr); + ret &= _bsr_bit_any_check("bsr bit-any alt off 17", &bsr, 0, 17, 0, out); + + return ret; +} + +static int +_test_bsr_bit_any(void) +{ + return _test_bsr_bit_any_ones() + & _test_bsr_bit_any_zeros() + & _test_bsr_bit_any_alt(); +} + +/* +** subsequents bitstream-reader tests assume the correctnesss of +** ur_bsr_bit_any(), and compare the output of a bit-at-a-time +** "golden master" with that of the relevant, higher-level operation. +** +** XX the "golden" master implementations shouldn't be in bitstream module, +** as we don't intend to run them, but it's kind of weird implement them +** in the test itself. +** +*/ +static int +_bsr_cmp_any_check(const char* cap, uint8_t off, uint8_t len, ur_bsr_t *a, ur_bsr_t *b) +{ + int ret = 1; + + if ( !ur_bsr_sane(a) ) { + fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, a->off, a->left, a->bits); + ret = 0; + } + + if ( !ur_bsr_sane(b) ) { + fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, b->off, b->left, b->bits); + ret = 0; + } + + if ( a->off != b->off ) { + fprintf(stderr, "%s: off %u len %u: offset fail (%u, %u)\r\n", + cap, off, len, a->off, b->off); + ret = 0; + } + + if ( a->left != b->left ) { + fprintf(stderr, "%s: off %u len %u: left fail (%" PRIu64 ", %" PRIu64 ")\r\n", + cap, off, len, a->left, b->left); + ret = 0; + } + + if ( a->bits != b->bits ) { + fprintf(stderr, "%s: off %u len %u: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", + cap, off, len, a->bits, b->bits); + ret = 0; + } + + if ( a->bytes != b->bytes ) { + fprintf(stderr, "%s: off %u len %u: bytes fail (%p, %p)\r\n", + cap, off, len, a->bytes, b->bytes); + ret = 0; + } + + return ret; +} + +/* +** ur_bsr8_any golden master +*/ +static uint8_t +_bsr8_any_slow(ur_bsr_t *bsr, uint8_t len) +{ + uint8_t i, out = 0; + + len = ur_min(8, len); + + for ( i = 0; i < len; i++ ) { + out ^= ur_bsr_bit_any(bsr) << i; + } + + return out; +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a varying numbers of bits via ur_bsr8_any and master, comparing +** the results and respective states each time. +*/ +static int +_test_bsr8_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + uint8_t *bytes; + ur_bsr_t a, b; + uint8_t c, d, i, j; + + bytes = malloc(len); + memset(bytes, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 8; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = bytes; + a.off = a.bits = b.off = b.bits = i; + + c = _bsr8_any_slow(&a, j); + d = ur_bsr8_any(&b, j); + + ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); + + if ( c != d ) { + fprintf(stderr, "%s: off %u, len %u not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); + ret = 0; + } + } + } + + free(bytes); + + return ret; +} + +static int +_test_bsr8(void) +{ + return _test_bsr8_loop("bsr8 ones 1", 1, 0xff) + & _test_bsr8_loop("bsr8 ones 2", 2, 0xff) + & _test_bsr8_loop("bsr8 zeros 1", 1, 0x0) + & _test_bsr8_loop("bsr8 zeros 2", 2, 0x0) + & _test_bsr8_loop("bsr8 alt-1 1", 1, 0xaa) + & _test_bsr8_loop("bsr8 alt-1 2", 2, 0xaa) + & _test_bsr8_loop("bsr8 alt-2 1", 1, 0x55) + & _test_bsr8_loop("bsr8 alt-2 2", 2, 0x55); +} + +/* +** ur_bsr32_any golden master +*/ +static uint32_t +_bsr32_any_slow(ur_bsr_t *bsr, uint8_t len) +{ + uint32_t out = 0; + uint8_t i; + + len = ur_min(32, len); + + for ( i = 0; i < len; i++ ) { + out ^= (uint32_t)ur_bsr_bit_any(bsr) << i; + } + + return out; +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a varying numbers of bits via ur_bsr32_any and master, comparing +** the results and respective states each time. +*/ +static int +_test_bsr32_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + uint8_t *bytes; + ur_bsr_t a, b; + uint32_t c, d; + uint8_t i, j; + + bytes = malloc(len); + memset(bytes, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 32; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = bytes; + a.off = a.bits = b.off = b.bits = i; + + c = _bsr32_any_slow(&a, j); + d = ur_bsr32_any(&b, j); + + ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); + + if ( c != d ) { + fprintf(stderr, "%s: off %u, len %u not equal (%08x, %08x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); + ret = 0; + } + } + } + + free(bytes); + + return ret; +} + +static int +_test_bsr32(void) +{ + return _test_bsr32_loop("bsr32 ones 1", 1, 0xff) + & _test_bsr32_loop("bsr32 ones 2", 2, 0xff) + & _test_bsr32_loop("bsr32 ones 3", 3, 0xff) + & _test_bsr32_loop("bsr32 ones 4", 4, 0xff) + & _test_bsr32_loop("bsr32 zeros 1", 1, 0x0) + & _test_bsr32_loop("bsr32 zeros 2", 2, 0x0) + & _test_bsr32_loop("bsr32 zeros 3", 3, 0x0) + & _test_bsr32_loop("bsr32 zeros 4", 4, 0x0) + & _test_bsr32_loop("bsr32 alt-1 1", 1, 0xaa) + & _test_bsr32_loop("bsr32 alt-1 2", 2, 0xaa) + & _test_bsr32_loop("bsr32 alt-1 3", 3, 0xaa) + & _test_bsr32_loop("bsr32 alt-1 4", 4, 0xaa) + & _test_bsr32_loop("bsr32 alt-2 1", 1, 0x55) + & _test_bsr32_loop("bsr32 alt-2 2", 2, 0x55) + & _test_bsr32_loop("bsr32 alt-2 3", 3, 0x55) + & _test_bsr32_loop("bsr32 alt-2 4", 4, 0x55); +} + +/* +** ur_bsr64_any golden master +*/ +static uint64_t +_bsr64_any_slow(ur_bsr_t *bsr, uint8_t len) +{ + uint64_t out = 0; + uint8_t i; + + len = ur_min(64, len); + + for ( i = 0; i < len; i++ ) { + out ^= (uint64_t)ur_bsr_bit_any(bsr) << i; + } + + return out; +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a varying numbers of bits via ur_bsr64_any and master, comparing +** the results and respective states each time. +*/ +static int +_test_bsr64_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + uint8_t *bytes; + ur_bsr_t a, b; + uint64_t c, d; + uint8_t i, j; + + bytes = malloc(len); + memset(bytes, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j <= 64; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = bytes; + a.off = a.bits = b.off = b.bits = i; + + c = _bsr64_any_slow(&a, j); + d = ur_bsr64_any(&b, j); + + ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); + + if ( c != d ) { + fprintf(stderr, "%s: off %u, len %u not equal (%016" PRIx64", %016" PRIx64") off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", + cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); + ret = 0; + } + } + } + + free(bytes); + + return ret; +} + +static int +_test_bsr64(void) +{ + return _test_bsr64_loop("bsr64 ones 1", 1, 0xff) + & _test_bsr64_loop("bsr64 ones 2", 2, 0xff) + & _test_bsr64_loop("bsr64 ones 3", 3, 0xff) + & _test_bsr64_loop("bsr64 ones 4", 4, 0xff) + & _test_bsr64_loop("bsr64 ones 5", 5, 0xff) + & _test_bsr64_loop("bsr64 ones 6", 6, 0xff) + & _test_bsr64_loop("bsr64 ones 7", 7, 0xff) + & _test_bsr64_loop("bsr64 ones 8", 8, 0xff) + & _test_bsr64_loop("bsr64 zeros 1", 1, 0x0) + & _test_bsr64_loop("bsr64 zeros 2", 2, 0x0) + & _test_bsr64_loop("bsr64 zeros 3", 3, 0x0) + & _test_bsr64_loop("bsr64 zeros 4", 4, 0x0) + & _test_bsr64_loop("bsr64 zeros 5", 5, 0x0) + & _test_bsr64_loop("bsr64 zeros 6", 6, 0x0) + & _test_bsr64_loop("bsr64 zeros 7", 7, 0x0) + & _test_bsr64_loop("bsr64 zeros 8", 8, 0x0) + & _test_bsr64_loop("bsr64 alt-1 1", 1, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 2", 2, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 3", 3, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 4", 4, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 5", 5, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 6", 6, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 7", 7, 0xaa) + & _test_bsr64_loop("bsr64 alt-1 8", 8, 0xaa) + & _test_bsr64_loop("bsr64 alt-2 1", 1, 0x55) + & _test_bsr64_loop("bsr64 alt-2 2", 2, 0x55) + & _test_bsr64_loop("bsr64 alt-2 3", 3, 0x55) + & _test_bsr64_loop("bsr64 alt-2 4", 4, 0x55) + & _test_bsr64_loop("bsr64 alt-2 5", 5, 0x55) + & _test_bsr64_loop("bsr64 alt-2 6", 6, 0x55) + & _test_bsr64_loop("bsr64 alt-2 7", 7, 0x55) + & _test_bsr64_loop("bsr64 alt-2 8", 8, 0x55); +} + +/* +** ur_bsr_bytes_any golden master +*/ +static void +_bsr_bytes_any_slow(ur_bsr_t *bsr, uint64_t len, uint8_t *out) +{ + uint64_t i, len_byt = len >> 3, len_bit = ur_mask_3(len); + + for ( i = 0; i < len_byt; i++ ) { + out[i] = _bsr8_any_slow(bsr, 8); + } + + if ( len_bit ) { + out[len_byt] = _bsr8_any_slow(bsr, len_bit); + } +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a varying numbers of bits via ur_bsr_bytes_any and master, comparing +** the results and respective states each time. +*/ +static int +_test_bsr_bytes_any_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + uint64_t max = (len << 3) + 7; + ur_bsr_t a, b; + uint8_t *bytes, *c, *d; + uint8_t i, j, k; + + c = malloc(1 + len); + d = malloc(1 + len); + bytes = malloc(len); + memset(bytes, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 1; j <= max; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = len ? bytes : 0; + a.off = b.off = len ? i : 0; + a.bits = b.bits = i; + memset(c, 0x0, len); + memset(d, 0x0, len); + + _bsr_bytes_any_slow(&a, j, c); + ur_bsr_bytes_any(&b, j, d); + + ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); + + if ( memcmp(c, d, len) ) { + fprintf(stderr, "%s: off %u, len %u not equal off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, i, j, b.off, b.left, b.bits); + fprintf(stderr, " a: { "); + for ( k = 0; k < len; k++ ) { + fprintf(stderr, "%02x, ", c[k]); + } + fprintf(stderr, "}\r\n"); + fprintf(stderr, " b: { "); + for ( k = 0; k < len; k++ ) { + fprintf(stderr, "%02x, ", d[k]); + } + fprintf(stderr, "}\r\n"); + ret = 0; + } + } + } + + free(bytes); + free(d); + free(c); + + return ret; +} + +static int +_test_bsr_bytes_any(void) +{ + return _test_bsr_bytes_any_loop("bsr bytes nought", 0, 0x0) + & _test_bsr_bytes_any_loop("bsr bytes ones odd", 3, 0xff) + & _test_bsr_bytes_any_loop("bsr bytes ones even", 4, 0xff) + & _test_bsr_bytes_any_loop("bsr bytes zeros odd", 5, 0x0) + & _test_bsr_bytes_any_loop("bsr bytes zeros even", 6, 0x0) + & _test_bsr_bytes_any_loop("bsr bytes alt 1 odd", 7, 0xaa) + & _test_bsr_bytes_any_loop("bsr bytes alt 1 even", 8, 0xaa) + & _test_bsr_bytes_any_loop("bsr bytes alt 2 odd", 9, 0x55) + & _test_bsr_bytes_any_loop("bsr bytes alt 2 even", 10, 0x55); +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** skip a varying numbers of bits via ur_bsr_skip_any and read the same via +** ur_bsr_bytes_any master, comparing the respective states each time. +*/ +static int +_test_bsr_skip_any_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + uint64_t max = (len << 3) + 7; + ur_bsr_t a, b; + uint8_t *bytes, *c; + uint8_t i, j; + + c = malloc(1 + len); + bytes = malloc(len); + memset(bytes, val, len); + + for ( i = 0; i < 8; i++) { + for ( j = 1; j <= max; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = len ? bytes : 0; + a.off = b.off = len ? i : 0; + a.bits = b.bits = i; + memset(c, 0x0, len); + + _bsr_bytes_any_slow(&a, j, c); + ur_bsr_skip_any(&b, j); + + ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); + } + } + + free(bytes); + free(c); + + return ret; +} + +static int +_test_bsr_skip_any(void) +{ + return _test_bsr_skip_any_loop("bsr skip nought", 0, 0x0) + & _test_bsr_skip_any_loop("bsr skip ones odd", 3, 0xff) + & _test_bsr_skip_any_loop("bsr skip ones even", 4, 0xff) + & _test_bsr_skip_any_loop("bsr skip zeros odd", 5, 0x0) + & _test_bsr_skip_any_loop("bsr skip zeros even", 6, 0x0) + & _test_bsr_skip_any_loop("bsr skip alt 1 odd", 7, 0xaa) + & _test_bsr_skip_any_loop("bsr skip alt 1 even", 8, 0xaa) + & _test_bsr_skip_any_loop("bsr skip alt 2 odd", 9, 0x55) + & _test_bsr_skip_any_loop("bsr skip alt 2 even", 10, 0x55); +} + +/* +** compare the result and state of two reads (that were not permitted +** to read past the end of the stream). +*/ +static int +_bsr_cmp_check(const char* cap, + uint8_t off, + uint8_t len, + ur_bsr_t *a, + ur_bsr_t *b, + uint8_t c, + uint8_t d, + ur_cue_res_e e, + ur_cue_res_e f) +{ + int ret = 1; + + if ( !ur_bsr_sane(a) ) { + fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, a->off, a->left, a->bits); + ret = 0; + } + + if ( !ur_bsr_sane(b) ) { + fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, b->off, b->left, b->bits); + ret = 0; + } + + if ( e != f ) { + fprintf(stderr, "%s: off %u, len %u ret not equal (%s, %s) off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, + (ur_cue_good == e) ? "good" : "gone", + (ur_cue_good == f) ? "good" : "gone", + b->off, b->left, b->bits); + ret = 0; + } + + if ( (ur_cue_good == e) && (c != d) ) { + fprintf(stderr, "%s: off %u, len %u val not equal (%02x, %02x) off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", + cap, off, len, c, d, b->off, b->left, b->bits); + ret = 0; + } + + if ( a->off != b->off ) { + fprintf(stderr, "%s: off %u len %u: offset fail (%u, %u)\r\n", + cap, off, len, a->off, b->off); + ret = 0; + } + + if ( a->left != b->left ) { + fprintf(stderr, "%s: off %u len %u: left fail (%" PRIu64 ", %" PRIu64 ")\r\n", + cap, off, len, a->left, b->left); + ret = 0; + } + + if ( a->bits != b->bits ) { + fprintf(stderr, "%s: off %u len %u: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", + cap, off, len, a->bits, b->bits); + ret = 0; + } + + if ( a->bytes != b->bytes ) { + fprintf(stderr, "%s: off %u len %u: bytes fail (%p, %p)\r\n", + cap, off, len, a->bytes, b->bytes); + ret = 0; + } + + + return ret; +} + +/* +** ur_bsr_log golden master +*/ +static ur_cue_res_e +_bsr_log_slow(ur_bsr_t *bsr, uint8_t *out) +{ + ur_cue_res_e res; + uint8_t bit, i = 0; + + do { + if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { + return res; + } + else if ( bit ) { + *out = i; + return ur_cue_good; + } + } + while ( ++i ); + + return ur_cue_meme; +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a varying numbers of bits via ur_bsr_log and master, comparing +** the results and respective states each time. +*/ +static int +_test_bsr_log_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + ur_bsr_t a, b; + uint8_t *bytes, c, d; + uint8_t i, j; + ur_cue_res_e e, f; + + bytes = malloc(len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j < len; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = bytes; + a.off = a.bits = b.off = b.bits = i; + + memset(bytes, 0x0, j); + memset(bytes + j, val, len - j); + + e = _bsr_log_slow(&a, &c); + f = ur_bsr_log(&b, &d); + + ret &= _bsr_cmp_check(cap, i, j, &a, &b, c, d, e, f); + } + } + + free(bytes); + + return ret; +} + +static int +_test_bsr_log(void) +{ + int ret = _test_bsr_log_loop("bsr log nought", 0, 0x0) + & _test_bsr_log_loop("bsr log ones odd", 3, 0xff) + & _test_bsr_log_loop("bsr log ones even", 4, 0xff) + & _test_bsr_log_loop("bsr log ones big", 50, 0xff) + & _test_bsr_log_loop("bsr log zeros odd", 5, 0x0) + & _test_bsr_log_loop("bsr log zeros even", 6, 0x0) + & _test_bsr_log_loop("bsr log zeros big", 50, 0x0); + + { + uint8_t i, j = 5; + char cap[1024]; + + for ( i = 0; i < 8; i++ ) { + snprintf(cap, 1000, "bsr log 1<<%u odd", i); + ret &= _test_bsr_log_loop((const char*)cap, j++, 0x1 << i); + + snprintf(cap, 1000, "bsr log 1<<%u even", i); + ret &= _test_bsr_log_loop((const char*)cap, j++, 0x1 << i); + + snprintf(cap, 1000, "bsr log 1<<%u big", i); + ret &= _test_bsr_log_loop((const char*)cap, 50, 0x1 << i); + } + } + + return ret; +} + +/* +** ur_bsr_tag golden master +*/ +static ur_cue_res_e +_bsr_tag_slow(ur_bsr_t *bsr, ur_cue_tag_e *out) +{ + ur_cue_res_e res; + uint8_t bit; + + if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { + return res; + } + else if ( 0 == bit ) { + *out = ur_jam_atom; + return ur_cue_good; + } + else if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { + return res; + } + + *out = ( 0 == bit ) ? ur_jam_cell : ur_jam_back; + return ur_cue_good; +} + +/* +** from a bitstream-reader initialized with varying values/lengths/offsets, +** read a jam type tag via ur_bsr_tag and master, comparing the results and +** respective states each time. +*/ +static int +_test_bsr_tag_loop(const char *cap, uint8_t len, uint8_t val) +{ + int ret = 1; + ur_bsr_t a, b; + uint8_t *bytes; + ur_cue_tag_e c, d; + uint8_t i, j; + ur_cue_res_e e, f; + + bytes = malloc(len); + + for ( i = 0; i < 8; i++) { + for ( j = 0; j < len; j++ ) { + a.left = b.left = len; + a.bytes = b.bytes = bytes; + a.off = a.bits = b.off = b.bits = i; + + memset(bytes, 0x0, j); + memset(bytes + j, val, len - j); + + e = _bsr_tag_slow(&a, &c); + f = ur_bsr_tag(&b, &d); + + ret &= _bsr_cmp_check(cap, i, j, &a, &b, c, d, e, f); + } + } + + free(bytes); + + return ret; +} + +static int +_test_bsr_tag(void) +{ + return _test_bsr_tag_loop("bsr tag nought", 0, 0x0) + & _test_bsr_tag_loop("bsr tag ones 1", 1, 0xff) + & _test_bsr_tag_loop("bsr tag ones 2", 2, 0xff) + & _test_bsr_tag_loop("bsr tag zeros 1", 1, 0x0) + & _test_bsr_tag_loop("bsr tag zeros 2", 2, 0x0) + & _test_bsr_tag_loop("bsr tag alt-1 1", 1, 0xaa) + & _test_bsr_tag_loop("bsr tag alt-1 2", 2, 0xaa) + & _test_bsr_tag_loop("bsr tag alt-2 1", 1, 0x55) + & _test_bsr_tag_loop("bsr tag alt-2 2", 2, 0x55); +} + +static int +_test_bsr(void) +{ + return _test_bsr_bit() + & _test_bsr_bit_any() + & _test_bsr_bytes_any() + & _test_bsr_skip_any() + & _test_bsr8() + & _test_bsr32() + & _test_bsr64() + & _test_bsr_log() + & _test_bsr_tag(); +} + +static int +_test_jam_spec(const char *cap, + ur_root_t *r, + ur_nref ref, + size_t len, + const uint8_t *res) +{ + uint64_t i, out_len; + uint8_t *out; + int ret; + + ur_jam(r, ref, &out_len, &out); + + if ( 0 != memcmp(out, res, len) ) { + fprintf(stderr, "\033[31mjam %s fail\033[0m\r\n", cap); + + fprintf(stderr, " actual: { "); + for ( i = 0; i < out_len; i++ ) { + fprintf(stderr, "0x%x, ", out[i]); + } + fprintf(stderr, "}\r\n"); + fprintf(stderr, " expect: { "); + for ( i = 0; i < len; i++ ) { + fprintf(stderr, "0x%x, ", res[i]); + } + fprintf(stderr, "}\r\n"); + + ret = 0; + } + else { + ret = 1; + } + + free(out); + + return ret; +} + +static int +_test_cue_spec(const char *cap, + ur_root_t* r, + ur_nref ref, + size_t len, + const uint8_t *res) +{ + int ret = 1; + ur_nref out; + + if ( !ur_cue_test(len, res) ) { + fprintf(stderr, "\033[31mcue %s fail 1\033[0m\r\n", cap); + ret = 0; + } + + if ( ur_cue_good != ur_cue(r, len, res, &out) ) { + fprintf(stderr, "\033[31mcue %s fail 2\033[0m\r\n", cap); + ret = 0; + } + else if ( ref != out ) { + fprintf(stderr, "\033[31mcue %s fail 3 ref=%" PRIu64 " out=%" PRIu64 " \033[0m\r\n", cap, ref, out); + ret = 0; + } + + return ret; +} + +/* +** test jam/cue correctness and roundtrips across a variety of inputs +*/ +static int +_test_jam_cue(void) +{ + ur_root_t *r = ur_root_init(); + int ret = 1; + +# define NC(a, b) ur_cons(r, a, b) +# define NT(a, b, c) NC(a, NC(b, c)) + +# define FAST 0x74736166 +# define FULL 0x6c6c7566 + +# define TEST_CASE(a, b) \ + const char* cap = a; \ + ur_nref ref = b; \ + ret &= _test_jam_spec(cap, r, ref, sizeof(res), res); \ + ret &= _test_cue_spec(cap, r, ref, sizeof(res), res); \ + + { + uint8_t res[1] = { 0x2 }; + TEST_CASE("0", 0); + } + + { + uint8_t res[1] = { 0xc }; + TEST_CASE("1", 1); + } + + { + uint8_t res[1] = { 0x48 }; + TEST_CASE("2", 2); + } + + { + uint8_t res[6] = { 0xc0, 0x37, 0xb, 0x9b, 0xa3, 0x3 }; + TEST_CASE("%fast", FAST); + } + + { + uint8_t res[6] = { 0xc0, 0x37, 0xab, 0x63, 0x63, 0x3 }; + TEST_CASE("%full", FULL); + } + + { + uint8_t res[1] = { 0x29 }; + TEST_CASE("[0 0]", NC(0, 0)); + } + + { + uint8_t res[2] = { 0x31, 0x3 }; + TEST_CASE("[1 1]", NC(1, 1)); + } + + { + uint8_t res[2] = { 0x21, 0xd1 }; + TEST_CASE("[2 3]", NC(2, 3)); + } + + { + uint8_t res[11] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0xe, 0x7c, 0xb3, 0x3a, 0x36, 0x36 }; + TEST_CASE("[%fast %full]", NC(FAST, FULL)); + } + + { + uint8_t res[2] = { 0x71, 0xcc }; + TEST_CASE("[1 1 1]", NC(1, NC(1, 1))); + } + + { + uint8_t res[12] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0x1e, 0xf0, 0xcd, 0xea, 0xd8, 0xd8, 0x93 }; + TEST_CASE("[%fast %full %fast]", NC(FAST, NC(FULL, FAST))); + } + + { + uint8_t res[6] = { 0xa5, 0x35, 0x19, 0xf3, 0x18, 0x5 }; + TEST_CASE("[[0 0] [[0 0] 1 1] 1 1]", NC(NC(0, 0), NC(NC(NC(0, 0), NC(1, 1)), NC(1, 1)))); + } + + { + uint8_t res[14] = { 0x15, 0x17, 0xb2, 0xd0, 0x85, 0x59, 0xb8, 0x61, 0x87, 0x5f, 0x10, 0x54, 0x55, 0x5 }; + TEST_CASE("deep", NC(NC(NC(1, NC(NC(2, NC(NC(3, NC(NC(4, NC(NT(5, 6, NC(7, NC(NC(8, 0), 0))), 0)), 0)), 0)), 0)), 0), 0)); + } + + { + uint8_t inp[33] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + uint8_t res[35] = { 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }; + TEST_CASE("wide", ur_coin_bytes(r, sizeof(inp), inp)); + } + + { + uint8_t inp[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xa8, 0xab, 0x60, 0xef, 0x2d, 0xd, 0x0, 0x0, 0x80 }; + uint8_t res[19] = { 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x50, 0x57, 0xc1, 0xde, 0x5b, 0x1a, 0x0, 0x0, 0x0, 0x1 }; + TEST_CASE("date", ur_coin_bytes(r, sizeof(inp), inp)); + } + + ur_root_free(r); + + return ret; +} + +static int +_test_ur(void) +{ + int ret = 1; + + if ( !_test_bsw() ) { + fprintf(stderr, "ur test bsw failed\r\n"); + ret = 0; + } + + if ( !_test_bsr() ) { + fprintf(stderr, "ur test bsr failed\r\n"); + ret = 0; + } + + if ( !_test_jam_cue() ) { + fprintf(stderr, "ur test jam/cue failed\r\n"); + ret = 0; + } + + return ret; +} + +int +main(int argc, char* argv[]) +{ + if ( !_test_ur() ) { + fprintf(stderr, "ur test failed\r\n"); + return 1; + } + + fprintf(stderr, "ur ok\n"); + return 0; +} |