File: STM.mli

package info (click to toggle)
ocaml-multicoretests 0.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,532 kB
  • sloc: ml: 8,904; awk: 66; ansic: 23; makefile: 11; sh: 1
file content (252 lines) | stat: -rw-r--r-- 10,185 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
(** Module with combinators and definitions to specify an STM test *)

(** Extensible type to represent result values *)
type 'a ty = ..

(** A range of constructors to represent built-in types *)
type _ ty +=
  | Unit : unit ty
  | Bool : bool ty
  | Char : char ty
  | Int : int ty
  | Int32 : int32 ty
  | Int64 : int64 ty
  | Float : float ty
  | String : string ty
  | Bytes : bytes ty
  | Exn : exn ty
  | Option : 'a ty -> 'a option ty
  | Result : 'a ty * 'b ty -> ('a, 'b) result ty
  | List : 'a ty -> 'a list ty
  | Array : 'a ty -> 'a array ty
  | Seq : 'a ty -> 'a Seq.t ty

type 'a ty_show = 'a ty * ('a -> string)
(** Combinator type to represent an OCaml type along with an associated [to_string] function *)

val unit : unit ty_show
(** Combinator to represent the {{!Stdlib.Unit.t}[unit]} type *)

val bool : bool ty_show
(** Combinator to represent the {{!Stdlib.Bool.t}[bool]} type *)

val char : char ty_show
(** Combinator to represent the {{!Stdlib.Char.t}[char]} type *)

val int : int ty_show
(** Combinator to represent the {{!Stdlib.Int.t}[int]} type *)

val int32 : int32 ty_show
(** Combinator to represent the {{!Stdlib.Int32.t}[int32]} type *)

val int64 : int64 ty_show
(** Combinator to represent the {{!Stdlib.Int64.t}[int64]} type *)

val float : float ty_show
(** Combinator to represent the {{!Stdlib.Float.t}[float]} type *)

val string : string ty_show
(** Combinator to represent the {{!Stdlib.String.t}[string]} type *)

val bytes : bytes ty_show
(** Combinator to represent the {{!Stdlib.Bytes.t}[bytes]} type *)

val option : 'a ty_show -> 'a option ty_show
(** [option t] builds a [t] {{!Stdlib.Option.t}[option]} type representation *)

val exn : exn ty_show
(** Combinator to represent the [exception] type *)

val result : 'a ty_show -> 'b ty_show -> ('a,'b) Result.t ty_show
(** [result a b] builds an [(a,b)] {{!Stdlib.Result.t}[result]} type representation *)

val list : 'a ty_show -> 'a list ty_show
(** [list t] builds a [t] {{!Stdlib.List.t}[list]} type representation *)

val array : 'a ty_show -> 'a array ty_show
(** [array t] builds a [t] {{!Stdlib.Array.t}[array]} type representation *)

val seq : 'a ty_show -> 'a Seq.t ty_show
(** [seq t] builds a [t] {{!Stdlib.Seq.t}[Seq.t]} type representation *)

type res =
  Res : 'a ty_show * 'a -> res

val show_res : res -> string


(** The specification of a state machine.

    See also {!SpecExt} and {!SpecDefaults}. *)
module type Spec =
sig
  type cmd
  (** The type of commands *)

  type state
  (** The type of the model's state *)

  type sut
  (** The type of the system under test *)

  val arb_cmd : state -> cmd QCheck.arbitrary
  (** A command generator. Accepts a state parameter to enable state-dependent {!cmd} generation. *)

  val init_state : state
  (** The model's initial state. *)

  val show_cmd : cmd -> string
  (** [show_cmd c] returns a string representing the command [c]. *)

  val next_state : cmd -> state -> state
  (** [next_state c s] expresses how interpreting the command [c] moves the
      model's internal state machine from the state [s] to the next state.
      Ideally a [next_state] function is pure, as it is run more than once.  *)

  val init_sut : unit -> sut
  (** Initialize the system under test. *)

  val cleanup : sut -> unit
  (** Utility function to clean up the {!sut} after each test instance,
      e.g., for closing sockets, files, or resetting global parameters*)

  val precond : cmd -> state -> bool
  (** [precond c s] expresses preconditions for command [c] in terms of the model state [s].
      A [precond] function should be pure.
      [precond] is useful, e.g., to prevent the shrinker from breaking invariants when minimizing
      counterexamples. *)

  val run : cmd -> sut -> res
  (** [run c i] should interpret the command [c] over the system under test (typically side-effecting). *)

  val postcond : cmd -> state -> res -> bool
  (** [postcond c s res] checks whether [res] arising from interpreting the
      command [c] over the system under test with {!run} agrees with the
      model's result. A [postcond] function should be a pure.

      {b Note:} the state parameter [s] is the model's {!state} before executing the command [c] (the "old/pre" state).
      This is helpful to model, e.g., a [remove] [cmd] that returns the removed element. *)
end

module type SpecExt =
sig
  (** Extended specification of a state machine.

      This signature may be extended in the future with new specifications that
      can be given defaults via {!SpecDefaults}. *)

  include Spec

  val wrap_cmd_seq : (unit -> 'a) -> 'a
  (** [wrap_cmd_seq] is used to wrap the execution of the generated command
      sequences. [wrap_cmd_seq] is useful, e.g., to handle effects performed by
      blocking primitives. [wrap_cmd_seq thunk] must call [thunk ()] and return
      or raise whatever [thunk ()] returned or raised. *)
end

module SpecDefaults :
sig
  (** Default implementations for state machine specifications that can be given
      useful defaults.

      The intention is that extended spec modules would [include] the defaults:

      {[
        module MySpec = struct
          include SpecDefaults

          (* ... *)
        end
      ]}

      This way the spec module can usually just continue working after new
      specifications have been added to {!SpecExt} with defaults in
      {!SpecDefaults}. *)

  val cleanup : 'sut -> unit
  (** [cleanup sut] just returns [()]. *)

  val precond : 'cmd -> 'state -> bool
  (** [precond cmd state] just returns [true]. *)

  val wrap_cmd_seq : (unit -> 'a) -> 'a
  (** [wrap_cmd_seq thunk] is equivalent to [thunk ()]. *)
end

module Internal : sig
open QCheck
(** Internal helper module to build STM tests. *)


(** Derives a test framework from a state machine specification. *)
module Make (Spec : Spec) :
sig
  (** {3 The resulting test framework derived from a state machine specification} *)

    val cmds_ok : Spec.state -> Spec.cmd list -> bool
    (** A precondition checker (stops early, thanks to short-circuit Boolean evaluation).
        Accepts the initial state and the command sequence as parameters.
        [cmds_ok] catches and ignores exceptions arising from {!next_state}.  *)

    val arb_cmds : Spec.state -> Spec.cmd list arbitrary
    (** A generator of command sequences. Accepts the initial state as parameter. *)

    val consistency_test : count:int -> name:string -> QCheck.Test.t
    (** A consistency test that generates a number of [cmd] sequences and
        checks that all contained [cmd]s satisfy the precondition [precond].
        Accepts two labeled parameters:
        [count] is the test count and [name] is the printed test name. *)

    val interp_agree : Spec.state -> Spec.sut -> Spec.cmd list -> bool
    (** Checks agreement between the model and the system under test
        (stops early, thanks to short-circuit Boolean evaluation). *)

    val check_disagree : Spec.state -> Spec.sut -> Spec.cmd list -> (Spec.cmd * res) list option
    (** [check_disagree state sut pg] checks that none of the commands present
        in [pg] violated the declared postconditions when [pg] is run in [state].
        Return [None] if none of the commands violate its postcondition, and
        [Some] list corresponding to the prefix of [pg] ending with the [cmd]
        violating its postcondition. *)

    val check_obs : (Spec.cmd * res) list -> (Spec.cmd * res) list -> (Spec.cmd * res) list -> Spec.state -> bool
    (** [check_obs pref cs1 cs2 s] tests whether the observations from the sequential prefix [pref]
        and the parallel traces [cs1] [cs2] agree with the model started in state [s]. *)

    val gen_cmds_size : (Spec.state -> Spec.cmd arbitrary) -> Spec.state -> int Gen.t -> Spec.cmd list Gen.t
    (** [gen_cmds_size arb state gen_int] generates a program of size generated
        by [gen_int] using [arb] to generate [cmd]s according to the current
        state. [state] is the starting state.
        [gen_cmds_size] catches and ignores generation-time exceptions arising
        from {!next_state}. *)

    val arb_cmds_triple : int -> int -> (Spec.cmd list * Spec.cmd list * Spec.cmd list) arbitrary
    (** [arb_cmds_triple seq_len par_len] generates a [cmd] triple with at most [seq_len]
        sequential commands and at most [par_len] parallel commands each.
        [arb_cmds_triple] catches and ignores generation-time exceptions arising
        from {!next_state}. *)

    val all_interleavings_ok : Spec.cmd list -> Spec.cmd list -> Spec.cmd list -> Spec.state -> bool
    (** [all_interleavings_ok seq spawn0 spawn1 state] checks that
        preconditions of all the {!cmd}s of [seq], [spawn0], and [spawn1] are satisfied in all the
        possible interleavings and starting with [state].
        [all_interleavings_ok] catches and ignores exceptions arising from
        {!next_state}. *)

    val shrink_triple : (Spec.state -> Spec.cmd arbitrary) -> (Spec.state -> Spec.cmd arbitrary) -> (Spec.state -> Spec.cmd arbitrary) -> (Spec.cmd list * Spec.cmd list * Spec.cmd list) Shrink.t
    (** [shrink_triple arb0 arb1 arb2] is a {!QCheck.Shrink.t} for programs (triple of list of [cmd]s) that is specialized for each part of the program. *)

    val arb_triple : int -> int -> (Spec.state -> Spec.cmd arbitrary) -> (Spec.state -> Spec.cmd arbitrary) -> (Spec.state -> Spec.cmd arbitrary) -> (Spec.cmd list * Spec.cmd list * Spec.cmd list) arbitrary
    (** [arb_triple seq_len par_len arb0 arb1 arb2] generates a [cmd] triple with at most [seq_len]
        sequential commands and at most [par_len] parallel commands each.
        The three [cmd] components are generated with [arb0], [arb1], and [arb2], respectively.
        Each of these take the model state as a parameter.
        [arb_triple] catches and ignores generation-time exceptions arising
        from {!next_state}. *)
end
  [@@alert internal "This module is exposed for internal uses only, its API may change at any time"]

end


val protect : ('a -> 'b) -> 'a -> ('b, exn) result
(** [protect f] turns an [exception]-throwing function into a {{!Stdlib.Result.t}[result]}-returning function. *)