add tests for leb128 library (#486)

add tests for containers.leb128

also fix a bug in fix zigzag decoding
This commit is contained in:
Simon Cruanes 2026-02-09 21:24:59 -05:00 committed by GitHub
parent 91cc585d5f
commit 42c4f1c173
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 242 additions and 1 deletions

View file

@ -60,7 +60,7 @@ module Decode = struct
Int64.to_int v, n_consumed
let[@inline] decode_zigzag (v : int64) : int64 =
Int64.(logxor (shift_right v 1) (neg (logand v Int64.one)))
Int64.(logxor (shift_right_logical v 1) (sub 0L (logand v 1L)))
let[@inline] i64 sl off : int64 * int =
let v, n_consumed = u64 sl off in

11
tests/leb128/dune Normal file
View file

@ -0,0 +1,11 @@
(executable
(name t_leb128)
(modules t_leb128)
(libraries containers containers.leb128 containers_testlib))
(rule
(alias runtest)
(deps t_leb128.exe)
(package containers)
(action
(run ./t_leb128.exe)))

230
tests/leb128/t_leb128.ml Normal file
View file

@ -0,0 +1,230 @@
include (val Containers_testlib.make ~__FILE__ ())
module Leb128 = Containers_leb128
module Buf = CCByte_buffer
module Slice = CCByte_slice
let encode_decode_u64 (i : int64) : bool =
let buf = Buf.create () in
Leb128.Encode.u64 buf i;
let slice = Buf.to_slice buf in
let i', n = Leb128.Decode.u64 slice 0 in
Int64.equal i i' && n = Slice.len slice
let encode_decode_i64 (i : int64) : bool =
let buf = Buf.create () in
Leb128.Encode.i64 buf i;
let slice = Buf.to_slice buf in
let i', n = Leb128.Decode.i64 slice 0 in
Int64.equal i i' && n = Slice.len slice
let encode_decode_uint (i : int) : bool =
i >= 0
&&
let buf = Buf.create () in
Leb128.Encode.uint buf i;
let slice = Buf.to_slice buf in
let i', n = Leb128.Decode.uint_truncate slice 0 in
Int.equal i i' && n = Slice.len slice
let encode_decode_int (i : int) : bool =
let buf = Buf.create () in
Leb128.Encode.int buf i;
let slice = Buf.to_slice buf in
let i', n = Leb128.Decode.int_truncate slice 0 in
Int.equal i i' && n = Slice.len slice
let zigzag_roundtrip (i : int64) : bool =
let encoded = Leb128.Encode.encode_zigzag i in
let decoded = Leb128.Decode.decode_zigzag encoded in
Int64.equal i decoded
;;
q ~count:10_000 ~long_factor:20 Q.int64 @@ fun i ->
if not (encode_decode_u64 (Int64.abs i)) then
Q.Test.fail_reportf "u64 roundtrip failed for %Ld" i;
true
;;
q ~count:10_000 ~long_factor:20 Q.int64 @@ fun i ->
if not (encode_decode_i64 i) then
Q.Test.fail_reportf "i64 roundtrip failed for %Ld" i;
true
;;
q ~count:10_000 ~long_factor:20 Q.int @@ fun i ->
(* make sure [i] is non negative *)
let i = max 0 (abs i) in
if not (encode_decode_uint i) then
Q.Test.fail_reportf "uint roundtrip failed for %d" i;
true
;;
q ~count:10_000 ~long_factor:20 Q.int @@ fun i ->
if not (encode_decode_int i) then
Q.Test.fail_reportf "int roundtrip failed for %d" i;
true
;;
q ~count:10_000 ~long_factor:20 Q.int64 @@ fun i ->
if not (zigzag_roundtrip i) then
Q.Test.fail_reportf "zigzag roundtrip failed for %Ld" i;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 0L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.u64 slice 0 in
assert_equal ~printer:Int64.to_string 0L v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 127L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.u64 slice 0 in
assert_equal ~printer:Int64.to_string 127L v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 128L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.u64 slice 0 in
assert_equal ~printer:Int64.to_string 128L v;
assert_equal ~printer:string_of_int 2 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 16383L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.u64 slice 0 in
assert_equal ~printer:Int64.to_string 16383L v;
assert_equal ~printer:string_of_int 2 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 16384L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.u64 slice 0 in
assert_equal ~printer:Int64.to_string 16384L v;
assert_equal ~printer:string_of_int 3 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf 0L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string 0L v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 127L;
Leb128.Encode.u64 buf 16384L;
Leb128.Encode.u64 buf 300L;
let slice = Buf.to_slice buf in
let n1 = Leb128.Decode.skip slice 0 in
let n2 = Leb128.Decode.skip slice n1 in
let n3 = Leb128.Decode.skip slice (n1 + n2) in
assert_equal ~printer:string_of_int 1 n1;
assert_equal ~printer:string_of_int 3 n2;
assert_equal ~printer:string_of_int 2 n3;
assert_equal ~printer:string_of_int 6 (n1 + n2 + n3);
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf (-1L);
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string (-1L) v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf 63L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string 63L v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf (-64L);
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string (-64L) v;
assert_equal ~printer:string_of_int 1 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf 64L;
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string 64L v;
assert_equal ~printer:string_of_int 2 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf (-65L);
let slice = Buf.to_slice buf in
let v, n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string (-65L) v;
assert_equal ~printer:string_of_int 2 n;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.i64 buf Int64.min_int;
let slice = Buf.to_slice buf in
let v, _n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string Int64.min_int v;
true
;;
let buf = Buf.create () in
Leb128.Encode.i64 buf Int64.max_int;
let slice = Buf.to_slice buf in
let v, _n = Leb128.Decode.i64 slice 0 in
assert_equal ~printer:Int64.to_string Int64.max_int v;
true
;;
t @@ fun () ->
let buf = Buf.create () in
Leb128.Encode.u64 buf 300L;
Leb128.Encode.u64 buf 500L;
let slice = Buf.to_slice buf in
let v1, n1 = Leb128.Decode.u64 slice 0 in
let v2, n2 = Leb128.Decode.u64 slice n1 in
assert_equal ~printer:Int64.to_string 300L v1;
assert_equal ~printer:Int64.to_string 500L v2;
assert_equal ~printer:string_of_int 2 n1;
assert_equal ~printer:string_of_int 2 n2;
true
let () = Containers_testlib.run_all ~descr:"test leb128" [ get () ]