open Crowbar [@@@warning "-3"] let create x = match Cstruct.create x with | c -> assert (x >= 0); c | exception Invalid_argument _ -> assert (x <= 0); bad_test () let create_sub x start len = try let c = Cstruct.create_unsafe x in for i = 0 to len - 1 do Cstruct.set_uint8 c i i done; Cstruct.sub c start len with Invalid_argument _ -> bad_test () let cstruct = choose [ map [int8] create; map [range 0x10000; int; int] create_sub; ] let bytes = map [bytes] Bytes.unsafe_of_string let buffer = map [uint8] Bigarray.(Array1.create Char c_layout) let pp_cstruct f c = Format.pp_print_string f (Cstruct.debug c) let check_within ~base x = check Cstruct.(base.off <= x.off); check Cstruct.(base.off + base.len >= x.off + x.len); check Cstruct.(x.len >= 0 && x.len <= base.len) let () = (* assert (Array.length Sys.argv = 2); (* Prevent accidentally running in quickcheck mode *) *) add_test ~name:"blit" [cstruct; int; cstruct; int; int] (fun src srcoff dst dstoff len -> try Cstruct.blit src srcoff dst dstoff len with Invalid_argument _ -> check (srcoff < 0 || srcoff > Cstruct.length src || dstoff < 0 || dstoff > Cstruct.length src || len < 0 || len > Cstruct.length src - srcoff || len > Cstruct.length dst - dstoff) ); add_test ~name:"sexp" [buffer] (fun b -> b |> Cstruct_sexp.sexp_of_buffer |> Cstruct_sexp.buffer_of_sexp |> check_eq ~cmp:(fun x y -> Cstruct.compare (Cstruct.of_bigarray x) (Cstruct.of_bigarray y)) b ); add_test ~name:"of_bigarray" [buffer; option int; option int] (fun b off len -> match Cstruct.of_bigarray b ?off ?len with | c -> check (Cstruct.length c <= Bigarray.Array1.dim b) | exception Invalid_argument _ -> () ); add_test ~name:"get_char" [cstruct; int] (fun c off -> let in_range = off >= 0 && off < Cstruct.length c in match Cstruct.get_char c off with | _ -> check in_range | exception Invalid_argument _ -> check (not in_range) ); add_test ~name:"set_char" [cstruct; int] (fun c off -> let in_range = off >= 0 && off < Cstruct.length c in match Cstruct.set_char c off 'x' with | () -> check in_range | exception Invalid_argument _ -> check (not in_range) ); add_test ~name:"sub" [cstruct; int; int] (fun base off len -> match Cstruct.sub base off len with | sub -> check_within ~base sub; check (Cstruct.length sub = len) | exception Invalid_argument _ -> check (off < 0 || len < 0 || off + len < 0 || off + len > Cstruct.length base) ); add_test ~name:"shift" [cstruct; int] (fun base off -> match Cstruct.shift base off with | sub -> check_within ~base sub; check (Cstruct.length sub = max (Cstruct.length base - off) 0); | exception Invalid_argument _ -> check (off < 0 || off > Cstruct.length base) ); add_test ~name:"shiftv" [list cstruct; int] (fun ts n -> match Cstruct.shiftv ts n with | exception Invalid_argument _ -> check (n < 0 || n > Cstruct.lenv ts) | ts' -> assert (Cstruct.equal (Cstruct.concat ts') (Cstruct.shift (Cstruct.concat ts) n)); assert ((Cstruct.lenv ts = n) = (ts' = [])); match ts' with | hd :: _ -> assert (not (Cstruct.is_empty hd)) | [] -> () ); add_test ~name:"copy" [cstruct; int; int] (fun base off len -> match Cstruct.copy base off len with | x -> check (String.length x = len); check (String.equal x (Cstruct.sub base off len |> Cstruct.to_string)) | exception Invalid_argument _ -> check (off < 0 || len < 0 || off + len < 0 || off + len > Cstruct.length base) ); add_test ~name:"blit_from_bytes" [bytes; int; cstruct; int; int] (fun src srcoff dst dstoff len -> match Cstruct.blit_from_bytes src srcoff dst dstoff len with | () -> check (Cstruct.equal (Cstruct.sub (Cstruct.of_bytes src) srcoff len) (Cstruct.sub dst dstoff len)) | exception Invalid_argument _ -> check (srcoff < 0 || srcoff > Bytes.length src || dstoff < 0 || dstoff > Bytes.length src || len < 0 || len > Bytes.length src - srcoff || len > Cstruct.length dst - dstoff) ); add_test ~name:"blit_to_bytes" [cstruct; int; bytes; int; int] (fun src srcoff dst dstoff len -> match Cstruct.blit_to_bytes src srcoff dst dstoff len with | () -> check (Cstruct.equal (Cstruct.sub src srcoff len) (Cstruct.sub (Cstruct.of_bytes dst) dstoff len)) | exception Invalid_argument _ -> check (srcoff < 0 || srcoff > Cstruct.length src || dstoff < 0 || dstoff > Cstruct.length src || len < 0 || len > Cstruct.length src - srcoff || len > Bytes.length dst - dstoff) ); add_test ~name:"memset" [cstruct; int; int] (fun c x i -> guard (i >= 0 && i < Cstruct.length c); Cstruct.memset c x; check (Cstruct.get_uint8 c i = x land 0xff) ); add_test ~name:"split" [cstruct; option int; int] (fun base start len -> match Cstruct.split ?start base len with | c1, c2 -> check_within ~base c1; check_within ~base c2; let start = match start with None -> 0 | Some x -> x in check (Cstruct.equal (Cstruct.sub base start len) c1); check (Cstruct.equal (Cstruct.shift base (start + len)) c2) | exception Invalid_argument _ -> () ); add_test ~name:"BE.set_uint64" [cstruct; int] (fun c off -> let in_range = off >= 0 && off < Cstruct.length c - 7 in match Cstruct.BE.set_uint64 c off 42L with | () -> check in_range | exception Invalid_argument _ -> check (not in_range) ); add_test ~name:"lenv" [list cstruct] (fun cs -> check (Cstruct.lenv cs >= 0) ); add_test ~name:"copyv" [list cstruct] (fun cs -> check (String.equal (Cstruct.copyv cs) (Cstruct.concat cs |> Cstruct.to_string)) ); add_test ~name:"fillv" [list cstruct; cstruct] (fun src dst -> let copied, rest = Cstruct.fillv ~src ~dst in check (copied + Cstruct.lenv rest = Cstruct.lenv src); (* OCaml tends to underestimate how much space bigarrays are using: *) Gc.minor () ); add_test ~name:"concat" [list cstruct] (fun cs -> let x = Cstruct.concat cs in check (Cstruct.length x = Cstruct.lenv cs) ); add_test ~name:"span" [ cstruct; list char ] (fun cs p -> let sat chr = List.exists ((=) chr) p in let a, b = Cstruct.span ~sat cs in let r = Cstruct.concat [ a; b ] in check (Cstruct.to_string r = Cstruct.to_string cs)); add_test ~name:"cut" [ cstruct; cstruct; ] (fun buf sep -> guard (Cstruct.length sep > 0); ( match Cstruct.cut ~sep buf with | Some (l, r) -> let r = Cstruct.concat [ l; sep; r; ] in check (Cstruct.to_string r = Cstruct.to_string buf) | None -> () )); add_test ~name:"cuts" [ cstruct; cstruct; ] (fun buf sep -> guard (Cstruct.length sep > 0); let lst = Cstruct.cuts ~sep buf in let lst = List.map Cstruct.to_string lst in let res = String.concat (Cstruct.to_string sep) lst in check (res = Cstruct.to_string buf));