// Standalone tests for reasampler::wire — no REAPER, no framework. The ONE // length-prefixed ext-state wire codec (Q-W1, T2-01b) behind provenance / // assignment_request / sample_usage / bank_sync. The consumers' own suites // prove their record grammars round-trip; this suite pins the CODEC contract — // byte-exact encode, the full hardening (length caps, overflow guards, // subtraction-first bounds), and the fixed fieldInt range rejection. // // NOTE: wire::Cursor BORROWS its input string, so every helper takes a named / // reference-bound std::string — the Cursor never outlives its buffer. #include "../src/core/wire/wire.h" #include #include using namespace reasampler; using namespace reasampler::wire; static int g_fail = 0; #define CHECK(cond) do { if(!(cond)) { \ std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0) // One length-prefixed field around `v` — the writer-side convention. static std::string enc(const std::string& v) { std::string out; wire::putField(out, v); return out; } // Single-field decode helpers (Cursor + buffer share the call's lifetime). static bool fieldFrom(const std::string& s, std::string& out) { wire::Cursor c(s); return c.field(out); } static bool i64From(const std::string& s, std::int64_t& out) { wire::Cursor c(s); return c.fieldInt64(out); } static bool intFrom(const std::string& s, int& out) { wire::Cursor c(s); return c.fieldInt(out); } static bool sizeFrom(const std::string& s, std::size_t& out) { wire::Cursor c(s); return c.fieldSizeT(out); } static bool dblFrom(const std::string& s, double& out) { wire::Cursor c(s); return c.fieldDouble(out); } // --- putField: byte-exact encode ---------------------------------------------- static void testPutFieldExactBytes() { std::string out; wire::putField(out, "abc"); CHECK(out == "3:abc"); wire::putField(out, ""); // empty field is legal: "0:" CHECK(out == "3:abc0:"); wire::putField(out, "a:b"); // ':' inside a value cannot shift the parse CHECK(out == "3:abc0:3:a:b"); } // --- Cursor: round-trip + literal --------------------------------------------- static void testFieldRoundTripIncludingSeparators() { std::string out = "magic"; wire::putField(out, "12:34"); // digits + colons in the value wire::putField(out, ""); wire::putField(out, "tail"); wire::Cursor c(out); std::string a, b, t; CHECK(c.literal("magic")); CHECK(c.field(a) && a == "12:34"); CHECK(c.field(b) && b.empty()); CHECK(c.field(t) && t == "tail"); CHECK(c.ok() && c.atEnd()); } static void testLiteralMismatchFails() { const std::string good = "rsprov1x"; const std::string wrong = "rsprov0x"; const std::string truncated = "rspro"; { wire::Cursor c(good); CHECK(c.literal("rsprov1")); } { wire::Cursor c(wrong); CHECK(!c.literal("rsprov1")); CHECK(!c.ok()); } { wire::Cursor c(truncated); CHECK(!c.literal("rsprov1")); } } // --- Cursor: field hardening --------------------------------------------------- static void testFieldRejectsMalformedLengths() { std::string f; CHECK(!fieldFrom("abc", f)); // no colon CHECK(!fieldFrom(":x", f)); // empty length CHECK(!fieldFrom("2x:ab", f)); // non-digit length CHECK(!fieldFrom("9:ab", f)); // runs past end // A 200-digit length cannot accumulate past SIZE_MAX (digit-run cap). CHECK(!fieldFrom(std::string(200, '9') + ":x", f)); // Exactly-20-digit values: SIZE_MAX itself passes the accumulate but fails the // bounds check; one past SIZE_MAX trips the overflow guard. CHECK(!fieldFrom("18446744073709551615:x", f)); CHECK(!fieldFrom("18446744073709551616:x", f)); } static void testFailureLatchesOk() { // After one failed read every subsequent read fails too — the caller may // check ok() once at the end (the "never a partial value" discipline). const std::string s = "3:abc"; wire::Cursor c(s); std::string f; CHECK(!c.literal("nope")); CHECK(!c.field(f)); CHECK(!c.ok()); } // --- Cursor: fieldInt64 / fieldInt -------------------------------------------- static void testFieldInt64AcceptsAndRejects() { std::int64_t v = 0; CHECK(i64From(enc("12345"), v)); CHECK(v == 12345); CHECK(i64From(enc("-42"), v)); CHECK(v == -42); CHECK(i64From(enc("9223372036854775807"), v)); // INT64_MAX CHECK(v == 9223372036854775807LL); CHECK(!i64From(enc("9223372036854775808"), v)); // overflow CHECK(!i64From(enc("12345678901234567890"), v)); // 20-digit cap CHECK(!i64From(enc("-"), v)); // bare sign CHECK(!i64From(enc("1a"), v)); // non-digit CHECK(!i64From(enc(""), v)); // empty } static void testFieldIntRejectsOutOfIntRange() { // The fixed form of the old provenance strtol TODO: an out-of-int-range field // FAILS the parse instead of silently narrowing. int v = 0; CHECK(intFrom(enc("2147483647"), v)); CHECK(v == 2147483647); CHECK(intFrom(enc("-2147483648"), v)); CHECK(v == -2147483647 - 1); CHECK(!intFrom(enc("2147483648"), v)); CHECK(!intFrom(enc("3000000000"), v)); } // --- Cursor: fieldSizeT / fieldDouble ------------------------------------------ static void testFieldSizeT() { std::size_t v = 1; CHECK(sizeFrom(enc("0"), v)); CHECK(v == 0); CHECK(sizeFrom(enc("4096"), v)); CHECK(v == 4096); CHECK(!sizeFrom(enc("-1"), v)); // sign = non-digit CHECK(!sizeFrom(enc(std::string(21, '9')), v)); // 21-digit cap CHECK(!sizeFrom(enc("18446744073709551616"), v)); // overflow guard } static void testFieldDoubleRoundTrip() { char buf[32]; std::snprintf(buf, sizeof(buf), "%.17g", 3141.592653589793); double v = 0; CHECK(dblFrom(enc(buf), v)); CHECK(v == 3141.592653589793); CHECK(!dblFrom(enc("1.5x"), v)); // trailing bytes } // --- parseUnsignedDecimal (the bank_sync generation core) ----------------------- static void testParseUnsignedDecimal() { std::int64_t v = 0; CHECK(wire::parseUnsignedDecimal("0", v) && v == 0); CHECK(wire::parseUnsignedDecimal("1721947293", v) && v == 1721947293); CHECK(wire::parseUnsignedDecimal("9223372036854775807", v) && v == 9223372036854775807LL); CHECK(!wire::parseUnsignedDecimal("", v)); CHECK(!wire::parseUnsignedDecimal("+5", v)); // sign rejected (non-digit) CHECK(!wire::parseUnsignedDecimal("-5", v)); CHECK(!wire::parseUnsignedDecimal("12a", v)); CHECK(!wire::parseUnsignedDecimal("9223372036854775808", v)); // overflow CHECK(!wire::parseUnsignedDecimal(std::string(40, '9'), v)); // long run cannot wrap } int main() { testPutFieldExactBytes(); testFieldRoundTripIncludingSeparators(); testLiteralMismatchFails(); testFieldRejectsMalformedLengths(); testFailureLatchesOk(); testFieldInt64AcceptsAndRejects(); testFieldIntRejectsOutOfIntRange(); testFieldSizeT(); testFieldDoubleRoundTrip(); testParseUnsignedDecimal(); if (g_fail == 0) std::printf("wire: all tests passed\n"); else std::printf("wire: %d CHECK(s) FAILED\n", g_fail); return g_fail == 0 ? 0 : 1; }