--- /dev/null
+/bool.t
+/compile_flags.txt
+/hexlet.t
+/magic.t
+/nil.t
+/tai.t
+/tai64.t
--- /dev/null
+redo-ifchange $(cat t.list)
--- /dev/null
+#include <stdbool.h>
+#include <stdlib.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/atom.h>
+#include <keks/enc.h>
+#include <keks/err.h>
+#include <keks/items.h>
+
+static void
+test(
+ bool (*encode)(size_t *len, unsigned char *buf, const size_t cap, const bool v),
+ enum KEKSItemType typ,
+ const bool encodeVal,
+ unsigned char binVal)
+{
+ size_t len = 0;
+ unsigned char buf[] = {0, 0};
+ size_t cap = 0;
+ ok(!encode(&len, buf, cap, encodeVal), "atom small buf");
+ ok(len == 1, "atom small buf len");
+
+ cap = 1;
+ len = 0;
+ ok(encode(&len, buf, cap, encodeVal), "atom encode");
+ ok(len == 1, "atom len");
+ ok(buf[0] == binVal, "atom val");
+
+ struct KEKSItems items;
+ KEKSItemsInit(&items, 1 + 1);
+ size_t off = 0;
+ enum KEKSErr err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "parse");
+ ok(off == 1, "parse off");
+ ok(items.reallocs == 0, "parse no reallocs");
+ ok(items.len == 1, "parse len");
+ ok(items.offsets[0] == 0, "parse offset");
+ struct KEKSItem item = items.list[0];
+ ok(item.next == 0, "atom next");
+ ok(item.atom.typ == typ, "atom typ");
+
+ cap = 0;
+ off = 0;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode small buf");
+ ok(off == 0, "items encode off");
+ cap = sizeof buf;
+ ok(KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode");
+ ok(off == 1, "items encode off");
+ ok(buf[0] == binVal, "items encode val");
+}
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ test(KEKSAtomBoolEncode, KEKSItemFalse, false, 0x02);
+ test(KEKSAtomBoolEncode, KEKSItemTrue, true, 0x03);
+
+ return exit_status();
+}
--- /dev/null
+#!/bin/sh -e
+
+rm -f $(cat t.list) compile_flags.txt
--- /dev/null
+redo-ifchange ../conf/prefix conf/tap.rc
+read PREFIX <../conf/prefix
+printf "%s\n" "-I$PREFIX/include"
+. conf/tap.rc
+printf "%s\n" "$TAP_CFLAGS"
--- /dev/null
+PKGCONF=${PKGCONF:-`command -v pkgconf || command -v pkg-config`}
+cat <<EOF
+{
+ read TAP_CFLAGS
+ read TAP_LDFLAGS
+ read TAP_LDLIBS
+} <<EOF
+EOF
+$PKGCONF --cflags tap
+$PKGCONF --libs-only-L tap
+$PKGCONF --libs-only-l tap
+echo EOF
--- /dev/null
+redo-ifchange $1.c \
+ ../conf/cc \
+ ../conf/cflags \
+ ../conf/ldflags \
+ ../conf/prefix \
+ conf/tap.rc
+read CC <../conf/cc
+CFLAGS=$(cat ../conf/cflags)
+LDFLAGS=$(cat ../conf/ldflags)
+read PREFIX <../conf/prefix
+. conf/tap.rc
+$CC $CFLAGS -I$PREFIX/include $TAP_CFLAGS -o $3 $1.c \
+ $LDFLAGS $TAP_LDFLAGS -L$PREFIX/lib -lkeks $TAP_LDLIBS
--- /dev/null
+#include <string.h>
+#include <sys/random.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/atom.h>
+#include <keks/enc.h>
+#include <keks/err.h>
+#include <keks/items.h>
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ unsigned char hexlet[16] = {0};
+ getrandom(hexlet, 16, 0);
+
+ size_t len = 0;
+ unsigned char buf[16 + 1] = {0};
+ size_t cap = 16;
+ ok(!KEKSAtomHexletEncode(&len, buf, cap, hexlet), "atom small buf");
+ ok(len == 16 + 1, "atom small buf len");
+
+ cap = 16 + 1;
+ len = 0;
+ ok(KEKSAtomHexletEncode(&len, buf, cap, hexlet), "atom encode");
+ ok(len == 16 + 1, "atom len");
+ ok(buf[0] == 0x04, "atom tag");
+ ok(memcmp(buf + 1, hexlet, 16) == 0, "atom val");
+
+ struct KEKSItems items;
+ KEKSItemsInit(&items, 1 + 1);
+ size_t off = 0;
+ enum KEKSErr err = KEKSItemsParse(&items, &off, buf, cap - 1);
+ ok(err == KEKSErrNotEnough, "parse not enough");
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "parse");
+ ok(off == 16 + 1, "parse off");
+ ok(items.reallocs == 0, "parse no reallocs");
+ ok(items.len == 1, "parse len");
+ ok(items.offsets[0] == 0, "parse offset");
+ struct KEKSItem item = items.list[0];
+ ok(item.next == 0, "atom next");
+ ok(item.atom.typ == KEKSItemHexlet, "atom typ");
+ ok(memcmp(item.atom.v.str.ptr, hexlet, 16) == 0, "atom val ptr");
+ ok(item.atom.v.str.len == 16, "atom val len");
+
+ cap = 0;
+ off = 0;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode small buf");
+ ok(off == 0, "items encode off");
+ cap = sizeof buf;
+ ok(KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode");
+ ok(off == 16 + 1, "items encode off");
+ ok(buf[0] == 0x04, "items encode tag");
+ ok(memcmp(buf + 1, hexlet, 16) == 0, "items encode val");
+
+ return exit_status();
+}
--- /dev/null
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/random.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/atom.h>
+#include <keks/enc.h>
+#include <keks/err.h>
+#include <keks/items.h>
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ unsigned char magic[12] = {0};
+ getrandom(magic, 12, 0);
+ magic[11] = 123;
+
+ size_t len = 0;
+ unsigned char buf[16] = {0};
+ size_t cap = 16 - 1;
+ ok(!KEKSAtomMagicEncode(&len, buf, cap, magic, 13), "atom too long");
+ ok(len == 0, "atom too long len");
+ ok(!KEKSAtomMagicEncode(&len, buf, cap, magic, 12), "atom small buf");
+ ok(len == 16, "atom small buf len");
+
+ cap = 16;
+ len = 0;
+ ok(KEKSAtomMagicEncode(&len, buf, cap, magic, 12), "atom encode");
+ ok(len == 16, "atom len");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "atom tag");
+ ok(memcmp(buf + 4, magic, 12) == 0, "atom val");
+
+ struct KEKSItems items;
+ KEKSItemsInit(&items, 1 + 1);
+ size_t off = 0;
+ enum KEKSErr err = KEKSItemsParse(&items, &off, buf, cap - 1);
+ ok(err == KEKSErrNotEnough, "parse not enough");
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "parse");
+ ok(off == 16, "parse off");
+ ok(items.reallocs == 0, "parse no reallocs");
+ ok(items.len == 1, "parse len");
+ ok(items.offsets[0] == 0, "parse offset");
+ struct KEKSItem item = items.list[0];
+ ok(item.next == 0, "atom next");
+ ok(item.atom.typ == KEKSItemMagic, "atom typ");
+ ok(item.atom.v.str.len == 12, "atom typ");
+ ok(memcmp(item.atom.v.str.ptr, magic, 12) == 0, "atom val");
+
+ cap = 0;
+ off = 0;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode small buf");
+ ok(off == 0, "items encode off");
+ cap = sizeof buf;
+ ok(KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode");
+ ok(off == 16, "items encode off");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "items encode tag");
+ ok(memcmp(buf + 4, magic, 12) == 0, "items encode val");
+
+ cap = sizeof buf;
+ item.atom.v.str.len = 12 + 1;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode too long");
+ ok(off == 16, "items encode too long off");
+
+ // ------------------------ >8 ------------------------
+
+ memset(magic + 7, 0, 5);
+
+ cap = 16;
+ len = 0;
+ ok(KEKSAtomMagicEncode(&len, buf, cap, magic, 7), "shorter atom encode");
+ ok(len == 16, "shorter atom len");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "shorter atom tag");
+ ok(memcmp(buf + 4, magic, 7) == 0, "shorter atom val");
+ ok(memcmp(buf + 4 + 7, (const unsigned char *)"\x00\x00\x00\x00\x00", 5) == 0,
+ "shorter atom suffix");
+
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "shorter parse");
+ ok(off == 16, "parse off");
+ ok(items.reallocs == 0, "shorter parse no reallocs");
+ ok(items.len == 1, "shorter parse len");
+ ok(items.offsets[0] == 0, "shorter parse offset");
+ item = items.list[0];
+ ok(item.next == 0, "shorter atom next");
+ ok(item.atom.typ == KEKSItemMagic, "shorter atom typ");
+ ok(item.atom.v.str.len == 7, "shorter atom typ");
+ ok(memcmp(item.atom.v.str.ptr, magic, 7) == 0, "shorter atom val");
+
+ cap = 0;
+ off = 0;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "shorter items encode small buf");
+ ok(off == 0, "shorter items encode off");
+ cap = sizeof buf;
+ ok(KEKSItemsEncode(&items, 0, &off, buf, cap), "shorter items encode");
+ ok(off == 16, "shorter items encode off");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "shorter items encode tag");
+ ok(memcmp(buf + 4, magic, 7) == 0, "shorter items encode val");
+ ok(memcmp(buf + 4 + 7, (const unsigned char *)"\x00\x00\x00\x00\x00", 5) == 0,
+ "shorter atom suffix");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 16;
+ len = 0;
+ ok(KEKSAtomMagicEncode(&len, buf, cap, NULL, 0), "atom encode empty");
+ ok(len == 16, "atom empty len");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "atom empty tag");
+ {
+ bool allZeros = true;
+ for (size_t i = 0; i < 12; i++) {
+ if (buf[4 + i] != 0) {
+ allZeros = false;
+ }
+ }
+ ok(allZeros, "atom empty val");
+ }
+
+ // ------------------------ >8 ------------------------
+
+ cap = 16;
+ len = 0;
+ ok(KEKSAtomMagicEncode(&len, buf, cap, NULL, 0), "atom encode empty");
+ ok(len == 16, "atom empty len");
+ ok(memcmp(buf, (const unsigned char *)"KEKS", 4) == 0, "atom empty tag");
+ {
+ bool allZeros = true;
+ for (size_t i = 0; i < 12; i++) {
+ if (buf[4 + i] != 0) {
+ allZeros = false;
+ }
+ }
+ ok(allZeros, "atom empty val");
+ }
+
+ // ------------------------ >8 ------------------------
+
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ buf[0] = 'K';
+ buf[1] = 'E';
+ buf[2] = 'K';
+ buf[3] = 's';
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrBadMagic, "bad magic KEKs");
+ buf[0] = 'K';
+ buf[1] = 'e';
+ buf[2] = 'K';
+ buf[3] = 'S';
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrBadMagic, "bad magic KeKS");
+
+ return exit_status();
+}
--- /dev/null
+#include <stdlib.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/atom.h>
+#include <keks/enc.h>
+#include <keks/err.h>
+#include <keks/items.h>
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ size_t len = 0;
+ unsigned char buf[] = {0, 0};
+ size_t cap = 0;
+ ok(!KEKSAtomNILEncode(&len, buf, cap), "atom small buf");
+ ok(len == 1, "atom small buf len");
+
+ cap = 1;
+ len = 0;
+ ok(KEKSAtomNILEncode(&len, buf, cap), "atom encode");
+ ok(len == 1, "atom len");
+ ok(buf[0] == 0x01, "atom val");
+
+ struct KEKSItems items;
+ KEKSItemsInit(&items, 1 + 1);
+ size_t off = 0;
+ enum KEKSErr err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "parse");
+ ok(off == 1, "parse off");
+ ok(items.reallocs == 0, "parse no reallocs");
+ ok(items.len == 1, "parse len");
+ ok(items.offsets[0] == 0, "parse offset");
+ struct KEKSItem item = items.list[0];
+ ok(item.next == 0, "atom next");
+ ok(item.atom.typ == KEKSItemNIL, "atom typ");
+
+ cap = 0;
+ off = 0;
+ ok(!KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode small buf");
+ ok(off == 0, "items encode off");
+ cap = sizeof buf;
+ ok(KEKSItemsEncode(&items, 0, &off, buf, cap), "items encode");
+ ok(off == 1, "items encode off");
+ ok(buf[0] == 0x01, "items encode val");
+
+ return exit_status();
+}
--- /dev/null
+bool.t
+hexlet.t
+magic.t
+nil.t
+tai.t
+tai64.t
--- /dev/null
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/random.h>
+#include <time.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/dectai.h>
+#include <keks/enctai.h>
+#include <keks/err.h>
+#include <keks/frombe.h>
+#include <keks/leapsecs.h>
+#include <keks/tobe.h>
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ unsigned char src[8] = {0};
+ getrandom(src, 4, 0);
+ struct timespec ts;
+ ts.tv_sec = (time_t)(0xFFFFFFFFFFFFFFFF - keksFromBE(src + 0, 4) % 1000000);
+ ts.tv_nsec = 0;
+ unsigned char buf[16] = {0};
+ ok(!KEKSTimespecToTAI64(buf, &ts), "too big secs");
+
+ getrandom(src, 8, 0);
+ ts.tv_sec = (time_t)(keksFromBE(src + 0, 8) % 0x4000000000000000);
+ ok(KEKSTimespecToTAI64(buf, &ts), "secs ok");
+ ok(memcmp(buf + 1 + 8, (const unsigned char *)"\x00\x00\x00\x00", 4) == 0,
+ "ns empty");
+
+ ts.tv_nsec = (long)(1000000000 + 1);
+ ok(!KEKSTimespecToTAI64(buf, &ts), "too big ns");
+
+ getrandom(src, 4, 0);
+ keksToBE(src, 4, keksFromBE(src, 4) % 1000000000);
+ ts.tv_nsec = (long)(keksFromBE(src, 4));
+ ok(KEKSTimespecToTAI64(buf, &ts), "ns ok");
+ ok(keksFromBE(buf + 8, 4) == keksFromBE(src, 4), "ns eq");
+
+ // ------------------------ >8 ------------------------
+
+ ts.tv_sec = (time_t)(0xFFFFFFFFFFFFFFFF);
+ ok(!KEKSTimespecToTAI(&ts), "to tai overflow, negative");
+
+ ts.tv_sec = (time_t)(0x8000000000000000 - 1);
+ ok(!KEKSTimespecToTAI(&ts), "to tai overflow, too big positive");
+
+ // ------------------------ >8 ------------------------
+
+ ts.tv_nsec = 0;
+ enum KEKSErr err = KEKSErrNo;
+ bool failed = false;
+ for (size_t i = 0; i < 1000; i++) {
+ getrandom(src, 4, 0);
+ ts.tv_sec = (time_t)(keksFromBE(src, 4));
+ if (!KEKSTimespecToTAI(&ts)) {
+ failed = false;
+ break;
+ }
+ err = KEKSTimespecToUTC(&ts);
+ if (err != KEKSErrNo) {
+ failed = false;
+ break;
+ }
+ }
+ ok(!failed, "symmetric ok");
+
+ // ------------------------ >8 ------------------------
+
+ ts.tv_sec = -1;
+ ok(KEKSTimespecToUTC(&ts) == KEKSErrTAI64InPast, "to utc, negative");
+
+ ts.tv_sec = 9;
+ ok(KEKSTimespecToUTC(&ts) == KEKSErrTAI64InPast, "to utc, in past");
+
+ // ------------------------ >8 ------------------------
+
+ for (size_t i = 0; i < KEKSLeapsecsN; i++) {
+ ts.tv_sec = (time_t)(KEKSLeapsecs[i]);
+ ok(KEKSTimespecToUTC(&ts) == KEKSErrTAI64IsLeap, "to utc, leap");
+ ts.tv_sec++;
+ ok(KEKSTimespecToUTC(&ts) == KEKSErrNo, "to utc, non-leap");
+ }
+
+ // ------------------------ >8 ------------------------
+
+ ok(KEKSTAI64ToTimespec(&ts, NULL, 13) == KEKSErrTAI64BadAsec, "too long");
+ ok(KEKSTAI64ToTimespec(&ts, NULL, 11) == KEKSErrTAI64BadAsec, "bad len");
+ ok(KEKSTAI64ToTimespec(&ts, NULL, 7) == KEKSErrTAI64BadAsec, "too short");
+
+ ok(KEKSTAI64ToTimespec(
+ &ts, (const unsigned char *)"\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) ==
+ KEKSErrTAI64InPast,
+ "in past");
+ ok(KEKSTAI64ToTimespec(
+ &ts, (const unsigned char *)"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) ==
+ KEKSErrTAI64TooBig,
+ "too big");
+
+ ok(KEKSTAI64ToTimespec(
+ &ts,
+ (const unsigned char *)"\x40\xFF\x00\x00\x00\x00\x00\x10\x3B\xA0\x00\x00",
+ 12) == KEKSErrTAI64BadNsec,
+ "too big ns");
+
+ return exit_status();
+}
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <sys/random.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+#include <tap.h>
+#pragma clang diagnostic pop
+
+#include <keks/atom.h>
+#include <keks/enc.h>
+#include <keks/err.h>
+#include <keks/frombe.h>
+#include <keks/items.h>
+#include <keks/tobe.h>
+
+int
+main(void)
+{
+ plan(NO_PLAN);
+
+ unsigned char src[16] = {0};
+ getrandom(src, 16, 0);
+ size_t len = 0;
+ unsigned char buf[16 + 1] = {0};
+
+ // ------------------------ >8 ------------------------
+
+ size_t cap = 16;
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 8 - 1), "64: bad src len");
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 8 + 1), "64: bad src len");
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 12 - 1), "64N: bad src len");
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 12 + 1), "64N: bad src len");
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 16 - 1), "64NA: bad src len");
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 16 + 1), "64NA: bad src len");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 8;
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 8), "64: encode small buf");
+ ok(len == 8 + 1, "64: encode small buf len");
+ cap = 12;
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 12), "64N: encode small buf");
+ ok(len == 12 + 1, "64: encode small buf len");
+ cap = 16;
+ ok(!KEKSAtomTAI64Encode(&len, buf, cap, src, 16), "64NA: encode small buf");
+ ok(len == 16 + 1, "64: encode small buf len");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 8 + 1;
+ ok(KEKSAtomTAI64Encode(&len, buf, cap, src, 8), "64: encode");
+ ok(len == 8 + 1, "64: encode len");
+ ok(buf[0] == 0x18, "64: tag");
+ ok(memcmp(buf + 1, src, 8) == 0, "64: val");
+
+ cap = 12 + 1;
+ ok(KEKSAtomTAI64Encode(&len, buf, cap, src, 12), "64N: encode");
+ ok(len == 12 + 1, "64N: encode len");
+ ok(buf[0] == 0x19, "64N: tag");
+ ok(memcmp(buf + 1, src, 12) == 0, "64N: val");
+
+ cap = 16 + 1;
+ ok(KEKSAtomTAI64Encode(&len, buf, cap, src, 16), "64NA: encode");
+ ok(len == 16 + 1, "64NA: encode len");
+ ok(buf[0] == 0x1A, "64NA: tag");
+ ok(memcmp(buf + 1, src, 16) == 0, "64NA: val");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 8 + 1;
+ src[0] &= (unsigned char)0x7F;
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 8);
+ struct KEKSItems items;
+ KEKSItemsInit(&items, 1 + 1);
+ size_t off = 0;
+ enum KEKSErr err = KEKSItemsParse(&items, &off, buf, cap - 1);
+ ok(err == KEKSErrNotEnough, "64: parse not enough");
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "64: parse");
+ ok(off == 8 + 1, "64: parse off");
+ ok(items.reallocs == 0, "64: parse no reallocs");
+ ok(items.len == 1, "64: parse len");
+ ok(items.offsets[0] == 0, "64: parse offset");
+ struct KEKSItem item = items.list[0];
+ ok(item.next == 0, "64: atom next");
+ ok(item.atom.typ == KEKSItemTAI64, "64: atom typ");
+ ok(item.atom.v.str.len == 8, "64: atom len");
+ ok(memcmp(item.atom.v.str.ptr, src, 8) == 0, "64: atom val");
+ src[0] |= (unsigned char)0x80;
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 8);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64TooBig, "64: highest bit set");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 12 + 1;
+ src[0] &= (unsigned char)0x7F;
+ memset(src + 8, 0, 4);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 12);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64NonMinimal, "64N: parse non-minimal");
+
+ getrandom(src + 8, 4, 0);
+ keksToBE(src + 8, 4, keksFromBE(src + 8, 4) % 1000000000);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 12);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap - 1);
+ ok(err == KEKSErrNotEnough, "64N: parse not enough");
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "64N: parse");
+ ok(off == 12 + 1, "64N: parse off");
+ ok(items.reallocs == 0, "64N: parse no reallocs");
+ ok(items.len == 1, "64N: parse len");
+ ok(items.offsets[0] == 0, "64N: parse offset");
+ item = items.list[0];
+ ok(item.next == 0, "64N: atom next");
+ ok(item.atom.typ == KEKSItemTAI64, "64N: atom typ");
+ ok(item.atom.v.str.len == 12, "64N: atom len");
+ ok(memcmp(item.atom.v.str.ptr, src, 12) == 0, "64N: atom val");
+
+ keksToBE(src + 8, 4, keksFromBE(src + 8, 4) + 1000000000);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 12);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64BadNsec, "64N: bad N");
+
+ src[0] |= (unsigned char)0x80;
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 12);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64TooBig, "64N: highest bit set");
+
+ // ------------------------ >8 ------------------------
+
+ cap = 16 + 1;
+ src[0] &= (unsigned char)0x7F;
+ keksToBE(src + 8, 4, keksFromBE(src + 8, 4) % 1000000000);
+ memset(src + 12, 0, 4);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 16);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64NonMinimal, "64NA: parse non-minimal");
+
+ memset(src + 8, 0, 4);
+ getrandom(src + 12, 4, 0);
+ keksToBE(src + 12, 4, keksFromBE(src + 12, 4) % 1000000000);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 16);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap - 1);
+ ok(err == KEKSErrNotEnough, "64NA: parse not enough");
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrNo, "64NA: parse");
+ ok(off == 16 + 1, "64NA: parse off");
+ ok(items.reallocs == 0, "64NA: parse no reallocs");
+ ok(items.len == 1, "64NA: parse len");
+ ok(items.offsets[0] == 0, "64NA: parse offset");
+ item = items.list[0];
+ ok(item.next == 0, "64NA: atom next");
+ ok(item.atom.typ == KEKSItemTAI64, "64NA: atom typ");
+ ok(item.atom.v.str.len == 16, "64NA: atom len");
+ ok(memcmp(item.atom.v.str.ptr, src, 16) == 0, "64NA: atom val");
+
+ keksToBE(src + 12, 4, keksFromBE(src + 12, 4) + 1000000000);
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 16);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64BadAsec, "64NA: bad A");
+
+ src[0] |= (unsigned char)0x80;
+ KEKSAtomTAI64Encode(&len, buf, cap, src, 16);
+ KEKSItemsFree(&items);
+ KEKSItemsInit(&items, 1 + 1);
+ off = 0;
+ err = KEKSItemsParse(&items, &off, buf, cap);
+ ok(err == KEKSErrTAI64TooBig, "64NA: highest bit set");
+
+ return exit_status();
+}