package base32_test; import base32; fn putstr(s: str, into: []u8, off: i32) i32 = { let i: i32 = 0; for (i < s.len) { into[off + i] = s[i]; i += 1; }; return off + s.len; }; fn streq(buf: []u8, expect: str) bool = { if (buf.len != expect.len) { return false; }; let i: i32 = 0; for (i < buf.len) { if (buf[i] != expect[i]) { return false; }; i += 1; }; return true; }; fn encvec(input: str, expect: str) void = { let inbuf: [128]u8; let outbuf: [128]u8; let n: i32 = putstr(input, inbuf[0:128], 0); let m: i32 = base32.encode(outbuf[0:128], inbuf[0:n]); assert(!(m != expect.len)); assert(!(!streq(outbuf[0:m], expect))); }; @test fn rfc4648_std() void = { // RFC 4648 §10 test vectors. encvec("", ""); encvec("f", "MY======"); encvec("fo", "MZXQ===="); encvec("foo", "MZXW6==="); encvec("foob", "MZXW6YQ="); encvec("fooba", "MZXW6YTB"); encvec("foobar", "MZXW6YTBOI======"); }; fn decvec(input: str, expect: str) void = { let inbuf: [128]u8; let outbuf: [128]u8; let n: i32 = putstr(input, inbuf[0:128], 0); let r: (i32 | base32.invalid) = base32.decode(outbuf[0:128], inbuf[0:n]); match (r) { case let m: i32 => { assert(!(m != expect.len)); assert(!(!streq(outbuf[0:m], expect))); }; case let e: base32.invalid => { abort(); }; }; }; @test fn rfc4648_decode() void = { decvec("", ""); decvec("MY======", "f"); decvec("MZXQ====", "fo"); decvec("MZXW6===", "foo"); decvec("MZXW6YQ=", "foob"); decvec("MZXW6YTB", "fooba"); decvec("MZXW6YTBOI======", "foobar"); }; fn enchexvec(input: str, expect: str) void = { let inbuf: [128]u8; let outbuf: [128]u8; let n: i32 = putstr(input, inbuf[0:128], 0); let m: i32 = base32.encodehex(outbuf[0:128], inbuf[0:n]); assert(!(m != expect.len)); assert(!(!streq(outbuf[0:m], expect))); }; @test fn rfc4648_hex() void = { // RFC 4648 §10 base32hex vectors. enchexvec("", ""); enchexvec("f", "CO======"); enchexvec("fo", "CPNG===="); enchexvec("foo", "CPNMU==="); enchexvec("foob", "CPNMUOG="); enchexvec("fooba", "CPNMUOJ1"); enchexvec("foobar", "CPNMUOJ1E8======"); }; @test fn roundtrip_all_quintets() void = { // Encode then decode every 5-byte combination of a small set. let raw: [5]u8; raw[0] = 0x00u8; raw[1] = 0x55u8; raw[2] = 0xAAu8; raw[3] = 0xFFu8; raw[4] = 0x01u8; let enc: [16]u8; let dec: [5]u8; let m: i32 = base32.encode(enc[0:16], raw[0:5]); assert(!(m != 8)); let r: (i32 | base32.invalid) = base32.decode(dec[0:5], enc[0:m]); match (r) { case let n: i32 => { assert(!(n != 5)); let i: i32 = 0; for (i < 5) { assert(!(dec[i] != raw[i])); i += 1; }; }; case let e: base32.invalid => { abort(); }; }; }; @test fn invalid_inputs() void = { let inbuf: [16]u8; let outbuf: [16]u8; // Length not a multiple of 8. let n: i32 = putstr("ABCD", inbuf[0:16], 0); let r1: (i32 | base32.invalid) = base32.decode(outbuf[0:16], inbuf[0:n]); match (r1) { case let m: i32 => { abort(); }; case let e: base32.invalid => void; }; // Bad pad count (5 '=' is illegal — must be 0,1,3,4,6). let n2: i32 = putstr("MZX=====", inbuf[0:16], 0); let r2: (i32 | base32.invalid) = base32.decode(outbuf[0:16], inbuf[0:n2]); match (r2) { case let m: i32 => { abort(); }; case let e: base32.invalid => void; }; // Bad char ('1' is not in the std alphabet). let n3: i32 = putstr("MZ1W6YTB", inbuf[0:16], 0); let r3: (i32 | base32.invalid) = base32.decode(outbuf[0:16], inbuf[0:n3]); match (r3) { case let m: i32 => { abort(); }; case let e: base32.invalid => void; }; }; @test fn sizes() void = { assert(!(base32.encodedsize(0) != 0)); assert(!(base32.encodedsize(1) != 8)); assert(!(base32.encodedsize(5) != 8)); assert(!(base32.encodedsize(6) != 16)); assert(!(base32.decodedsize(8) != 5)); assert(!(base32.decodedsize(16) != 10)); }; export fn main() i32 = { rfc4648_std(); rfc4648_decode(); rfc4648_hex(); roundtrip_all_quintets(); invalid_inputs(); sizes(); return 0; };