Raw File
qcheck2_helpers.mli
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 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.                                                 *)
(*                                                                           *)
(*****************************************************************************)

(** Wrap QCheck tests into Alcotest. *)
val qcheck_wrap :
  ?verbose:bool ->
  ?long:bool ->
  ?rand:Random.State.t ->
  QCheck2.Test.t list ->
  unit Alcotest.test_case list

(** Wrap QCheck tests into Alcotest_lwt. *)
val qcheck_wrap_lwt :
  ?verbose:bool ->
  ?long:bool ->
  ?rand:Random.State.t ->
  QCheck2.Test.t list ->
  (string * [`Quick | `Slow] * (unit -> unit Lwt.t)) list

(** [qcheck_make_result ?print ?pp_error ?count ?check ~name ~gen f]
    is a wrapper around {!QCheck2.Test.make} where [f] returns a
    result type. If [check] is not provided and if the result of [f] is
    an error, {!Qcheck2.Test.fail_reportf} is called and the error is
    shown if [pp_error] is provided. *)
val qcheck_make_result :
  ?count:int ->
  ?print:'a QCheck2.Print.t ->
  ?pp_error:(Format.formatter -> 'b -> unit) ->
  ?check:((bool, 'b) result -> bool) ->
  name:string ->
  gen:'a QCheck2.Gen.t ->
  ('a -> (bool, 'b) result) ->
  QCheck2.Test.t

(** [qcheck_make_lwt ?print ?count ~extract ~name ~gen f] is a wrapper
    around {!QCheck2.Test.make} where [f] returns a [bool Lwt.t].
    [extract] needs to be provided to extract the [bool] from [Lwt], e.g.
    [Lwt_main.run]. *)
val qcheck_make_lwt :
  ?count:int ->
  ?print:'a QCheck2.Print.t ->
  extract:(bool Lwt.t -> bool) ->
  name:string ->
  gen:'a QCheck2.Gen.t ->
  ('a -> bool Lwt.t) ->
  QCheck2.Test.t

(** [qcheck_make_result_lwt ?print ?count ~extract ~name ~gen f] is
    the combination of [qcheck_make_result] and [qcheck_make_lwt]. *)
val qcheck_make_result_lwt :
  ?count:int ->
  ?print:'a QCheck2.Print.t ->
  ?pp_error:(Format.formatter -> 'b -> unit) ->
  ?check:((bool, 'b) result -> bool) ->
  extract:((bool, 'b) result Lwt.t -> (bool, 'b) result) ->
  name:string ->
  gen:'a QCheck2.Gen.t ->
  ('a -> (bool, 'b) result Lwt.t) ->
  QCheck2.Test.t

(** [qcheck_eq_tests ~eq ~gen ~eq_name] returns
    three tests of [eq]: reflexivity, symmetry, and transitivity.

    [eq_name] should be the name of the function defining [eq].
    For example, given an equality function defined as [let mytype_eq = ...],
    call [qcheck_eq_tests mytype_eq gen "mytype_eq"]. [eq_name] is
    only used for logging. *)
val qcheck_eq_tests :
  eq:('a -> 'a -> bool) ->
  gen:'a QCheck2.Gen.t ->
  eq_name:string ->
  QCheck2.Test.t list

(** [qcheck_eq pp cmp eq a b] evaluates whether [a] and [b] are equal, and if they
    are not, raises a failure and prints an error message.
    Equality is evaluated as follows:
    - use a provided [eq]
    - if no [eq] is provided, use a provided [cmp]
    - if neither [eq] nor [cmp] is provided, use {!Stdlib.compare}

    If [pp] is provided, use this to print [x] and [y] if they are not equal.

    If [__LOC__] is provided, print it at the beginning of the error message
    when applicable. *)
val qcheck_eq :
  ?pp:(Format.formatter -> 'a -> unit) ->
  ?cmp:('a -> 'a -> int) ->
  ?eq:('a -> 'a -> bool) ->
  ?__LOC__:string ->
  'a ->
  'a ->
  bool

(** Similar to {!qcheck_eq} but tests that two values are {e not} equal. *)
val qcheck_neq :
  ?pp:(Format.formatter -> 'a -> unit) ->
  ?cmp:('a -> 'a -> int) ->
  ?eq:('a -> 'a -> bool) ->
  'a ->
  'a ->
  bool

(** Labeled variant of {!qcheck_eq}. The [unit] argument is necessary as OCaml
    requires at least one positional (non-labeled) argument in case of optional
    arguments. *)
val qcheck_eq' :
  ?pp:(Format.formatter -> 'a -> unit) ->
  ?cmp:('a -> 'a -> int) ->
  ?eq:('a -> 'a -> bool) ->
  expected:'a ->
  actual:'a ->
  unit ->
  bool

(** [qcheck_cond pp cond a] evaluate [cond a], if this condition is false,
    raises a failure and prints an error message.

    If [pp] is provided, use this to print [a] if [cond a] is false. *)
val qcheck_cond :
  ?pp:(Format.formatter -> 'a -> unit) ->
  cond:('a -> bool) ->
  'a ->
  unit ->
  bool

(** [int64_range_gen a b] generates an [int64] between [a] inclusive
    and [b] inclusive.

    Poorman's implementation until
    https://github.com/c-cube/qcheck/issues/105 is done. *)
val int64_range_gen : int64 -> int64 -> int64 QCheck2.Gen.t

(** [int32_range_gen a b] generates an [int32] between [a] inclusive
    and [b] inclusive.

    Poorman's implementation until
    https://github.com/c-cube/qcheck/issues/105 is done. *)
val int32_range_gen : int32 -> int32 -> int32 QCheck2.Gen.t

(** [int64_strictly_positive_gen x] generates an [int64] between [1] inclusive
    and [x] inclusive.

    This will fail if [x] is not strictly positive. *)
val int64_strictly_positive_gen : int64 -> int64 QCheck2.Gen.t

(** [int_strictly_positive_gen x] generates an [int] between [1] inclusive
    and [x] inclusive.

    This will fail if [x] is not strictly positive. *)
val int_strictly_positive_gen : int -> int QCheck2.Gen.t

(** [uint16] is a generator of unsigned int16 values *)
val uint16 : int QCheck2.Gen.t

(** [int16] is a generator of signed int16 values *)
val int16 : int QCheck2.Gen.t

(** [uint8] is a generator of unsigned int8 values *)
val uint8 : int QCheck2.Gen.t

(** [int8] is a generator of signed int8 values  *)
val int8 : int QCheck2.Gen.t

(** [string_fixed n] is a generator of strings of length [n]. *)
val string_fixed : int -> string QCheck2.Gen.t

(** [bytes_gen] is a [QCheck2.Gen.t] for [bytes]. *)
val bytes_gen : bytes QCheck2.Gen.t

(** [small_bytes_gen] is a [QCheck2.Gen.t] for [bytes] of small size. *)
val small_bytes_gen : bytes QCheck2.Gen.t

(** [bytes_fixed_gen n] is a [QCheck2.Gen.t] for [bytes] of length [n]. *)
val bytes_fixed_gen : int -> bytes QCheck2.Gen.t

(** [endpoint_gen] is a [QCheck2.Gen.t] for endpoints (such as
    [octez-client]'s [--endpoint] flag). It returns URLs of the form:
    [(http|https)://(string\.)+(:port)?]. It is by no means the most
    general [Uri.t] generator. Generalize it if needed. *)
val endpoint_gen : Uri.t QCheck2.Gen.t

(** A generator that returns a sublist of the given list. Lists returned
    by this generator are not in the same order as the given list
    (they are shuffled). This generator can return a list equal to the input list
    (this generator does not guarantee to return strict sublists of the input list). *)
val sublist : 'a list -> 'a list QCheck2.Gen.t

(** A generator that returns lists whose elements are from the given list,
    preserving the order. For example, given the input list [0, 1, 2],
    this generator can produce [], [0], [0, 2], [1, 2], [1], etc. *)
val holey : 'a list -> 'a list QCheck2.Gen.t

(** [of_option_gen gen] converts a generator [gen] of optional values into a
    generator of values by rerunning the generator if the generated value
    was a [None] until a [Some] is generated.

    Be careful: if [None] is always returned, this hangs forever! *)
val of_option_gen : 'a option QCheck2.Gen.t -> 'a QCheck2.Gen.t

(** Map-related generators. *)
module MakeMapGen (Map : sig
  type 'a t

  type key

  val of_seq : (key * 'a) Seq.t -> 'a t
end) : sig
  (** [gen_of_size size_gen key_gen val_gen] is a generator of Map where the keys
      are generated with [key_gen] and the values with [val_gen].
      The number of entries in the map is decided by [size_gen]. *)
  val gen_of_size :
    int QCheck2.Gen.t ->
    Map.key QCheck2.Gen.t ->
    'v QCheck2.Gen.t ->
    'v Map.t QCheck2.Gen.t

  (** [gen key_gen gen_gen] is a generator of Map where the keys
      are generated with [key_gen] and the values with [val_gen]. *)
  val gen : Map.key QCheck2.Gen.t -> 'v QCheck2.Gen.t -> 'v Map.t QCheck2.Gen.t
end

(** Test the roundtripness of an encoding both in JSON and binary formats. *)
val test_roundtrip :
  count:int ->
  title:string ->
  gen:'a QCheck2.Gen.t ->
  eq:('a -> 'a -> bool) ->
  'a Data_encoding.t ->
  QCheck2.Test.t

(** Test the roundtripness of two encodings in binary formats. *)
val test_roundtrip_through_binary :
  count:int ->
  title:string ->
  gen:'a QCheck2.Gen.t ->
  eq:('a -> 'a -> bool) ->
  'a Data_encoding.t ->
  'a Data_encoding.t ->
  QCheck2.Test.t
back to top