452 lines
15 KiB
OCaml
452 lines
15 KiB
OCaml
open Data_encoding
|
|
open Hash
|
|
open Error_monad
|
|
|
|
let (>>=) = Lwt.bind
|
|
let (>|=) = Lwt.(>|=)
|
|
let (//) = Filename.concat
|
|
|
|
let is_invalid_arg = function
|
|
| Invalid_argument _ -> true
|
|
| _ -> false
|
|
|
|
|
|
let is_await = function Binary.Await _ -> true | _ -> false
|
|
let is_success = function Binary.Success _ -> true | _ -> false
|
|
let is_error = function Binary.Error -> true | _ -> false
|
|
|
|
|
|
let rec fold_left_pending f accu l =
|
|
match l with
|
|
| [] -> accu
|
|
| a::l -> fold_left_pending f (f accu a l) l
|
|
|
|
let test_read_simple_bin_ko_invalid_data
|
|
?msg ?(not_equal=Assert.not_equal) encoding value =
|
|
let len_data = MBytes.length (Binary.to_bytes encoding value) in
|
|
if classify encoding != `Variable && len_data > 0 then
|
|
for sz = 1 to len_data do
|
|
let l = (Binary.to_bytes_list sz encoding value) in
|
|
List.iter (fun b ->
|
|
for i = 0 to MBytes.length b - 1 do
|
|
(* alter data *)
|
|
MBytes.set_int8 b i ((MBytes.get_int8 b i)+1)
|
|
done
|
|
)l;
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status =
|
|
Binary.read_stream_of_bytes ~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Await _ -> ()
|
|
| Binary.Error -> ()
|
|
| Binary.Success {res; remaining} ->
|
|
(* should not have "Success" *)
|
|
Assert.equal ~msg:__LOC__ remaining [];
|
|
not_equal value res
|
|
end;
|
|
_done
|
|
)[] l
|
|
)
|
|
done
|
|
|
|
let unexpected loc =
|
|
loc ^ ": This case should not happen"
|
|
|
|
let test_read_simple_bin_ko_await ?msg encoding value =
|
|
let len_data = MBytes.length (Binary.to_bytes encoding value) in
|
|
if classify encoding != `Variable && len_data > 0 then
|
|
for sz = 1 to len_data do
|
|
let l = Binary.to_bytes_list sz encoding value in
|
|
match List.rev l with
|
|
| [] -> Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| e::r ->
|
|
let l = List.rev r in (* last mbyte removed !! *)
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status=
|
|
Binary.read_stream_of_bytes
|
|
~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
if not (is_await status) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__);
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Await _ -> ()
|
|
| Binary.Error ->
|
|
if not (classify encoding == `Variable) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| Binary.Success result ->
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
end;
|
|
_done
|
|
)[] l
|
|
)
|
|
done
|
|
|
|
let test_read_simple_bin_ok ?msg ?(equal=Assert.equal) encoding value =
|
|
let len_data = max 1 (MBytes.length (Binary.to_bytes encoding value)) in
|
|
for sz = 1 to len_data do
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status =
|
|
Binary.read_stream_of_bytes ~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
if MBytes.length mbyte <> 0 && is_success status then
|
|
Assert.fail_msg "%s" (unexpected __LOC__);
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Success {res; remaining} ->
|
|
Assert.equal ~msg:__LOC__ remaining [];
|
|
equal ?msg value res
|
|
| Binary.Await _ -> Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| Binary.Error ->
|
|
if not (classify encoding == `Variable) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
end;
|
|
_done
|
|
)[] (Binary.to_bytes_list sz encoding value)
|
|
)
|
|
done
|
|
|
|
let test_check_simple_bin_ko_invalid_data
|
|
?msg ?(not_equal=Assert.not_equal) encoding value =
|
|
let len_data = MBytes.length (Binary.to_bytes encoding value) in
|
|
if classify encoding != `Variable && len_data > 0 then
|
|
for sz = 1 to len_data do
|
|
let l = (Binary.to_bytes_list sz encoding value) in
|
|
List.iter (fun b ->
|
|
for i = 0 to MBytes.length b - 1 do
|
|
(* alter data *)
|
|
MBytes.set_int8 b i ((MBytes.get_int8 b i)+1)
|
|
done
|
|
)l;
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status =
|
|
Binary.check_stream_of_bytes ~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Await _ -> ()
|
|
| Binary.Error -> ()
|
|
| Binary.Success {res; remaining} ->
|
|
Assert.equal ~msg:__LOC__ remaining [];
|
|
(* res is unit for check *)
|
|
end;
|
|
_done
|
|
)[] l
|
|
)
|
|
done
|
|
|
|
let test_check_simple_bin_ko_await ?msg encoding value =
|
|
let len_data = MBytes.length (Binary.to_bytes encoding value) in
|
|
if classify encoding != `Variable && len_data > 0 then
|
|
for sz = 1 to len_data do
|
|
let l = Binary.to_bytes_list sz encoding value in
|
|
match List.rev l with
|
|
| [] -> Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| e::r ->
|
|
let l = List.rev r in (* last mbyte removed !! *)
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status=
|
|
Binary.check_stream_of_bytes
|
|
~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
if not (is_await status) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__);
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Await _ -> ()
|
|
| Binary.Error ->
|
|
if not (classify encoding == `Variable) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| Binary.Success result ->
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
end;
|
|
_done
|
|
)[] l
|
|
)
|
|
done
|
|
|
|
let test_check_simple_bin_ok ?msg ?(equal=Assert.equal) encoding value =
|
|
let len_data = max 1 (MBytes.length (Binary.to_bytes encoding value)) in
|
|
for sz = 1 to len_data do
|
|
ignore(
|
|
fold_left_pending
|
|
(fun _done e _todo ->
|
|
let _done = e :: _done in
|
|
begin
|
|
let status =
|
|
Binary.check_stream_of_bytes ~init:(List.rev _done) encoding in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
if MBytes.length mbyte <> 0 && is_success status then
|
|
Assert.fail_msg "%s" (unexpected __LOC__);
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status _todo
|
|
in
|
|
match status with
|
|
| Binary.Success {res; remaining} ->
|
|
Assert.equal ~msg:__LOC__ remaining [];
|
|
(* res is unit for check *)
|
|
| Binary.Await _ -> Assert.fail_msg "%s" (unexpected __LOC__)
|
|
| Binary.Error ->
|
|
if not (classify encoding == `Variable) then
|
|
Assert.fail_msg "%s" (unexpected __LOC__)
|
|
end;
|
|
_done
|
|
)[] (Binary.to_bytes_list sz encoding value)
|
|
)
|
|
done
|
|
|
|
let test_simple
|
|
~msg ?(equal=Assert.equal) ?(not_equal=Assert.not_equal) enc value
|
|
=
|
|
test_check_simple_bin_ok ~msg:(msg ^ ": binary-ok") ~equal enc value;
|
|
test_check_simple_bin_ko_await ~msg:(msg ^ ": binary-ko_await") enc value;
|
|
test_check_simple_bin_ko_invalid_data
|
|
~msg:(msg ^ ": binary-invalid_data") ~not_equal enc value;
|
|
|
|
test_read_simple_bin_ok ~msg:(msg ^ ": binary-ok") ~equal enc value;
|
|
test_read_simple_bin_ko_await ~msg:(msg ^ ": binary-ko_await") enc value;
|
|
test_read_simple_bin_ko_invalid_data
|
|
~msg:(msg ^ ": binary-invalid_data") ~not_equal enc value
|
|
|
|
|
|
|
|
|
|
let test_simple_int ~msg encoding i =
|
|
let range_min = - (1 lsl (i-1)) in
|
|
let range_max = (1 lsl (i-1)) - 1 in
|
|
test_simple ~msg encoding range_min ;
|
|
test_simple ~msg encoding range_max
|
|
|
|
let test_simple_uint ~msg encoding i =
|
|
let range_min = 0 in
|
|
let range_max = (1 lsl i) - 1 in
|
|
test_simple ~msg encoding range_min ;
|
|
test_simple ~msg encoding range_max
|
|
|
|
let test_simple_values _ =
|
|
test_simple ~msg:__LOC__ null ();
|
|
test_simple ~msg:__LOC__ empty ();
|
|
test_simple ~msg:__LOC__ (constant "toto") ();
|
|
test_simple_int ~msg:__LOC__ int8 8;
|
|
test_simple_uint ~msg:__LOC__ uint8 8;
|
|
test_simple_int ~msg:__LOC__ int16 16;
|
|
test_simple_uint ~msg:__LOC__ uint16 16;
|
|
test_simple_int ~msg:__LOC__ int31 31;
|
|
test_simple ~msg:__LOC__ int32 Int32.min_int;
|
|
test_simple ~msg:__LOC__ int32 Int32.max_int;
|
|
test_simple ~msg:__LOC__ int64 Int64.min_int;
|
|
test_simple ~msg:__LOC__ int64 Int64.max_int;
|
|
test_simple ~msg:__LOC__ bool true;
|
|
test_simple ~msg:__LOC__ bool false;
|
|
test_simple ~msg:__LOC__ string "tutu";
|
|
test_simple ~msg:__LOC__ bytes (MBytes.of_string "titi");
|
|
test_simple ~msg:__LOC__ float 42.;
|
|
test_simple ~msg:__LOC__ float max_float;
|
|
test_simple ~msg:__LOC__ float min_float;
|
|
test_simple ~msg:__LOC__ float (-. 0.);
|
|
test_simple ~msg:__LOC__ float (+. 0.);
|
|
test_simple ~msg:__LOC__ float infinity;
|
|
test_simple ~msg:__LOC__ float neg_infinity;
|
|
test_simple ~msg:__LOC__ float epsilon_float;
|
|
test_simple ~msg:__LOC__ ~equal:Assert.equal_float float nan;
|
|
test_simple ~msg:__LOC__ (option string) (Some "thing");
|
|
test_simple ~msg:__LOC__ (option string) None;
|
|
let enum_enc =
|
|
["one", 1; "two", 2; "three", 3; "four", 4; "five", 6; "six", 6] in
|
|
test_simple ~msg:__LOC__ (string_enum enum_enc) 4;
|
|
|
|
Lwt.return_unit
|
|
|
|
|
|
type t = A of int | B of string | C of int | D of string | E
|
|
|
|
let prn_t = function
|
|
| A i -> Printf.sprintf "A %d" i
|
|
| B s -> Printf.sprintf "B %s" s
|
|
| C i -> Printf.sprintf "C %d" i
|
|
| D s -> Printf.sprintf "D %s" s
|
|
| E -> "E"
|
|
|
|
let test_union _ =
|
|
let enc =
|
|
(union [
|
|
case ~tag:1
|
|
int8
|
|
(function A i -> Some i | _ -> None)
|
|
(fun i -> A i) ;
|
|
case ~tag:2
|
|
string
|
|
(function B s -> Some s | _ -> None)
|
|
(fun s -> B s) ;
|
|
case ~tag:3
|
|
int8
|
|
(function C i -> Some i | _ -> None)
|
|
(fun i -> C i) ;
|
|
case ~tag:4
|
|
(obj2
|
|
(req "kind" (constant "D"))
|
|
(req "data" (string)))
|
|
(function D s -> Some ((), s) | _ -> None)
|
|
(fun ((), s) -> D s) ;
|
|
]) in
|
|
let jsonA = Json.construct enc (A 1) in
|
|
let jsonB = Json.construct enc (B "2") in
|
|
let jsonC = Json.construct enc (C 3) in
|
|
let jsonD = Json.construct enc (D"4") in
|
|
Assert.test_fail
|
|
~msg:__LOC__ (fun () -> Json.construct enc E) is_invalid_arg ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (A 1) (Json.destruct enc jsonA) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (B "2") (Json.destruct enc jsonB) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (A 3) (Json.destruct enc jsonC) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (D "4") (Json.destruct enc jsonD) ;
|
|
let binA = Binary.to_bytes_list 1 enc (A 1) in
|
|
let binB = Binary.to_bytes_list 1 enc (B "2") in
|
|
let binC = Binary.to_bytes_list 1 enc (C 3) in
|
|
let binD = Binary.to_bytes_list 1 enc (D "4") in
|
|
Assert.test_fail ~msg:__LOC__ (fun () -> Binary.to_bytes enc E)
|
|
(function
|
|
| No_case_matched -> true
|
|
| _ -> false) ;
|
|
let get_result ~msg bin_l =
|
|
let status = Binary.read_stream_of_bytes enc in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status bin_l
|
|
in
|
|
match status with
|
|
| Binary.Error -> Assert.fail_msg "%s" msg
|
|
| Binary.Await _ -> Assert.fail_msg "%s" msg
|
|
| Binary.Success {res} -> res
|
|
in
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (A 1) (get_result ~msg:__LOC__ binA) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (B "2") (get_result ~msg:__LOC__ binB) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (C 3) (get_result ~msg:__LOC__ binC) ;
|
|
Assert.equal ~prn:prn_t ~msg:__LOC__ (D "4") (get_result ~msg:__LOC__ binD) ;
|
|
Lwt.return_unit
|
|
|
|
type s = { field : int }
|
|
|
|
let test_splitted _ =
|
|
let s_enc =
|
|
def "s" @@
|
|
describe
|
|
~title:"testsuite encoding test"
|
|
~description: "A human readable description" @@
|
|
conv
|
|
(fun s -> string_of_int s.field)
|
|
(fun s -> { field = int_of_string s })
|
|
string in
|
|
let enc =
|
|
(splitted
|
|
~binary:string
|
|
~json:
|
|
(union [
|
|
case ~tag:1
|
|
string
|
|
(fun _ -> None)
|
|
(fun s -> s) ;
|
|
case ~tag:2
|
|
s_enc
|
|
(fun s -> Some { field = int_of_string s })
|
|
(fun s -> string_of_int s.field) ;
|
|
])) in
|
|
let get_result ~msg bin_l =
|
|
let status = Binary.read_stream_of_bytes enc in
|
|
let status =
|
|
List.fold_left
|
|
(fun status mbyte ->
|
|
match status with
|
|
| Binary.Await f -> f mbyte
|
|
| _ -> status
|
|
)status bin_l
|
|
in
|
|
match status with
|
|
| Binary.Error -> Assert.fail_msg "%s" msg
|
|
| Binary.Await _ -> Assert.fail_msg "%s" msg
|
|
| Binary.Success {res} -> res
|
|
in
|
|
let jsonA = Json.construct enc "41" in
|
|
let jsonB = Json.construct s_enc {field = 42} in
|
|
let binA = Binary.to_bytes_list 1 enc "43" in
|
|
let binB = Binary.to_bytes_list 1 s_enc {field = 44} in
|
|
Assert.equal ~msg:__LOC__ "41" (Json.destruct enc jsonA);
|
|
Assert.equal ~msg:__LOC__ "42" (Json.destruct enc jsonB);
|
|
Assert.equal ~msg:__LOC__ "43" (get_result ~msg:__LOC__ binA);
|
|
Assert.equal ~msg:__LOC__ "44" (get_result ~msg:__LOC__ binB);
|
|
Lwt.return_unit
|
|
|
|
|
|
let wrap_test f base_dir =
|
|
f base_dir >>= fun result ->
|
|
return result
|
|
|
|
let tests = [
|
|
"simple", test_simple_values ;
|
|
"union", test_union ;
|
|
"splitted", test_splitted ;
|
|
]
|
|
|
|
let () =
|
|
Test.run "stream_data_encoding."
|
|
(List.map (fun (s, f) -> s, wrap_test f) tests)
|