ref: 9bf446ab7795f7397bc4fb7ae9e46ce14c3f679c
dir: /lib/flate/test/flate.myr/
use bio use flate use std use testr impl std.equatable std.result(int, flate.err) = eq = {a, b match (a, b) | (`std.Ok na, `std.Ok nb): -> na == nb | (`std.Err (`flate.Io ea), `std.Err (`flate.Io eb)): -> ea == eb | (`std.Err (`flate.Format ea), `std.Err (`flate.Format eb)): -> std.sleq(ea, eb) | _: -> false ;; } ;; const init = {in -> flate.flatedec# -> std.mk([ .rdf = bio.mkmem(in), .bpos = 8, ]) } const eof = `std.Err (`flate.Io `bio.Eof) const bits = {ctx var st st = init("") testr.eq(ctx, flate.bits(st, 1), eof) st = init(" ") testr.eq(ctx, flate.bits(st, 9), eof) /* simple bit reading */ st = init("\xaa") testr.eq(ctx, flate.bits(st, 0), `std.Ok 0) testr.eq(ctx, flate.bits(st, 1), `std.Ok 0) testr.eq(ctx, flate.bits(st, 1), `std.Ok 1) testr.eq(ctx, flate.bits(st, 2), `std.Ok 2) testr.eq(ctx, flate.bits(st, 3), `std.Ok 2) testr.eq(ctx, flate.bits(st, 2), eof) /* reading across byte boundaries */ st = init("\xaa\xaa") testr.eq(ctx, flate.bits(st, 2), `std.Ok 2) testr.eq(ctx, flate.bits(st, 8+2), `std.Ok 0x2aa) testr.eq(ctx, flate.bits(st, 1), `std.Ok 0) testr.eq(ctx, flate.bits(st, 4), eof) /* reading whole bytes */ st = init("\xab\xcd") testr.eq(ctx, flate.bits(st, 8), `std.Ok 0xab) testr.eq(ctx, flate.bits(st, 8), `std.Ok 0xcd) /* refilling */ st = init("") var n = 0 var pn = &n st.rdf = bio.mk(bio.Rd, [ .read = {buf buf[0] = (++pn# : byte) -> `std.Ok 1 } ]) testr.eq(ctx, flate.bits(st, 3), `std.Ok 1) testr.eq(ctx, flate.bits(st, 8), `std.Ok (2 << 5)) testr.eq(ctx, flate.bits(st, 10), `std.Ok (3 << 5)) } const mkhufc = {ctx var count var ht count = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ][:] flate.mkhufc([][:], &ht) testr.check(ctx, std.eq(ht.count[:], count), "empty code") flate.mkhufc([1, 1][:], &ht) count[1] = 2 testr.check(ctx, std.eq(ht.count[:], count), "1-bit code") testr.eq(ctx, ht.symbol[:2], [0, 1][:]) flate.mkhufc([2, 1, 3, 3][:], &ht) std.slcp(count[1:4], [1, 1, 2][:]) testr.check(ctx, std.eq(ht.count[:], count), "rfc code") testr.eq(ctx, ht.symbol[:4], [1, 0, 2, 3][:]) } const readcode = {ctx var st, ht flate.mkhufc([2, 1, 3, 3][:], &ht) st = init("\xcd\x05") testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 0) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 2) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 1) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 3) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 1) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 0) testr.eq(ctx, st.bpos, 4) /* same as above with some empty codes */ flate.mkhufc([2, 1, 0, 0, 3, 0, 3][:], &ht) st = init("\xcd\x05") testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 0) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 4) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 1) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 6) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 1) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 0) testr.eq(ctx, st.bpos, 4) /* empty codes at the beginning */ flate.mkhufc([0, 0, 0, 4][:], &ht) st = init("\x00") testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 3) testr.eq(ctx, flate.readcode(st, &ht), `std.Ok 3) testr.eq(ctx, flate.readcode(st, &ht), eof) } const bitsf = {str : byte[:] var sl, n, b sl = [][:] n = 0 b = 0 for c : str match (c : char) | '0': n++ | '1': b += (1 << n); n++ | _: /* do nothing */ ;; if n == 8 std.slpush(&sl, (b : byte)) n = 0 b = 0 ;; ;; std.slpush(&sl, (b : byte)) -> bio.mkmem(sl) } const expect = {ctx, t, str var exp exp = std.mk(str) const write = {buf if buf.len > exp#.len testr.fail(ctx, "({}) more bytes written than expected:" \ " '{}' written when expecting '{}'", t, buf, exp#) ;; if !std.eq(buf, exp#[:buf.len]) testr.fail(ctx, "({}) '{}' written when expecting '{}'", t, buf, exp#[:buf.len]) ;; exp# = exp#[buf.len:] -> `std.Ok buf.len } const close = { if exp#.len > 0 testr.fail(ctx, "({}) output closed when still expecting '{}'", t, exp#) ;; -> true } -> bio.mk(bio.Wr, [.write = write, .close = close]) } type errortype = union `None `Eof `Io `Format ;; const decode = {ctx const tests = [ ("empty", "", "", `Eof), ("reserved block", "1 11 00", "", `Format), ("partial block", "1 1", "", `Eof), /* could be `Format error... */ ("uncompressed empty block", "1 00 00000 0000000000000000 1111111111111111", "", `None), ("uncompressed 3-bytes block", "1 00 00000 1100000000000000 0011111111111111" \ "10000110 01000110 11000110", "abc", `None), ("uncompressed 1-byte then 2-bytes block", "0 00 00000 1000000000000000 0111111111111111" \ "10000110" \ "1 00 00000 0100000000000000 1011111111111111" \ "01000110 11000110", "abc", `None), ("uncompressed mismatched len nlen", "1 00 00000 1000000000000000 0111111111111011" \ "10000110", "", `Format), ("fixed code single block", "1 10 10011000 10010101 10011100 10011100" \ "10011111 01010001 0000000", "hello!", `None), ("dynamic code block", // 'r' markers are used when bits must come in "reverse" "1 01" \ "r00000 r00000 r1111" \ // 257 literal, 1 distance, 19 code codes "r101 101 101 101 101 101 101 101 101 101 101 101" \ " 101 101 101 101 101 101 101" \ // All 14 code codes of length 5 "10010 r0110101" \ // 97 zeroes "00011 00011 00011" \ // then three times 3 "10010 r1111111 10010 r1110000" \ // then 156 (= 11+127 + 11+7) zeroes "00011" \ // then 3 once (end of block) "00000" \ // one unused length code "000 001 010 011", // finally, some data "abc", `None), ("dynamic code block with reference", "1 01" \ "r01000 r10000 r1111" \ // 258 literal, 2 distance, 19 code codes "r101 101 101 101 101 101 101 101 101 101 101 101" \ " 101 101 101 101 101 101 101" \ // All 14 code codes of length 5 "10010 r0110101" \ // 97 zeroes "00011 00011 00011" \ // then three times 3 "10010 r1111111 10010 r1110000" \ // then 156 (= 11+127 + 11+7) zeroes "00011 00000 00011" \ // then 3, 0, 3 (ref of length 4) "00010 00010" \ // two size two distance code "000 001 010 100 01 011", // use the reference at the end "abcbcbc", `None), ("dynamic code with invalid reference", "1 01" \ "r01000 r10000 r1111" \ "r101 101 101 101 101 101 101 101 101 101 101 101" \ " 101 101 101 101 101 101 101" \ "10010 r0110101" \ "00011 00011 00011" \ "10010 r1111111 10010 r1110000" \ "00011 00000 00011" \ "00010 00010" \ "000 100 01", "a", `Format), ("dynamic code with cross-blocks reference", "0 00 00000 1100000000000000 0011111111111111" \ "10000110 01000110 11000110" \ // "abc" uncompressed "1 01" \ "r01000 r00000 r1000" \ // 258 literal, 1 distance, 5 code codes "r110 110 110 000 010" \ // code lengths of 3, 3, 3, 0, 2 \ // for 16, 17, 18, 0, 8 "100 r1111111" \ // 138 zeroes "100 r1101011" \ // +118 zeroes = 256 zeroes "00" \ // 256 (=EOB) has length 8 "010 r00" \ // repeat this length 3 times "00000001 00000000 00000000", // one reference, then EOB "abcccc", `None), ] var outf, err for (t, in, out, experr) : tests outf = expect(ctx, t, out) err = flate.decode(outf, bitsf(in)) match (err, experr) | (`std.Ok _, `None): | (`std.Err (`flate.Io `bio.Eof), `Eof): | (`std.Err (`flate.Io _), `Io): | (`std.Err (`flate.Format _), `Format): | _: testr.fail(ctx, "({}) {} error expected but got {} instead", t, experr, err) ;; bio.close(outf) ;; } const main = { testr.run([ [.name = "bits", .fn = bits], [.name = "mkhufc", .fn = mkhufc], [.name = "readcode", .fn = readcode], [.name = "decode", .fn = decode], ][:]) }