forked from c-cube/qcheck
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQCheck.mli
More file actions
2178 lines (1658 loc) · 73.9 KB
/
QCheck.mli
File metadata and controls
2178 lines (1658 loc) · 73.9 KB
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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(*
QCheck: Random testing for OCaml
copyright (c) 2013-2017, Guillaume Bury, Simon Cruanes, Vincent Hugot,
Jan Midtgaard, Julien Debon, Valentin Chaboche
all rights reserved.
*)
(** {1 Quickcheck inspired property-based testing} *)
(** {1 Introduction}
The library takes inspiration from Haskell's QuickCheck library. The
rough idea is that the programmer describes invariants that values of
a certain type need to satisfy ("properties"), as functions from this type
to [bool]. The programmer also needs to describe how to generate random values of the type,
so that the property is tried and checked on a number of random instances.
This explains the organization of this module:
- {{!section:arbitrary}The ['a arbitrary] record type} describes how to generate random values,
shrink them (reduce counter-examples to a minimum), print them, etc.
It is the generator type expected by {!Test.make}.
- Auxiliary modules such as {!Gen}, {!Print}, and {!Shrink} can be used along with {!make}
to build custom generators.
- {!Test} is used to describe a single test, that is, a property of
type ['a -> bool] combined with an ['a arbitrary] that is used to generate
the test cases for this property. Optional parameters
allow to specify the random generator state, number of instances to generate
and test, etc.
{1 Examples}
- List.rev is involutive:
{[
let test =
QCheck.(Test.make ~count:1000
(list int) (fun l -> List.rev (List.rev l) = l));;
QCheck.Test.check_exn test;;
]}
- Not all lists are sorted (false property that will fail. The 15 smallest
counter-example lists will be printed):
{[
let test = QCheck.(
Test.make
~count:10_000 ~max_fail:3
(list nat_small)
(fun l -> l = List.sort compare l));;
QCheck.Test.check_exn test;;
]}
- generate 20 random trees using {! Gen.fix} :
{[
type tree = Leaf of int | Node of tree * tree
let leaf x = Leaf x
let node x y = Node (x,y)
let g = QCheck.Gen.(sized @@ fix
(fun self n -> match n with
| 0 -> map leaf nat
| n ->
frequency
[1, map leaf nat;
2, map2 node (self (n/2)) (self (n/2))]
))
Gen.generate ~n:20 g;;
]}
More complex and powerful combinators can be found in Gabriel Scherer's
{{:https://github.com/gasche/random-generator}[Generator]} module. Its documentation can be found
{{:http://gasche.github.io/random-generator/doc/Generator.html } here}.
*)
(** {1 Assumptions} *)
val (==>) : bool -> bool -> bool
(** [b1 ==> b2] is the logical implication [b1 => b2]
ie [not b1 || b2] (except that it is strict and will interact
better with {!Test.check_exn} and the likes, because they will know
the precondition was not satisfied.).
{b WARNING}: this function should only be used in a property
(see {!Test.make}), because it raises a special exception in case of
failure of the first argument, to distinguish between failed test
and failed precondition. Because of OCaml's evaluation order,
both [b1] and [b2] are always evaluated; if [b2] should only be
evaluated when [b1] holds, see {!assume}.
*)
val assume : bool -> unit
(** [assume cond] checks the precondition [cond], and does nothing
if [cond=true]. If [cond=false], it interrupts the current test.
{b WARNING} This function, like {!(==>)}, should only be used in
a test, not outside.
Example:
{[
Test.make (list int) (fun l ->
assume (l <> []);
List.hd l :: List.tl l = l)
]}
@since 0.5.1
*)
val assume_fail : unit -> 'a
(** [assume_fail ()] is like [assume false], but can take any type
since we know it always fails (like [assert false]).
This is useful to ignore some branches in [if] or [match].
Example:
{[
Test.make (list int) (function
| [] -> assume_fail ()
| _::_ as l -> List.hd l :: List.tl l = l)
]}
@since 0.5.1
*)
(** {1 Generate Random Values} *)
module Gen : sig
(** The [Gen] module offers combinators to build custom generators.
Unlike the {{!section:arbitrary}the ['a arbitrary] record type},
which comes with printers, shrinkers, etc. {!Gen.t} represents
a type for generation only. *)
type 'a t = Random.State.t -> 'a
(** A random generator for values of type 'a. *)
type 'a sized = int -> Random.State.t -> 'a
(** Random generator with a size bound. *)
val return : 'a -> 'a t
(** Create a constant generator. *)
val pure : 'a -> 'a t
(** Synonym for {!return}
@since 0.8 *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Monadic bind for writing dependent generators. First generates an ['a] and then
passes it to the given function, to generate a ['b]. *)
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
(** Infix operator for composing a function generator and an argument generator
into a result generator. *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** [map f g] transforms a generator [g] by applying [f] to each generated element. *)
val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** [map2 f g1 g2] transforms two generators [g1] and [g2] by applying [f] to each
pair of generated elements. *)
val map3 : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t
(** [map3 f g1 g2 g3] transforms three generators [g1], [g2], and [g3] by applying [f]
to each triple of generated elements. *)
val map4 : ('a -> 'b -> 'c -> 'd -> 'e) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t
(** [map4 f g1 g2 g3 g4] transforms four generators [g1], [g2], [g3], and [g4]
by applying [f] to each quadruple of generated elements.
@since 0.25 *)
val map5 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t
(** [map5 f g1 g2 g3 g4 g5] transforms five generators [g1], [g2], [g3], [g4],
and [g5] by applying [f] to each quintuple of generated elements.
@since 0.25 *)
val map_keep_input : ('a -> 'b) -> 'a t -> ('a * 'b) t
(** [map_keep_input f g] transforms a generator [g] by applying [f] to each generated element.
Returns both the generated element from [g] and the output from [f]. *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
(** An infix synonym for {!map}. *)
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
(** An infix synonym for {!map}
@since 0.13 *)
val oneof : 'a t list -> 'a t
(** Constructs a generator that selects among a given list of generators.
@raise Invalid_argument or Failure if list is empty *)
val oneofl : 'a list -> 'a t
(** Constructs a generator that selects among a given list of values.
@raise Invalid_argument or Failure if list is empty *)
val oneofa : 'a array -> 'a t
(** Constructs a generator that selects among a given array of values.
@raise Invalid_argument or Failure if list is empty *)
val frequency : (int * 'a t) list -> 'a t
(** Constructs a generator that selects among a given list of generators.
Each of the given generators are chosen based on a positive integer weight. *)
val frequencyl : (int * 'a) list -> 'a t
(** Constructs a generator that selects among a given list of values.
Each of the given values are chosen based on a positive integer weight. *)
val frequencya : (int * 'a) array -> 'a t
(** Constructs a generator that selects among a given array of values.
Each of the array entries are chosen based on a positive integer weight. *)
val shuffle_a : 'a array -> unit t
(** Shuffles the array in place. *)
val shuffle_l : 'a list -> 'a list t
(** Creates a generator of shuffled lists. *)
val shuffle_w_l : (int * 'a) list -> 'a list t
(** Creates a generator of weighted shuffled lists. A given list is shuffled on each
generation according to the weights of its elements. An element with a larger weight
is more likely to be at the front of the list than an element with a smaller weight.
If we want to pick random elements from the (head of) list but need to prioritize
some elements over others, this generator can be useful.
Example: given a weighted list [[1, "one"; 5, "five"; 10, "ten"]], the generator is
more likely to generate [["ten"; "five"; "one"]] or [["five"; "ten"; "one"]] than
[["one"; "ten"; "five"]] because "ten" and "five" have larger weights than "one".
@since 0.11
*)
val range_subset : size:int -> int -> int -> int array t
(** [range_subset ~size:k low high] generates an array of length [k]
of sorted distinct integers in the range [low..high] (included).
Complexity O(k log k), drawing [k] random integers.
@raise Invalid_argument outside the valid region [0 <= k <= high-low+1].
@since 0.18
*)
val array_subset : int -> 'a array -> 'a array t
(** [array_subset k arr] generates a sub-array of [k] elements
at distinct positions in the input array [arr],
in the same order.
Complexity O(k log k), drawing [k] random integers.
@raise Invalid_argument outside the valid region
[0 <= size <= Array.length arr].
@since 0.18
*)
(** {3 Primitive generators} *)
val unit : unit t (** The unit generator. *)
val bool : bool t (** The boolean generator. *)
val float : float t (** Generates floating point numbers. *)
val float_pos : float t (** Generates positive floating point numbers (0. included). *)
val float_neg : float t (** Generates negative floating point numbers (-0. included). *)
val pfloat : float t
(** Generates positive floating point numbers (0. included).
@deprecated use {!float_pos} instead. *)
val nfloat : float t
(** Generates negative floating point numbers (-0. included).
@deprecated use {!float_neg} instead. *)
val float_bound_inclusive : float -> float t
(** [float_bound_inclusive bound] returns a random floating-point number between 0 and
[bound] (inclusive). If [bound] is negative, the result is negative or zero. If
[bound] is 0, the result is 0.
@since 0.11 *)
val float_bound_exclusive : float -> float t
(** [float_bound_exclusive bound] returns a random floating-point number between 0 and
[bound] (exclusive). If [bound] is negative, the result is negative or zero.
@raise Invalid_argument if [bound] is zero.
@since 0.11 *)
val float_range : float -> float -> float t
(** [float_range low high] generates floating-point numbers within [low] and [high] (inclusive)
@raise Invalid_argument if [high < low] or if the range is larger than [max_float].
@since 0.11 *)
val (--.) : float -> float -> float t
(** Synonym for [float_range]
@since 0.11 *)
val float_exp : float -> float t
(** [float_exp m] generates floating-point numbers following an exponential
distribution with a mean of [m].
@raise Invalid_argument if [m] is NaN.
@since NEXT_RELEASE *)
val exponential : float -> float t
(** Synonym for {!float_exp}.
@since 0.23 *)
val nat : int t
(** Generates small natural numbers. *)
val int_pos_mid : int t
(** Generates small natural numbers.
Synonym for {!nat}.
@since NEXT_RELEASE *)
val big_nat : int t
(** Generates natural numbers, possibly large.
@since 0.10
@deprecated use [map abs int] instead. *)
val int_neg : int t
(** Generates strictly negative integers uniformly (0 excluded).
@since NEXT_RELEASE *)
val neg_int : int t
(** Generates non-strictly negative integers (0 included).
@deprecated use {!int_neg} or [map (fun i -> -i) nat] instead. *)
val int_pos : int t
(** Generates non-strictly positive integers uniformly (0 included).
@since NEXT_RELEASE *)
val pint : int t
(** Generates non-strictly positive integers uniformly (0 included).
@deprecated use {!int_pos} instead. *)
val int : int t (** Generates integers uniformly. *)
val int_small : int t
(** Generated small signed integers.
@since NEXT_RELEASE *)
val int_pos_small : int t
(** Small integers (< 100)
@since NEXT_RELEASE *)
val nat_small : int t
(** Small integers (< 100)
Synonym for {!int_pos_small}.
@since NEXT_RELEASE *)
val small_nat : int t
(** Small integers (< 100)
@since 0.5.1
@deprecated use {!nat_small} instead *)
val small_int : int t
(** Small UNSIGNED integers, for retrocompatibility.
@deprecated use {!nat_small}. *)
val small_signed_int : int t
(** Small SIGNED integers, based on {!small_nat}.
@since 0.5.2
@deprecated use {!int_small} instead. *)
val int_bound : int -> int t
(** Uniform integer generator producing integers between [0] and [bound]
(inclusive).
For [bound < 2^{30} - 1] uses [Random.State.int] for integer generation.
@raise Invalid_argument if the argument is negative. *)
val int_range : int -> int -> int t
(** Uniform integer generator producing integers within [low,high] (inclusive).
@raise Invalid_argument if [low > high]. *)
val graft_corners : 'a t -> 'a list -> unit -> 'a t
(** [graft_corners gen l ()] makes a new generator that enumerates
the corner cases in [l] and then behaves like [g].
Note that [graft_corners gen l ()] is stateful, meaning that once the
elements of [l] have been emitted, subsequent calls will not reproduce
them. It is therefore recommended that separate tests each use a fresh
generator.
@since 0.6 *)
val int_pos_corners : int list
(** Non-negative corner cases for int.
@since 0.6 *)
val int_corners : int list
(** All corner cases for int.
@since 0.6 *)
val int_small_corners : unit -> int t
(** As [int_small], but each newly created generator starts with
a list of corner cases before falling back on random generation.
Note that [int_small_corners ()] is stateful, meaning that once the list of
corner cases has been emitted, subsequent calls will not reproduce them.
@since NEXT_RELEASE *)
val (--) : int -> int -> int t (** Synonym for {!int_range}. *)
val int32 : int32 t
(** Generates [int32] values uniformly.
@since 0.24 *)
val int64 : int64 t
(** Generates [int64] values uniformly.
@since 0.24 *)
val ui32 : int32 t
(** Generates [int32] values.
@deprecated use {!val:int32} instead, the name is wrong, values {i are} signed.
*)
val ui64 : int64 t
(** Generates [int64] values.
@deprecated use {!val:int64} instead, the name is wrong, values {i are} signed.
*)
val list : 'a t -> 'a list t
(** Builds a list generator from an element generator. List size is generated by {!nat}. *)
val list_size : int t -> 'a t -> 'a list t
(** Builds a list generator from a (non-negative) size generator and an element generator. *)
val list_repeat : int -> 'a t -> 'a list t
(** [list_repeat i g] builds a list generator from exactly [i] elements generated by [g].
@deprecated use [list_size (return i) g] instead. *)
val array : 'a t -> 'a array t
(** Builds an array generator from an element generator. Array size is generated by {!nat}. *)
val array_size : int t -> 'a t -> 'a array t
(** Builds an array generator from a (non-negative) size generator and an element generator. *)
val array_repeat : int -> 'a t -> 'a array t
(** [array_repeat i g] builds an array generator from exactly [i] elements generated by [g].
@deprecated use [array_size (return i) g] instead. *)
val option : ?ratio:float -> 'a t -> 'a option t
(** An option generator, with optional ratio.
@param ratio a float between [0.] and [1.] indicating the probability of a sample to be [Some _]
rather than [None].
@since 0.19 (renamed from [opt])
*)
val opt : ?ratio:float -> 'a t -> 'a option t
(** [opt] is an alias of {!val:option} for backward compatibility.
@since 0.18 ([?ratio] parameter)
*)
val result : ?ratio:float -> 'a t -> 'e t -> ('a, 'e) result t
(** A result generator, with optional ratio.
@param ratio a float between [0.] and [1.] indicating the probability of a sample to be [Ok _]
rather than [Error _].
@since 0.24
*)
val char : char t
(** Generates characters upto character code 255. *)
val char_printable : char t
(** Generates printable ascii characters - either '\n' or in the range 32 to 126, inclusive.
@since NEXT_RELEASE *)
val printable : char t
(** Synonym for {!char_printable}. *)
val char_numeral : char t
(** Generates numeral characters uniformly distributed over ['0'..'9'].
@since NEXT_RELEASE *)
val numeral : char t
(** Synonym for {!char_numeral}. *)
val char_range : char -> char -> char t
(** Generates chars between the two bounds, inclusive.
Example: [char_range 'a' 'z'] for all lower case ascii letters.
@since 0.13 *)
val bytes_size : ?gen:char t -> int t -> bytes t
(** Builds a bytes generator from a (non-negative) size generator.
Accepts an optional character generator (the default is {!char}).
@since 0.20 *)
val bytes_size_of : int t -> char t -> bytes t
(** Builds a bytes generator from a (non-negative) size generator
and a character generator.
@since NEXT_RELEASE *)
val bytes : bytes t
(** Builds a bytes generator. Bytes size is generated by {!nat}
and characters are generated by {!char}.
Note: This had an optional [?gen] parameter removed in NEXT_RELEASE.
Use {!bytes_of} instead to pass a [char] generator.
@since 0.20 *)
val bytes_of : char t -> bytes t
(** Builds a bytes generator using the given character generator.
@since 0.20 *)
val bytes_printable : bytes t
(** Generator using the {!printable} character generator.
@since 0.20 *)
val bytes_small : bytes t
(** Builds a bytes generator using the {!char} character generator, length is {!nat_small}
@since 0.20 *)
val bytes_small_of : char t -> bytes t
(** Builds a bytes generator using the given character generator, length is {!nat_small}.
@since 0.20 *)
val string_size : ?gen:char t -> int t -> string t
(** Builds a string generator from a (non-negative) size generator.
Accepts an optional character generator (the default is {!char}). *)
val string_size_of : int t -> char t -> string t
(** Builds a string generator from a (non-negative) size generator
and a character generator.
@since NEXT_RELEASE *)
val string : string t
(** Builds a string generator. String size is generated by {!nat}
and characters are generated by {!char}.
Note: This had an optional [?gen] parameter removed in NEXT_RELEASE.
Use {!string_of} instead to pass a [char] generator. *)
val string_of : char t -> string t
(** Builds a string generator using the given character generator.
@since 0.11 *)
val string_readable : string t
(** Builds a string generator using the {!printable} character generator.
@since 0.11
@deprecated use {!string_printable} *)
[@@deprecated "see string_printable"]
val string_printable : string t
(** Builds a string generator using the {!printable} character generator.
@since 0.18 *)
val small_string : ?gen:char t -> string t
(** Builds a string generator, length is {!nat_small}
Accepts an optional character generator (the default is {!char}).
@deprecated use {!string_small} *)
val string_small : string t
(** Builds a string generator using the {!char} character generator, length is {!nat_small}
@since 0.20 *)
val string_small_of : char t -> string t
(** Builds a string generator using the given character generator, length is {!nat_small}.
@since 0.20 *)
val list_small : 'a t -> 'a list t
(** Generates lists of small size (see {!nat_small}).
@since NEXT_RELEASE *)
val small_list : 'a t -> 'a list t
(** Generates lists of small size (see {!nat_small}).
@since 0.5.3
@deprecated use {!list_small} instead. *)
val flatten_l : 'a t list -> 'a list t
(** Generate a list of elements from individual generators
@since 0.13 *)
val flatten_a : 'a t array -> 'a array t
(** Generate an array of elements from individual generators
@since 0.13 *)
val flatten_opt : 'a t option -> 'a option t
(** Generate an option from an optional generator
@since 0.13 *)
val flatten_res : ('a t, 'e) result -> ('a,'e) result t
(** Generate a result from [Ok g], an error from [Error e]
@since 0.13 *)
val array_small : 'a t -> 'a array t
(** Generates arrays of small size (see {!nat_small}).
@since NEXT_RELEASE *)
val small_array : 'a t -> 'a array t
(** Generates arrays of small size (see {!nat_small}).
@since 0.10
@deprecated use {!array_small} instead. *)
(** {3 Tuple generators}
Create tuple generators by composing individual element generators. For example,
[Gen.(tup3 int char bool)] creates a [(int * char * bool)] triple generator
by composing the [int], [char], and [bool] generators.
*)
val pair : 'a t -> 'b t -> ('a * 'b) t (** Generates pairs. *)
val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t (** Generates triples. *)
val quad : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
(** Generates quadruples.
@since 0.5.1 *)
val tup2 : 'a t -> 'b t -> ('a * 'b) t
(** Combines two generators into a 2-tuple generator. *)
val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
(** Combines three generators into a 3-tuple generator. *)
val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
(** Combines four generators into a 4-tuple generator. *)
val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
(** Combines five generators into a 5-tuple generator. *)
val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
('a * 'b * 'c * 'd * 'e * 'f) t
(** Combines six generators into a 6-tuple generator. *)
val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g) t
(** Combines seven generators into a 7-tuple generator. *)
val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
(** Combines eight generators into an 8-tuple generator. *)
val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
(** Combines nine generators into a 9-tuple generator. *)
val join : 'a t t -> 'a t
(** Collapses a generator of generators to simply a generator.
@since 0.5 *)
val sized : 'a sized -> 'a t
(** Creates a generator from a size-bounded generator by first
generating a size using {!nat} and passing the result to the size-bounded generator. *)
val sized_size : int t -> 'a sized -> 'a t
(** Creates a generator from a size-bounded generator by first
generating a size using the integer generator and passing the result
to the size-bounded generator.
@since 0.5 *)
val fix : (('a -> 'b t) -> 'a -> 'b t) -> 'a -> 'b t
(** Parametrized fixpoint combinator for generating recursive values.
The fixpoint is parametrized over an arbitrary state ('a), and the
fixpoint computation may change the value of this state in the recursive
calls.
In particular, this can be used for size-bounded generators ('a is int).
The passed size-parameter should decrease to ensure termination. *)
(** Example:
{[
type tree = Leaf of int | Node of tree * tree
let leaf x = Leaf x
let node x y = Node (x,y)
let g = QCheck.Gen.(sized @@ fix
(fun self n -> match n with
| 0 -> map leaf nat
| n ->
frequency
[1, map leaf nat;
2, map2 node (self (n/2)) (self (n/2))]
))
]}
*)
val nat_split2 : int -> (int * int) t
(** [nat_split2 n] generates pairs [(n1, n2)] of natural numbers
with [n1 + n2 = n].
This is useful to split sizes to combine sized generators.
@since 0.18
*)
val pos_split2 : int -> (int * int) t
(** [pos_split2 n] generates pairs [(n1, n2)] of strictly positive
(nonzero) natural numbers with [n1 + n2 = n].
@raise Invalid_argument unless [n >= 2].
This is useful to split sizes to combine sized generators.
@since 0.18
*)
val nat_split : size:int -> int -> int array t
(** [nat_split ~size:k n] generates [k]-sized arrays [n1,n2,..nk]
of natural numbers in [[0;n]] with [n1 + n2 + ... + nk = n].
This is useful to split sizes to combine sized generators.
Complexity O(k log k).
@since 0.18
*)
val pos_split : size:int -> int -> int array t
(** [pos_split ~size:k n] generates [k]-sized arrays [n1,n2,..nk]
of strictly positive (non-zero) natural numbers with
[n1 + n2 + ... + nk = n].
This is useful to split sizes to combine sized generators.
Complexity O(k log k).
@raise Invalid_argument unless [0 < k <= n] or [0 = k = n].
@since 0.18
*)
val delay : (unit -> 'a t) -> 'a t
(** Delay execution of some code until the generator is actually called.
This can be used to manually implement recursion or control flow
in a generator.
@since 0.17 *)
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!map}. *)
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!pair}. *)
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!(>>=)}. *)
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!pair}. *)
(** {3 Debug generators}
These functions should not be used in tests: they are provided
for convenience to debug/investigate what values a generator produces.
*)
val generate : ?rand:Random.State.t -> n:int -> 'a t -> 'a list
(** [generate ~n g] generates [n] instances of [g]. *)
val generate1 : ?rand:Random.State.t -> 'a t -> 'a
(** [generate1 g] generates one instance of [g]. *)
end
(** {1 Printing Values} *)
module Print : sig
(** The [Print] module offers combinators for printing generated values. *)
type 'a t = 'a -> string
(** Printer for values of type ['a]. *)
val unit : unit t
(** [unit] is a printer of unit.
@since 0.6 *)
val int : int t (** Integer printer. *)
val int32 : int32 t
(** 32-bit integer printer.
@since 0.24 *)
val int64 : int64 t
(** 64-bit integer printer.
@since 0.24 *)
val bool : bool t (** Boolean printer. *)
val float : float t (** Floating point number printer. *)
val char : char t (** Character printer. *)
val bytes : bytes t
(** Bytes printer.
@since 0.20 *)
val string : string t (** String printer. *)
val option : 'a t -> 'a option t (** Option printer. *)
val result : 'a t -> 'e t -> ('a, 'e) result t
(** Result printer.
@since 0.24 *)
val pair : 'a t -> 'b t -> ('a*'b) t
(** Pair printer. Expects printers for each component. *)
val triple : 'a t -> 'b t -> 'c t -> ('a*'b*'c) t
(** Triple (3-tuple) printer. Expects printers for each component. *)
val quad : 'a t -> 'b t -> 'c t -> 'd t -> ('a*'b*'c*'d) t
(** Quadruple (4-tuple) printer. Expects printers for each component. *)
val list : 'a t -> 'a list t
(** List printer. Expects a printer for the list element type. *)
val array : 'a t -> 'a array t
(** Array printer. Expects a printer for the array entry type. *)
val comap : ('a -> 'b) -> 'b t -> 'a t
(** [comap f p] maps [p], a printer of type ['b], to a printer of type ['a] by
first converting a printed value using [f : 'a -> 'b]. *)
val tup2 : 'a t -> 'b t -> ('a * 'b) t
(** 2-tuple printer. Expects printers for each component. *)
val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
(** 3-tuple printer. Expects printers for each component. *)
val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
(** 4-tuple printer. Expects printers for each component. *)
val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
(** 5-tuple printer. Expects printers for each component. *)
val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
('a * 'b * 'c * 'd * 'e * 'f) t
(** 6-tuple printer. Expects printers for each component. *)
val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g) t
(** 7-tuple printer. Expects printers for each component. *)
val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
(** 8-tuple printer. Expects printers for each component. *)
val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
(** 9-tuple printer. Expects printers for each component. *)
end
(** {1 Shrinking Values}
Shrinking is used to reduce the size of a counter-example. It tries
to make the counter-example smaller, e.g., by decreasing an integer,
or removing elements of a list, until the property to test holds again;
it then returns the smallest value that still made the test fail.
Shrinking is defined as a type {!Shrink.t} that takes an argument to shrink
and produces an iterator of type {!Iter.t} of shrinking candidates.
⚠️ In order to function well, a shrinker must:
- never return its argument as a shrinking candidate, and
- return shrinking candidates which are smaller by some termination measure
([list] length, tree depth, number of bits, ...)
Failure to do so, may result in an infinite shrinker loop.
*)
(** {2 Iterators} *)
module Iter : sig
(** [Iter] is compatible with the library "sequence". An iterator [i] is simply
a function that accepts another function [f] (of type ['a -> unit])
and calls [f] on a sequence of elements [f x1; f x2; ...; f xn]. *)
type 'a t = ('a -> unit) -> unit
(** The type of iterators, underlying {!Shrink.t}. *)
val empty : 'a t
(** The empty iterator *)
val return : 'a -> 'a t
(** The constant iterator *)
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
(** Applicative operator for iterators, combining a function iterator and
an argument iterator into a result generator. *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Monadic bind operator for iterators.
[i >>= f] passes each element of [i] to [f], iterating over each element
of [f]'s resulting iterators. *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** [map f i] returns an iterator of elements from [i], each of which have
been applied to [f]. *)
val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** [map f i j] returns an iterator of elements from [i] and [j], which have
been applied to [f]. *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
(** An infix synonym for {!map}. *)
val append : 'a t -> 'a t -> 'a t
(** [append a b] first iterates over [a]'s elements and then over [b]'s. *)
val (<+>) : 'a t -> 'a t -> 'a t
(** Synonym for {!append}. *)
val of_list : 'a list -> 'a t
(** [of_list xs] builds an iterator over the list elements of [xs]. *)
val of_array : 'a array -> 'a t
(** [of_array xs] builds an iterator over the array elements of [xs]. *)
val pair : 'a t -> 'b t -> ('a * 'b) t
(** [pair a b] iterates over pairs [(x,y)] with [x] coming from [a] and
[y] coming from [b]. *)
val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
(** [triple a b c] iterates over triples [(x,y,z)] with [x] coming from [a],
[y] coming from [b], and [z] coming from [c]. *)
val quad : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
(** [quad a b c d] iterates over quadruples [(x,y,z,w)] with [x] coming from [a],
[y] coming from [b], [z] coming from [c], and [w] coming from [d]. *)
val find : ('a -> bool) -> 'a t -> 'a option
(** [find p i] maps over the iterator [i], returning [Some _] when the
predicate [p] is [true] and [None] otherwise. *)
val filter : ('a -> bool) -> 'a t -> 'a t
(** [filter p i] returns an iterator of elements from [i] satisfying [p]. *)
val append_l : 'a t list -> 'a t
(** Appends a list of iterators into a single iterator.
@since 0.8 *)
val flatten : 'a t t -> 'a t
(** Flattens an iterator of iterators into a single iterator.
@since 0.8 *)
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!map}. *)
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!pair}. *)
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!(>>=)}. *)
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
(** {{: https://ocaml.org/manual/bindingops.html} Binding operator} alias for {!pair}. *)
end
(** {2 Shrinkers} *)
module Shrink : sig
(** The [Shrink] module contains combinators to build up composite shrinkers
for user-defined types
⚠️ Warning: [QCheck]'s shrinking phase may loop infinitely if
- the shrinker returns its own argument as a shrinking candidate, or
- fails to return a strictly smaller shrinking candidate by some termination measure
(e.g., a [list] permutation may lead to an infinite shrinking cycle).
*)
type 'a t = 'a -> 'a Iter.t
(** Given a counter-example, return an iterator on smaller versions
of the counter-example. *)
val nil : 'a t
(** No shrink *)
val unit : unit t
(** unit shrinker. Does not produce any shrinking candidates.
@since 0.6 *)
val bool : bool t
(** bool shrinker. Shrinks towards [false].
@since 0.23 *)
val char : char t
(** char shrinker. Shrinks towards ['a'].
@since 0.6 *)
val char_numeral : char t
(** char digit shrinker. Shrinks towards ['0'].
@since 0.19 *)
val char_printable : char t