(**************************************************************************) (* *) (* Copyright (c) 2014 - 2018. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) (* *) (**************************************************************************) (** Trivial back-and-forth test: a value is serialized, then unserialized and compared to the original value. All backend (json, bson, binary, and streamed binary) are tested for each of the basic encoding described here. No serialization or deserialization failure are expected in these tests. *) (* TODO `varopt` ; `assoc` ; `Data_encoding.json` *) open Data_encoding open Helpers open Types open Utils.Infix let json ty encoding value () = no_exception begin fun () -> let json = Json.construct encoding value in let result = Json.destruct encoding json in Alcotest.check ty "json" value result end let bson ty encoding value () = no_exception begin fun () -> let json = Bson.construct encoding value in let result = Bson.destruct encoding json in Alcotest.check ty "bson" value result end let binary ty encoding value () = no_exception begin fun () -> let bytes = Binary.to_bytes encoding value in let result = Binary.of_bytes_exn encoding bytes in Alcotest.check ty "binary" value result end let stream ty encoding value () = no_exception begin fun () -> let bytes = Binary.to_bytes encoding value in let len_data = MBytes.length bytes in for sz = 1 to max 1 len_data do let name = Format.asprintf "stream (%d)" sz in match chunked_read sz encoding bytes with | Binary.Success { result ; size ; stream } -> if size <> MBytes.length bytes || not (Binary_stream.is_empty stream) then Alcotest.failf "%s failed: remaining data" name ; Alcotest.check ty name value result | Binary.Await _ -> Alcotest.failf "%s failed: not enough data" name | Binary.Error error -> Alcotest.failf "@[%s failed: read error@ %a@]" name Binary.pp_read_error error done ; end let all name ty encoding value = let stream_encoding = match Data_encoding.classify encoding with | `Variable -> dynamic_size encoding | `Dynamic | `Fixed _ -> encoding in [ name ^ ".json", `Quick, json ty encoding value ; name ^ ".bson", `Quick, bson ty encoding value ; name ^ ".binary", `Quick, binary ty encoding value ; name ^ ".binary_stream", `Quick, stream ty stream_encoding value ] let all_int encoding size = let name = Format.asprintf "int%d" size in all (name ^ ".min") Alcotest.int encoding ~- (1 lsl (size - 1)) @ all (name ^ ".mean") Alcotest.int encoding 0 @ all (name ^ ".max") Alcotest.int encoding ((1 lsl (size - 1)) - 1) let all_uint encoding size = let name = Format.asprintf "uint%d" size in all (name ^ ".min") Alcotest.int encoding 0 @ all (name ^ ".mean") Alcotest.int encoding (1 lsl (size - 1)) @ all (name ^ ".max") Alcotest.int encoding ((1 lsl size) - 1) let all_ranged_int minimum maximum = let encoding = ranged_int minimum maximum in let name = Format.asprintf "ranged_int.%d" minimum in all (name ^ ".min") Alcotest.int encoding minimum @ all (name ^ ".mean") Alcotest.int encoding ((minimum + maximum) / 2) @ all (name ^ ".max") Alcotest.int encoding maximum let all_ranged_float minimum maximum = let encoding = ranged_float minimum maximum in let name = Format.asprintf "ranged_float.%f" minimum in all (name ^ ".min") Alcotest.float encoding minimum @ all (name ^ ".mean") Alcotest.float encoding ((minimum +. maximum) /. 2.) @ all (name ^ ".max") Alcotest.float encoding maximum let test_z_sequence () = let test i = binary Alcotest.z z i () ; stream Alcotest.z z i () in for i = -10_000 to 10_000 do test (Z.of_int i) done ; for i = 100_000_000 to 100_010_000 do test (Z.of_int i) done ; for i = -100_000_000 downto -100_010_000 do test (Z.of_int i) done let test_string_enum_boundary () = let entries = List.rev_map (fun x -> string_of_int x, x) (0 -- 254) in let run_test cases = List.iter (fun (_, num) -> let enc = string_enum cases in json Alcotest.int enc num () ; bson Alcotest.int enc num () ; binary Alcotest.int enc num () ; stream Alcotest.int enc num ()) cases in run_test entries ; let entries2 = (("255", 255) :: entries) in run_test entries2 ; run_test (("256", 256) :: entries2) let tests = all "null" Alcotest.pass null () @ all "empty" Alcotest.pass empty () @ all "constant" Alcotest.pass (constant "toto") () @ all_int int8 8 @ all_uint uint8 8 @ all_int int16 16 @ all_uint uint16 16 @ all_int int31 31 @ all "int32.min" Alcotest.int32 int32 Int32.min_int @ all "int32.max" Alcotest.int32 int32 Int32.max_int @ all "int64.min" Alcotest.int64 int64 Int64.min_int @ all "int64.max" Alcotest.int64 int64 Int64.max_int @ all_ranged_int 100 400 @ all_ranged_int 19000 19254 @ all_ranged_int ~-100 300 @ all_ranged_int ~-300_000_000 300_000_000 @ all "bool.true" Alcotest.bool bool true @ all "bool.false" Alcotest.bool bool false @ all "string" Alcotest.string string "tutu" @ all "string.fixed" Alcotest.string (Fixed.string 4) "tutu" @ all "string.variable" Alcotest.string Variable.string "tutu" @ all "bytes" Alcotest.bytes bytes (MBytes.of_string "titi") @ all "bytes.fixed" Alcotest.bytes (Fixed.bytes 4) (MBytes.of_string "titi") @ all "bytes.variable" Alcotest.bytes Variable.bytes (MBytes.of_string "titi") @ all "float" Alcotest.float float 42. @ all "float.max" Alcotest.float float max_float @ all "float.min" Alcotest.float float min_float @ all "float.neg_zero" Alcotest.float float (-. 0.) @ all "float.zero" Alcotest.float float (+. 0.) @ all "float.infinity" Alcotest.float float infinity @ all "float.neg_infity" Alcotest.float float neg_infinity @ all "float.epsilon" Alcotest.float float epsilon_float @ all "float.nan" Alcotest.float float nan @ all_ranged_float ~-. 100. 300. @ all "z.zero" Alcotest.z z (Z.zero) @ all "z.one" Alcotest.z z (Z.one) @ [ "z.sequence", `Quick, test_z_sequence ] @ let rec fact n l = if n < 1 then [] else let l = Z.mul l (Z.of_int n) in fact (n - 1) l @ all (Format.asprintf "z.fact.%d" n) Alcotest.z z l in fact 35 Z.one @ all "z.a" Alcotest.z z (Z.of_string "123574503164821730218493275982143254986574985328") @ all "z.b" Alcotest.z z (Z.of_string "8493275982143254986574985328") @ all "z.c" Alcotest.z z (Z.of_string "123574503164821730218474985328") @ all "z.d" Alcotest.z z (Z.of_string "10000000000100000000001000003050000000060600000000000777000008") @ all "z.e" Alcotest.z z (Z.of_string "-123574503164821730218493275982143254986574985328") @ all "z.f" Alcotest.z z (Z.of_string "-8493275982143254986574985328") @ all "z.g" Alcotest.z z (Z.of_string "-123574503164821730218474985328") @ all "z.h" Alcotest.z z (Z.of_string "-10000000000100000000001000003050000000060600000000000777000008") @ all "none" Alcotest.(option string) (option string) None @ all "some.string" Alcotest.(option string) (option string) (Some "thing") @ all "enum" Alcotest.int enum_enc 4 @ all "obj" Alcotest.record record_obj_enc default_record @ all "obj.dft" Alcotest.record record_obj_enc { default_record with b = false } @ all "obj.req" Alcotest.record record_obj_enc { default_record with c = None } @ all "tup" Alcotest.record record_tup_enc default_record @ all "obj.variable" Alcotest.variable_record variable_record_obj_enc default_variable_record @ all "tup.variable" Alcotest.variable_record variable_record_tup_enc default_variable_record @ all "obj.variable_left" Alcotest.variable_left_record variable_left_record_obj_enc default_variable_left_record @ all "tup.variable_left" Alcotest.variable_left_record variable_left_record_tup_enc default_variable_left_record @ all "union.A" Alcotest.union union_enc (A 1) @ all "union.B" Alcotest.union union_enc (B "2") @ all "union.C" Alcotest.union union_enc (C 3) @ all "union.D" Alcotest.union union_enc (D "4") @ all "union.E" Alcotest.union union_enc E @ all "variable_list.empty" Alcotest.(list int) (Variable.list int31) [] @ all "variable_list" Alcotest.(list int) (Variable.list int31) [1;2;3;4;5] @ all "variable_array.empty" Alcotest.(array int) (Variable.array int31) [||] @ all "variable_array" Alcotest.(array int) (Variable.array int31) [|1;2;3;4;5|] @ all "list.empty" Alcotest.(list int) (list int31) [] @ all "list" Alcotest.(list int) (list int31) [1;2;3;4;5] @ all "array.empty" Alcotest.(array int) (array int31) [||] @ all "array" Alcotest.(array int) (array int31) [|1;2;3;4;5|] @ all "mu_list.empty" Alcotest.(list int) (mu_list_enc int31) [] @ all "mu_list" Alcotest.(list int) (mu_list_enc int31) [1;2;3;4;5] @ [ "string_enum_boundary", `Quick, test_string_enum_boundary ; ]