swh:1:snp:61dcfc0dd5674a0e65803e88039c122d9532074e
Raw File
Tip revision: fdb3771ab4db55bfc5d991d7514fd40961b8db2a authored by Raphaƫl Proust on 12 September 2022, 06:53:11 UTC
Ensure that tups of zero-width are described with non-empty `fields`
Tip revision: fdb3771
json_roundtrip_in_binary.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com>     *)
(* Copyright (c) 2020-2021 Nomadic Labs, <contact@nomadic-labs.com>          *)
(*                                                                           *)
(* Permission is hereby granted, free of charge, to any person obtaining a   *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense,  *)
(* and/or sell copies of the Software, and to permit persons to whom the     *)
(* Software is furnished to do so, subject to the following conditions:      *)
(*                                                                           *)
(* The above copyright notice and this permission notice shall be included   *)
(* in all copies or substantial portions of the Software.                    *)
(*                                                                           *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL   *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER       *)
(* DEALINGS IN THE SOFTWARE.                                                 *)
(*                                                                           *)
(*****************************************************************************)

let string1 =
  let open Crowbar in
  with_printer pp_string
  @@ map
       [choose [range ~min:48 10; range ~min:65 26; range ~min:97 26]]
       (fun c -> String.make 1 (Char.chr c))

let string0 =
  let open Crowbar in
  with_printer pp_string @@ choose [string1; const ""]

let rec printer fmt =
  let open Format in
  function
  | `Null -> pp_print_string fmt "null"
  | `Bool true -> pp_print_string fmt "true"
  | `Bool false -> pp_print_string fmt "false"
  | `Float _ -> pp_print_string fmt "<float>"
  | `String s -> fprintf fmt "%S" s
  | `A js ->
      pp_print_string fmt "[" ;
      pp_print_list
        ~pp_sep:(fun fmt () -> pp_print_string fmt ", ")
        printer
        fmt
        js ;
      pp_print_string fmt "]"
  | `O kvs ->
      pp_print_string fmt "{" ;
      pp_print_list
        ~pp_sep:(fun fmt () -> pp_print_string fmt ", ")
        (fun fmt (k, v) ->
          fprintf fmt "%S" k ;
          pp_print_string fmt ": " ;
          printer fmt v)
        fmt
        kvs ;
      pp_print_string fmt "}"

let g : Data_encoding.Json.t Crowbar.gen =
  let open Crowbar in
  with_printer printer
  @@ fix (fun g ->
         choose
           [
             const @@ `Null;
             const @@ `Bool true;
             const @@ `Bool false;
             map [string0] (fun s -> `String s);
             map [float] (fun f -> `Float f);
             map [list g] (fun xs -> `A xs);
             map [list (map [string1; g] (fun k v -> (k, v)))] (fun xs -> `O xs);
           ])

(* Setting up the actual tests *)
let test_json (j : Data_encoding.Json.t) =
  let json =
    try Data_encoding.Json.construct Data_encoding.Json.encoding j
    with exc -> failwith ("Cannot construct: " ^ Printexc.to_string exc)
  in
  let jj =
    try Data_encoding.Json.destruct Data_encoding.Json.encoding json
    with Data_encoding.Json.Cannot_destruct (_, _) ->
      failwith "Cannot destruct"
  in
  assert (j = jj)

let () = Crowbar.add_test ~name:"json_json_roundtrip" [g] test_json

(* The basic binary test would fail. This is because:
   - The binary encoding of JSON values uses the BSON representation
   - The BSON representation of Arrays is identical to that of an Object indexed
     by number ([`A [x; y]] is the same as [`O [("1", x); ("2", y)]]

   Instead of testing a strict equality, we test equality modulo this `A-`O
   equivalence. *)
let test_binary (j : Data_encoding.Json.t) =
  let s =
    try Data_encoding.Binary.to_string_exn Data_encoding.Json.encoding j
    with exc -> failwith ("Cannot construct: " ^ Printexc.to_string exc)
  in
  let jj =
    try Data_encoding.Binary.of_string_exn Data_encoding.Json.encoding s
    with _ -> failwith "Cannot destruct"
  in
  let rec assert_equal a b =
    match (a, b) with
    | `Null, `Null -> ()
    | `Bool a, `Bool b -> assert (a = b)
    | `Float a, `Float b -> assert (a = b)
    | `String a, `String b -> assert (a = b)
    | `A a, `A b -> List.iter2 (fun a b -> assert_equal a b) a b
    | `O a, `O b ->
        List.iter2
          (fun (n, a) (m, b) ->
            assert (n = m) ;
            assert_equal a b)
          a
          b
    | `A b, `O a | `O a, `A b ->
        let b = List.mapi (fun i x -> (string_of_int i, x)) b in
        List.iter2
          (fun (n, a) (m, b) ->
            assert (n = m) ;
            assert_equal a b)
          a
          b
    | _ -> assert false
  in
  assert_equal j jj

let () = Crowbar.add_test ~name:"json_binary(bson)_roundtrip" [g] test_binary
back to top