diff --git a/src/proto_alpha/lib_protocol/bond_id_repr.ml b/src/proto_alpha/lib_protocol/bond_id_repr.ml index 665d0e64d5bfd84534b339dbe8d8fac0936a5346..0feb48847f17de610945aa847e69f939fefbf3a9 100644 --- a/src/proto_alpha/lib_protocol/bond_id_repr.ml +++ b/src/proto_alpha/lib_protocol/bond_id_repr.ml @@ -63,34 +63,34 @@ let pp ppf = function | Tx_rollup_bond_id id -> Tx_rollup_repr.pp ppf id | Sc_rollup_bond_id id -> Sc_rollup_repr.pp ppf id -let rpc_arg = - let construct = function - | Tx_rollup_bond_id id -> Tx_rollup_repr.to_b58check id - | Sc_rollup_bond_id id -> Sc_rollup_repr.Address.to_b58check id - in - let destruct id = - (* String.starts_with from the stdlib 4.14, with [unsafe_get] replaced by - [get], comparators replaced by theirs versions in [Compare.*]. *) - let starts_with ~prefix s = - let open String in - let len_s = length s and len_pre = length prefix in - let rec aux i = - if Compare.Int.(i = len_pre) then true - else if Compare.Char.(get s i <> get prefix i) then false - else aux (i + 1) - in - Compare.Int.(len_s >= len_pre) && aux 0 +let destruct id = + (* String.starts_with from the stdlib 4.14, with [unsafe_get] replaced by + [get], comparators replaced by their versions in [Compare.*]. *) + let starts_with ~prefix s = + let open String in + let len_s = length s and len_pre = length prefix in + let rec aux i = + if Compare.Int.(i = len_pre) then true + else if Compare.Char.(get s i <> get prefix i) then false + else aux (i + 1) in - if starts_with ~prefix:Tx_rollup_repr.Hash.rollup_hash id then - match Tx_rollup_repr.of_b58check_opt id with - | Some id -> Result.ok (Tx_rollup_bond_id id) - | None -> Result.error "Cannot parse transaction rollup id" - else if starts_with ~prefix:Sc_rollup_repr.Address.prefix id then - match Sc_rollup_repr.Address.of_b58check_opt id with - | Some id -> Result.ok (Sc_rollup_bond_id id) - | None -> Result.error "Cannot parse smart contract rollup id" - else Result.error "Cannot parse rollup id" + Compare.Int.(len_s >= len_pre) && aux 0 in + if starts_with ~prefix:Tx_rollup_prefixes.rollup_address.prefix id then + match Tx_rollup_repr.of_b58check_opt id with + | Some id -> Result.ok (Tx_rollup_bond_id id) + | None -> Result.error "Cannot parse transaction rollup id" + else if starts_with ~prefix:Sc_rollup_repr.Address.prefix id then + match Sc_rollup_repr.Address.of_b58check_opt id with + | Some id -> Result.ok (Sc_rollup_bond_id id) + | None -> Result.error "Cannot parse smart contract rollup id" + else Result.error "Cannot parse rollup id" + +let construct = function + | Tx_rollup_bond_id id -> Tx_rollup_repr.to_b58check id + | Sc_rollup_bond_id id -> Sc_rollup_repr.Address.to_b58check id + +let rpc_arg = RPC_arg.make ~descr:"A bond identifier." ~name:"bond_id" @@ -98,6 +98,12 @@ let rpc_arg = ~destruct () +module Internal_for_test = struct + let destruct = destruct + + let construct = construct +end + module Index = struct type nonrec t = t diff --git a/src/proto_alpha/lib_protocol/bond_id_repr.mli b/src/proto_alpha/lib_protocol/bond_id_repr.mli index b9e8089cace84d1b722cbd0751f5fef46d2b978e..67298a9b174658e61d398a4efd566cd31939970c 100644 --- a/src/proto_alpha/lib_protocol/bond_id_repr.mli +++ b/src/proto_alpha/lib_protocol/bond_id_repr.mli @@ -35,4 +35,10 @@ val encoding : t Data_encoding.t include Compare.S with type t := t +module Internal_for_test : sig + val destruct : string -> (t, string) result + + val construct : t -> string +end + module Index : Storage_description.INDEX with type t = t diff --git a/src/proto_alpha/lib_protocol/test/helpers/assert.ml b/src/proto_alpha/lib_protocol/test/helpers/assert.ml index da3e4892c0df4b824fee3a0d852006b40181be33..91f1ba7971f0d7dc4c6771f911d085fba2eac100 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/assert.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/assert.ml @@ -165,6 +165,19 @@ let is_none ~loc ~pp = function | Some x -> failwith "Unexpected (Some %a) (%s)" pp x loc | None -> return_unit +let equal_result ~loc ~pp_ok ~pp_error eq_ok eq_error a b = + equal + ~loc + (Result.equal ~ok:eq_ok ~error:eq_error) + "Results are not equal" + (Format.pp_print_result ~ok:pp_ok ~error:pp_error) + a + b + +let is_error ~loc ~pp = function + | Ok x -> failwith "Unexpected (Ok %a) (%s)" pp x loc + | Error _ -> return_unit + open Context (* Some asserts for account operations *) diff --git a/src/proto_alpha/lib_protocol/test/unit/main.ml b/src/proto_alpha/lib_protocol/test/unit/main.ml index 7f2c2362427418624599040fef323c970b3fa179..ac07dd5d4e3799017a28aa80c2e839174ad1c7eb 100644 --- a/src/proto_alpha/lib_protocol/test/unit/main.ml +++ b/src/proto_alpha/lib_protocol/test/unit/main.ml @@ -81,5 +81,6 @@ let () = Unit_test.spec "sc rollup management protocol" Test_sc_rollup_management_protocol.tests; + Unit_test.spec "Bond_id_repr.ml" Test_bond_id_repr.tests; ] |> Lwt_main.run diff --git a/src/proto_alpha/lib_protocol/test/unit/test_bond_id_repr.ml b/src/proto_alpha/lib_protocol/test/unit/test_bond_id_repr.ml new file mode 100644 index 0000000000000000000000000000000000000000..86b65ecf2b934f0eed9b5041ad17b4d9eccf92e8 --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/unit/test_bond_id_repr.ml @@ -0,0 +1,147 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Trilitech *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Bond_id_repr + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- test Bond_id_repr + Dependencies: -- + Subject: Test bond id representations for RPC definitions. +*) + +open Protocol +open Lwt_result_syntax + +let assert_bond_id_result_equal ~loc = + Assert.equal_result + ~loc + ~pp_ok:Bond_id_repr.pp + ~pp_error:Format.pp_print_string + Bond_id_repr.( = ) + ( = ) + +let test_destruct_sc_bond_id_repr () = + let sc_rollup_address1 = "scr1HLXM32GacPNDrhHDLAssZG88eWqCUbyLF" in + let sc_rollup_address2 = "scr1Ew52VCdi6nF1JuokRGMqfmSeiAEXymW2m" in + let invalid_sc_rollup_address = "scr1HLXM32GacPNDrhHDLAssZG88eWqCUbyF" in + let destruct = Bond_id_repr.Internal_for_test.destruct in + let sc_bond id = + match Sc_rollup_repr.Address.of_b58check_opt id with + | Some id -> Ok (Bond_id_repr.Sc_rollup_bond_id id) + | None -> Error "Not an sc address" + in + let* _ = + assert_bond_id_result_equal + ~loc:__LOC__ + (destruct sc_rollup_address1) + (sc_bond sc_rollup_address1) + in + let* _ = + assert_bond_id_result_equal + ~loc:__LOC__ + (destruct sc_rollup_address2) + (sc_bond sc_rollup_address2) + in + Assert.is_error + ~loc:__LOC__ + ~pp:Bond_id_repr.pp + (destruct invalid_sc_rollup_address) + +let test_destruct_tx_bond_id_repr () = + let tx_rollup_address1 = "txr1UTQm2gtoVJNvJRGfwora8GmM7D5dnEcdb" in + let tx_rollup_address2 = "txr1YNMEtkj5Vkqsbdmt7xaxBTMRZjzS96UAi" in + let invalid_tx_rollup_address = "txr1YNMEtkj5Vkqsbdmt7xaxBTMRZjzS96Ui" in + let destruct = Bond_id_repr.Internal_for_test.destruct in + let tx_bond id = + match Tx_rollup_repr.of_b58check_opt id with + | Some id -> Ok (Bond_id_repr.Tx_rollup_bond_id id) + | None -> Error "Not a tx address" + in + let* _ = + assert_bond_id_result_equal + ~loc:__LOC__ + (destruct tx_rollup_address1) + (tx_bond tx_rollup_address1) + in + let* _ = + assert_bond_id_result_equal + ~loc:__LOC__ + (destruct tx_rollup_address2) + (tx_bond tx_rollup_address2) + in + Assert.is_error + ~loc:__LOC__ + ~pp:Bond_id_repr.pp + (destruct invalid_tx_rollup_address) + +let test_destruct_invalid_bond_id_repr () = + let invalid_address = "asdfasdfasdf" in + let empty_address = "" in + let destruct = Bond_id_repr.Internal_for_test.destruct in + let* _ = + Assert.is_error ~loc:__LOC__ ~pp:Bond_id_repr.pp (destruct invalid_address) + in + Assert.is_error ~loc:__LOC__ ~pp:Bond_id_repr.pp (destruct empty_address) + +let test_roundtrip () = + let destruct_for_rountrip v = + let r = + match Bond_id_repr.Internal_for_test.destruct v with + | Ok r -> return r + | _ -> failwith "Destruct failed for %s" v + in + r + in + let rountrip_test loc s = + let* r = destruct_for_rountrip s in + let s2 = Bond_id_repr.Internal_for_test.construct r in + Assert.equal_string ~loc s s2 + in + let tx_rollup_address1 = "txr1UTQm2gtoVJNvJRGfwora8GmM7D5dnEcdb" in + let tx_rollup_address2 = "txr1YNMEtkj5Vkqsbdmt7xaxBTMRZjzS96UAi" in + let sc_rollup_address1 = "scr1HLXM32GacPNDrhHDLAssZG88eWqCUbyLF" in + let sc_rollup_address2 = "scr1Ew52VCdi6nF1JuokRGMqfmSeiAEXymW2m" in + let* _ = rountrip_test __LOC__ tx_rollup_address1 in + let* _ = rountrip_test __LOC__ tx_rollup_address2 in + let* _ = rountrip_test __LOC__ sc_rollup_address1 in + rountrip_test __LOC__ sc_rollup_address2 + +let tests = + [ + Tztest.tztest + "Deserializing sc bond ids succeeds only when id is valid" + `Quick + test_destruct_sc_bond_id_repr; + Tztest.tztest + "Deserializing tx bond ids succeeds only when id is valid" + `Quick + test_destruct_tx_bond_id_repr; + Tztest.tztest + "Deserializing invalid bond ids fails" + `Quick + test_destruct_invalid_bond_id_repr; + Tztest.tztest "Deserialize/serialize roundtrip" `Quick test_roundtrip; + ]