summaryrefslogtreecommitdiff
path: root/vere/pkg/ur/tests.c
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/ur/tests.c
claude is gud
Diffstat (limited to 'vere/pkg/ur/tests.c')
-rw-r--r--vere/pkg/ur/tests.c1862
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;
+}