Skip to content

Testing framework: a library

E. Rivas requested to merge er433/test/poc-lib into dev

This MR adds an explicit Test. library in code.

As an example, we remove a few functions (e.g. Test.michelson_equal, Test.get_storage and Test.compile_value) and replace them by LIGO code:

type test_exec_error = Rejected of (michelson_program * address) | Other
type test_exec_result = Success of nat | Fail of test_exec_error

module Internal__Test = struct
  module CURRY = struct
    let get_storage (type p s) (t : (p, s) typed_address) : s =
      let c : p contract = Test.to_contract t in
      let a : address = Tezos.address c in
      let s : michelson_program = Test.get_storage_of_address a in
      let s : s = Test.decompile s in
      s
    let eval (type a) (x : a) : michelson_program = Test.run (fun (x : a) -> x) x
    let compile_value (type a) (x : a) : michelson_program = Test.run (fun (x : a) -> x) x
    let to_address (type p s) (t : (p, s) typed_address) : address = Tezos.address (Test.to_contract t)
    let transfer (a : address) (mp : michelson_program) (m : tez) : test_exec_result =
      let ta : (unit, unit) typed_address = Test.cast_address a in
      let c : unit contract = Test.to_contract ta in
      Test.transfer_ c mp m
    let transfer_exn (a : address) (mp : michelson_program) (m : tez) : nat =
      let ta : (unit, unit) typed_address = Test.cast_address a in
      let c : unit contract = Test.to_contract ta in
      Test.transfer_exn_ c mp m
    let transfer_to_contract (type p) (c : p contract) (p : p) (m : tez) : test_exec_result =
      let mp : michelson_program = eval p in
      Test.transfer_ c mp m
    let transfer_to_contract_exn (type p) (c : p contract) (p : p) (m : tez) : nat =
      let mp : michelson_program = eval p in
      Test.transfer_exn_ c mp m
    let transfer_to_typed_address_exn (type p s) (ta : (p, s) typed_address) (p : p) (m : tez) : nat =
      let c : p contract = Test.to_contract ta in
      transfer_to_contract_exn c p m
    let michelson_equal (v : michelson_program) (w : michelson_program) : bool = v = w
  end
  module UNCURRY = struct
    let get_storage (type p s) (t : (p, s) typed_address) : s = CURRY.get_storage t
    let eval (type a) (x : a) : michelson_program = CURRY.eval x
    let compile_value (type a) (x : a) : michelson_program = CURRY.compile_value x
    let to_address (type p s) (t : (p, s) typed_address) : address = CURRY.to_address t
    let transfer ((a, p, m) : address * michelson_program * tez) : test_exec_result = CURRY.transfer a p m
    let transfer_exn ((a, p, m) : address * michelson_program * tez) : nat = CURRY.transfer_exn a p m
    let transfer_to_contract (type p) ((c, p, m) : p contract * p * tez) : test_exec_result = CURRY.transfer_to_contract c p m
    let transfer_to_contract_exn (type p) ((c, p, m) : p contract * p * tez) : nat = CURRY.transfer_to_contract_exn c p m
    let transfer_to_typed_address_exn (type p s) ((ta, p, m) : (p, s) typed_address * p * tez) : nat = CURRY.transfer_to_typed_address_exn ta p m
    let michelson_equal ((v, w) : michelson_program * michelson_program) : bool = CURRY.michelson_equal v w
  end
end

We also add two functions to Test., which are to_address and transfer_to_typed_address_exn, as an example. These functions are not essential, and this is why they were not implemented, but it's nice to provide them to LIGO users. We also remove test_exec_error and test_exec_result from the environment, and add them as defined by the library.

Main changes:

  • Abstractors: if built-in search fails, constructs regular accessor for module instead of failing.
  • Typing: removed those custom typing rules for the constants.
  • Vendored build system: only postprocess : t -> t is included (it could be kept out, but it could be useful for other things).
  • Environment: we define what a "library" is there:
type lib = {
    code : module_ ;
    install_lib : Self_ast_imperative.Syntax.v_syntax -> module_
}

The field code is the library code (Internal__Test thing above). The install_lib is a code installing the library (used in each file, depends on the language to solve curried/uncurried calling convention of functions which are originally operators):

  let install_lib = function
    | CameLIGO ->
       [Location.wrap @@ Ast_typed.Module_alias { alias = "Test" ; binders = List.Ne.of_list ["Internal__Test"; "CURRY"] } ]
    | ReasonLIGO | PascaLIGO | JsLIGO ->
       [Location.wrap @@ Ast_typed.Module_alias { alias = "Test" ; binders = List.Ne.of_list ["Internal__Test"; "UNCURRY"] } ] in
  Environment.{ code ; install_lib }
  • Build: the function build_context has an optional parameter for the library.

  • API: before calling eval_test, we ask for the test library.

  • Example with big_maps: show how we can simply use Test.transfer_to_typed_address_exn.

  • has a changelog entry

Edited by E. Rivas

Merge request reports