Codebase list ocaml-qcheck / upstream/0.18.1+git20220309.1.e92837e
Import upstream version 0.18.1+git20220309.1.e92837e Debian Janitor 2 years ago
40 changed file(s) with 3969 addition(s) and 191 deletion(s). Raw diff Collapse all Expand all
00 # Changes
1
2 ## 0.19
3
4 - add optional `debug_shrink` parameters in alcotest interface and
5 expose default `debug_shrinking_choices` in test runners
6
7 - add missing `?handler` parameter to `Test.check_cell_exn`
8
9 - remove `--no-buffer` option on `dune runtest` to avoid garbling the
10 test output
11
12 - add an option `retries` parameter `Test.make` et al. for checking a
13 property repeatedly while shrinking.
14 This can be useful when testing non-deterministic code.
15 [#212](https://github.com/c-cube/qcheck/pull/212)
16
17 - add tup2 to tup9 for generators
18
19 - documentation updates:
20 - clarify upper bound inclusion in `Gen.int_bound` and `Gen.int_range`
21 - clarify `printable_char` and `Gen.printable` distributions
22 - add missing `string_gen_of_size` and `small_printable_string` documentation
23 - document `QCheck_alcotest.to_alcotest`
24 - fix documented size distribution for `arbitrary` generators
25 `string_gen`, `string`, `printable_string`, `numeral_string`, `list`, and `array`
126
227 ## 0.18.1
328
44 @dune build @install
55
66 test:
7 @dune runtest --no-buffer --force
7 @dune runtest --force
88
99 clean:
1010 @dune clean
4747 QCheck.(make gen_tree)
4848 (fun tree -> rev_tree (rev_tree tree) = tree)
4949
50 let debug_shrink =
51 QCheck.Test.make ~count:10
52 ~name:"debug_shrink"
53 (* we use a very constrained test to have a smaller shrinking tree *)
54 QCheck.(pair (1 -- 3) (1 -- 3))
55 (fun (a, b) -> a = b);;
56
5057 let () =
5158 Printexc.record_backtrace true;
5259 let module A = Alcotest in
5461 List.map QCheck_alcotest.to_alcotest
5562 [ passing; failing; error; simple_qcheck; passing_tree_rev ]
5663 in
57 A.run "my test" [
58 "suite", suite
59 ]
64 A.run ~show_errors:true "my test" [
65 "suite", suite;
66 "shrinking", [
67 QCheck_alcotest.to_alcotest ~verbose:true ~debug_shrink:(Some stdout) debug_shrink
68 ];
69 ];
00 qcheck random seed: 1234
11 Testing `my test'.
2 [OK] suite 0 list_rev_is_involutive.
3 > [FAIL] suite 1 fail_sort_id.
4 [FAIL] suite 2 error_raise_exn.
5 [FAIL] suite 3 fail_check_err_message.
6 [OK] suite 4 tree_rev_is_involutive.
2 [OK] suite 0 list_rev_is_involutive.
3 [FAIL] suite 1 fail_sort_id.
4 [FAIL] suite 2 error_raise_exn.
5 [FAIL] suite 3 fail_check_err_message.
6 [OK] suite 4 tree_rev_is_involutive.
7 [FAIL] shrinking 0 debug_shrink.
78 ┌──────────────────────────────────────────────────────────────────────────────┐
8 │ [FAIL] suite 1 fail_sort_id. │
9 │ [FAIL] suite 1 fail_sort_id. │
910 └──────────────────────────────────────────────────────────────────────────────┘
1011 test `fail_sort_id` failed on ≥ 1 cases: [1; 0] (after 20 shrink steps)
1112 [exception] test `fail_sort_id` failed on ≥ 1 cases: [1; 0] (after 20 shrink steps)
1213 ──────────────────────────────────────────────────────────────────────────────
13 3 failures! 5 tests run.
14 ┌──────────────────────────────────────────────────────────────────────────────┐
15 │ [FAIL] suite 2 error_raise_exn. │
16 └──────────────────────────────────────────────────────────────────────────────┘
17 test `error_raise_exn`
18 raised exception `Error`
19 on `0 (after 63 shrink steps)`
20 [exception] test `error_raise_exn`
21 raised exception `Error`
22 on `0 (after 63 shrink steps)`
23 ──────────────────────────────────────────────────────────────────────────────
24 ┌──────────────────────────────────────────────────────────────────────────────┐
25 │ [FAIL] suite 3 fail_check_err_message. │
26 └──────────────────────────────────────────────────────────────────────────────┘
27 test `fail_check_err_message` failed on ≥ 1 cases:
28 0 (after 7 shrink steps)
29 this
30 will
31 always
32 fail
33 [exception] test `fail_check_err_message` failed on ≥ 1 cases:
34 0 (after 7 shrink steps)
35 this
36 will
37 always
38 fail
39 ──────────────────────────────────────────────────────────────────────────────
40 ┌──────────────────────────────────────────────────────────────────────────────┐
41 │ [FAIL] shrinking 0 debug_shrink. │
42 └──────────────────────────────────────────────────────────────────────────────┘
43 ~~~ Shrink ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44 Test debug_shrink successfully shrunk counter example (step 0) to:
45 (3, 1)
46 ~~~ Shrink ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 Test debug_shrink successfully shrunk counter example (step 1) to:
48 (2, 1)
49 ~~~ Shrink ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50 Test debug_shrink successfully shrunk counter example (step 2) to:
51 (2, 0)
52 ~~~ Shrink ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 Test debug_shrink successfully shrunk counter example (step 3) to:
54 (1, 0)
55 law debug_shrink: 2 relevant cases (2 total)
56 test `debug_shrink` failed on ≥ 1 cases: (1, 0) (after 3 shrink steps)
57 [exception] test `debug_shrink` failed on ≥ 1 cases: (1, 0) (after 3 shrink steps)
58 ──────────────────────────────────────────────────────────────────────────────
59 4 failures! 6 tests run.
1111 | grep -v 'Raised at ' \
1212 | grep -v 'Called from ' \
1313 | sed 's/! in .*s\./!/' \
14 | sed 's/`.*.Error`/`Error`/g' \
1415 | sed 's/[ \t]*$//g' \
1516 | tr -s "\n"
1617 exit $CODE
0 opam-version: "2.0"
1 name: "ppx_deriving_qcheck"
2 version: "0.2.0"
3 license: "BSD-2-Clause"
4 synopsis: "PPX Deriver for QCheck"
5
6 maintainer: "valentin.chb@gmail.com"
7 author: [ "the qcheck contributors" ]
8
9 depends: [
10 "dune" {>= "2.8.0"}
11 "ocaml" {>= "4.08.0"}
12 "qcheck" {>= "0.17"}
13 "ppxlib" {>= "0.22.0"}
14 "ppx_deriving" {>= "5.2.1"}
15 "odoc" {with-doc}
16 "alcotest" {with-test & >= "1.4.0" }
17 ]
18
19 build: [
20 ["dune" "build" "-p" name "-j" jobs]
21 ["dune" "build" "@doc" "-p" name "-j" jobs] {with-doc}
22 ["dune" "runtest" "-p" name "-j" jobs] {with-test}
23 ]
24
25 homepage: "https://github.com/c-cube/qcheck/"
26 bug-reports: "https://github.com/c-cube/qcheck/-/issues"
27 dev-repo: "git+https://github.com/vch9/ppx_deriving_qcheck.git"
44 license: "BSD-2-Clause"
55 synopsis: "Alcotest backend for qcheck"
66 doc: ["http://c-cube.github.io/qcheck/"]
7 version: "0.18.1"
7 version: "0.18"
88 tags: [
99 "test"
1010 "quickcheck"
44 license: "BSD-2-Clause"
55 synopsis: "Core qcheck library"
66 doc: ["http://c-cube.github.io/qcheck/"]
7 version: "0.18.1"
7 version: "0.18"
88 tags: [
99 "test"
1010 "property"
44 homepage: "https://github.com/c-cube/qcheck/"
55 doc: ["http://c-cube.github.io/qcheck/"]
66 synopsis: "OUnit backend for qcheck"
7 version: "0.18.1"
7 version: "0.18"
88 tags: [
99 "qcheck"
1010 "quickcheck"
44 homepage: "https://github.com/c-cube/qcheck/"
55 license: "BSD-2-Clause"
66 doc: ["http://c-cube.github.io/qcheck/"]
7 version: "0.18.1"
7 version: "0.18"
88 tags: [
99 "test"
1010 "property"
3232 )
3333
3434 let to_alcotest
35 ?(verbose=Lazy.force verbose_) ?(long=Lazy.force long_) ?(rand=default_rand())
35 ?(colors=false) ?(verbose=Lazy.force verbose_) ?(long=Lazy.force long_)
36 ?(debug_shrink = None) ?debug_shrink_list ?(rand=default_rand())
3637 (t:T.t) =
3738 let T.Test cell = t in
39 let handler name cell r =
40 match r, debug_shrink with
41 | QCheck2.Test.Shrunk (step, x), Some out ->
42 let go = match debug_shrink_list with
43 | None -> true
44 | Some test_list -> List.mem name test_list in
45 if not go then ()
46 else
47 QCheck_base_runner.debug_shrinking_choices
48 ~colors ~out ~name cell ~step x
49 | _ ->
50 ()
51 in
3852 let print = Raw.print_std in
3953 let run() =
40 T.check_cell_exn cell
41 ~long ~rand ~call:(Raw.callback ~colors:false ~verbose ~print_res:true ~print)
54 let call = Raw.callback ~colors ~verbose ~print_res:true ~print in
55 T.check_cell_exn
56 ~long ~call ~handler ~rand
57 cell
4258 in
4359 let name = T.get_name cell in
44 name, `Slow, run
60 ((name, `Slow, run) : unit Alcotest.test_case)
1111 *)
1212
1313 val to_alcotest :
14 ?verbose:bool -> ?long:bool -> ?rand:Random.State.t ->
14 ?colors:bool -> ?verbose:bool -> ?long:bool ->
15 ?debug_shrink:(out_channel option) ->
16 ?debug_shrink_list:(string list) ->
17 ?rand:Random.State.t ->
1518 QCheck2.Test.t -> unit Alcotest.test_case
16 (** Convert a qcheck test into an alcotest test
17 @param verbose used to print information on stdout (default: [verbose()])
18 @param rand the random generator to use (default: [random_state ()])
19 (** Convert a qcheck test into an alcotest test.
20
21 In addition to the environment variables mentioned above, you can control
22 the behavior of QCheck tests using optional parameters that behave in the
23 same way as the parameters of {!QCheck_base_runner.run_tests}.
24
1925 @since 0.9
26 @since 0.9 parameters [verbose], [long], [rand]
27 @since NEXT_VERSION parameters [colors], [debug_shrink], [debug_shrink_list]
2028 *)
3939
4040 let _opt_map_4 ~f a b c d = match a, b, c, d with
4141 | Some x, Some y, Some z, Some w -> Some (f x y z w)
42 | _ -> None
43
44 let _opt_map_5 ~f a b c d e = match a, b, c, d, e with
45 | Some x, Some y, Some z, Some u, Some v -> Some (f x y z u v)
46 | _ -> None
47
48 let _opt_map_6 ~f a b c d e g = match a, b, c, d, e, g with
49 | Some a, Some b, Some c, Some d, Some e, Some g -> Some (f a b c d e g)
50 | _ -> None
51
52 let _opt_map_7 ~f a b c d e g h = match a, b, c, d, e, g, h with
53 | Some a, Some b, Some c, Some d, Some e, Some g, Some h -> Some (f a b c d e g h)
54 | _ -> None
55
56 let _opt_map_8 ~f a b c d e g h i = match a, b, c, d, e, g, h, i with
57 | Some a, Some b, Some c, Some d, Some e, Some g, Some h, Some i ->
58 Some (f a b c d e g h i)
59 | _ -> None
60
61 let _opt_map_9 ~f a b c d e g h i j = match a, b, c, d, e, g, h, i, j with
62 | Some a, Some b, Some c, Some d, Some e, Some g, Some h, Some i, Some j ->
63 Some (f a b c d e g h i j)
4264 | _ -> None
4365
4466 let _opt_sum a b = match a, b with
282304
283305 let char st = char_of_int (RS.int st 256)
284306
307 let tup2 = pair
308
309 let tup3 = triple
310
311 let tup4 = quad
312
313 let tup5 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) : ('a * 'b * 'c * 'd * 'e) t =
314 (fun a b c d e -> (a, b, c, d, e)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5
315
316 let tup6 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) : ('a * 'b * 'c * 'd * 'e * 'f) t =
317 (fun a b c d e f -> (a, b, c, d, e, f)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6
318
319 let tup7 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g) t =
320 (fun a b c d e f g -> (a, b, c, d, e, f, g)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7
321
322 let tup8 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) (g8 : 'h t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t =
323 (fun a b c d e f g h -> (a, b, c, d, e, f, g, h)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7 <*> g8
324
325 let tup9 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) (g8 : 'h t) (g9 : 'i t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t =
326 (fun a b c d e f g h i -> (a, b, c, d, e, f, g, h, i)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7 <*> g8 <*> g9
327
285328 let printable_chars =
286329 let l = 126-32+1 in
287330 let s = Bytes.create l in
402445 let triple a b c (x,y,z) = Printf.sprintf "(%s, %s, %s)" (a x) (b y) (c z)
403446 let quad a b c d (x,y,z,w) =
404447 Printf.sprintf "(%s, %s, %s, %s)" (a x) (b y) (c z) (d w)
448
449 let default = fun _ -> "<no printer>"
450
451 let tup2 p_a p_b (a, b) =
452 Printf.sprintf "(%s, %s)" (p_a a) (p_b b)
453
454 let tup2_opt p_a p_b (a, b) =
455 let p_a = Option.value ~default p_a in
456 let p_b = Option.value ~default p_b in
457 tup2 p_a p_b (a, b)
458
459 let tup3 p_a p_b (p_c) (a, b, c) =
460 Printf.sprintf "(%s, %s, %s)" (p_a a) (p_b b) (p_c c)
461
462 let tup3_opt p_a p_b p_c (a, b, c) =
463 let p_a = Option.value ~default p_a in
464 let p_b = Option.value ~default p_b in
465 let p_c = Option.value ~default p_c in
466 tup3 p_a p_b p_c (a, b, c)
467
468 let tup4 p_a p_b p_c p_d (a, b, c, d) =
469 Printf.sprintf "(%s, %s, %s, %s)"
470 (p_a a) (p_b b)
471 (p_c c) (p_d d)
472
473 let tup4_opt p_a p_b p_c p_d (a, b, c, d) =
474 let p_a = Option.value ~default p_a in
475 let p_b = Option.value ~default p_b in
476 let p_c = Option.value ~default p_c in
477 let p_d = Option.value ~default p_d in
478 tup4 p_a p_b p_c p_d (a, b, c, d)
479
480 let tup5 p_a p_b p_c p_d p_e (a, b, c, d, e) =
481 Printf.sprintf "(%s, %s, %s, %s, %s)"
482 (p_a a) (p_b b)
483 (p_c c) (p_d d)
484 (p_e e)
485
486 let tup5_opt p_a p_b p_c p_d p_e (a, b, c, d, e) =
487 let p_a = Option.value ~default p_a in
488 let p_b = Option.value ~default p_b in
489 let p_c = Option.value ~default p_c in
490 let p_d = Option.value ~default p_d in
491 let p_e = Option.value ~default p_e in
492 tup5 p_a p_b p_c p_d p_e (a, b, c, d, e)
493
494 let tup6 p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f) =
495 Printf.sprintf "(%s, %s, %s, %s, %s, %s)"
496 (p_a a) (p_b b)
497 (p_c c) (p_d d)
498 (p_e e) (p_f f)
499
500 let tup6_opt p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f) =
501 let p_a = Option.value ~default p_a in
502 let p_b = Option.value ~default p_b in
503 let p_c = Option.value ~default p_c in
504 let p_d = Option.value ~default p_d in
505 let p_e = Option.value ~default p_e in
506 let p_f = Option.value ~default p_f in
507 tup6 p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f)
508
509 let tup7 p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g) =
510 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s)"
511 (p_a a) (p_b b)
512 (p_c c) (p_d d)
513 (p_e e) (p_f f)
514 (p_g g)
515
516 let tup7_opt p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g) =
517 let p_a = Option.value ~default p_a in
518 let p_b = Option.value ~default p_b in
519 let p_c = Option.value ~default p_c in
520 let p_d = Option.value ~default p_d in
521 let p_e = Option.value ~default p_e in
522 let p_f = Option.value ~default p_f in
523 let p_g = Option.value ~default p_g in
524 tup7 p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g)
525
526 let tup8 p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h) =
527 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s, %s)"
528 (p_a a) (p_b b)
529 (p_c c) (p_d d)
530 (p_e e) (p_f f)
531 (p_g g) (p_h h)
532
533 let tup8_opt p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h) =
534 let p_a = Option.value ~default p_a in
535 let p_b = Option.value ~default p_b in
536 let p_c = Option.value ~default p_c in
537 let p_d = Option.value ~default p_d in
538 let p_e = Option.value ~default p_e in
539 let p_f = Option.value ~default p_f in
540 let p_g = Option.value ~default p_g in
541 let p_h = Option.value ~default p_h in
542 tup8 p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h)
543
544 let tup9 p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i) =
545 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s, %s, %s)"
546 (p_a a) (p_b b)
547 (p_c c) (p_d d)
548 (p_e e) (p_f f)
549 (p_g g) (p_h h)
550 (p_i i)
551
552 let tup9_opt p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i) =
553 let p_a = Option.value ~default p_a in
554 let p_b = Option.value ~default p_b in
555 let p_c = Option.value ~default p_c in
556 let p_d = Option.value ~default p_d in
557 let p_e = Option.value ~default p_e in
558 let p_f = Option.value ~default p_f in
559 let p_g = Option.value ~default p_g in
560 let p_h = Option.value ~default p_h in
561 let p_i = Option.value ~default p_i in
562 tup9 p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i)
405563
406564 let list pp l =
407565 let b = Buffer.create 25 in
612770 b y (fun y' -> yield (x,y',z,w));
613771 c z (fun z' -> yield (x,y,z',w));
614772 d w (fun w' -> yield (x,y,z,w'))
773
774 let default = nil
775
776 let tup2 = pair
777
778 let tup2_opt a b =
779 let a = Option.value ~default a in
780 let b = Option.value ~default b in
781 tup2 a b
782
783 let tup3 = triple
784
785 let tup3_opt a b c =
786 let a = Option.value ~default a in
787 let b = Option.value ~default b in
788 let c = Option.value ~default c in
789 tup3 a b c
790
791 let tup4 = quad
792
793 let tup4_opt a b c d =
794 let a = Option.value ~default a in
795 let b = Option.value ~default b in
796 let c = Option.value ~default c in
797 let d = Option.value ~default d in
798 tup4 a b c d
799
800 let tup5 a b c d e (a', b', c', d', e') yield =
801 a a' (fun x -> yield (x,b',c',d',e'));
802 b b' (fun x -> yield (a',x,c',d',e'));
803 c c' (fun x -> yield (a',b',x,d',e'));
804 d d' (fun x -> yield (a',b',c',x,e'));
805 e e' (fun x -> yield (a',b',c',d',x))
806
807 let tup5_opt a b c d e =
808 let a = Option.value ~default a in
809 let b = Option.value ~default b in
810 let c = Option.value ~default c in
811 let d = Option.value ~default d in
812 let e = Option.value ~default e in
813 tup5 a b c d e
814
815 let tup6 a b c d e f (a', b', c', d', e', f') yield =
816 a a' (fun x -> yield (x,b',c',d',e',f'));
817 b b' (fun x -> yield (a',x,c',d',e',f'));
818 c c' (fun x -> yield (a',b',x,d',e',f'));
819 d d' (fun x -> yield (a',b',c',x,e',f'));
820 e e' (fun x -> yield (a',b',c',d',x,f'));
821 f f' (fun x -> yield (a',b',c',d',e',x))
822
823 let tup6_opt a b c d e f =
824 let a = Option.value ~default a in
825 let b = Option.value ~default b in
826 let c = Option.value ~default c in
827 let d = Option.value ~default d in
828 let e = Option.value ~default e in
829 let f = Option.value ~default f in
830 tup6 a b c d e f
831
832 let tup7 a b c d e f g (a', b', c', d', e', f', g') yield =
833 a a' (fun x -> yield (x,b',c',d',e',f',g'));
834 b b' (fun x -> yield (a',x,c',d',e',f',g'));
835 c c' (fun x -> yield (a',b',x,d',e',f',g'));
836 d d' (fun x -> yield (a',b',c',x,e',f',g'));
837 e e' (fun x -> yield (a',b',c',d',x,f',g'));
838 f f' (fun x -> yield (a',b',c',d',e',x,g'));
839 g g' (fun x -> yield (a',b',c',d',e',f',x))
840
841 let tup7_opt a b c d e f g =
842 let a = Option.value ~default a in
843 let b = Option.value ~default b in
844 let c = Option.value ~default c in
845 let d = Option.value ~default d in
846 let e = Option.value ~default e in
847 let f = Option.value ~default f in
848 let g = Option.value ~default g in
849 tup7 a b c d e f g
850
851 let tup8 a b c d e f g h (a', b', c', d', e', f', g', h') yield =
852 a a' (fun x -> yield (x,b',c',d',e',f',g',h'));
853 b b' (fun x -> yield (a',x,c',d',e',f',g',h'));
854 c c' (fun x -> yield (a',b',x,d',e',f',g',h'));
855 d d' (fun x -> yield (a',b',c',x,e',f',g',h'));
856 e e' (fun x -> yield (a',b',c',d',x,f',g',h'));
857 f f' (fun x -> yield (a',b',c',d',e',x,g',h'));
858 g g' (fun x -> yield (a',b',c',d',e',f',x,h'));
859 h h' (fun x -> yield (a',b',c',d',e',f',g',x))
860
861 let tup8_opt a b c d e f g h =
862 let a = Option.value ~default a in
863 let b = Option.value ~default b in
864 let c = Option.value ~default c in
865 let d = Option.value ~default d in
866 let e = Option.value ~default e in
867 let f = Option.value ~default f in
868 let g = Option.value ~default g in
869 let h = Option.value ~default h in
870 tup8 a b c d e f g h
871
872 let tup9 a b c d e f g h i (a', b', c', d', e', f', g', h', i') yield =
873 a a' (fun x -> yield (x,b',c',d',e',f',g',h',i'));
874 b b' (fun x -> yield (a',x,c',d',e',f',g',h',i'));
875 c c' (fun x -> yield (a',b',x,d',e',f',g',h',i'));
876 d d' (fun x -> yield (a',b',c',x,e',f',g',h',i'));
877 e e' (fun x -> yield (a',b',c',d',x,f',g',h',i'));
878 f f' (fun x -> yield (a',b',c',d',e',x,g',h',i'));
879 g g' (fun x -> yield (a',b',c',d',e',f',x,h',i'));
880 h h' (fun x -> yield (a',b',c',d',e',f',g',x,i'));
881 i i' (fun x -> yield (a',b',c',d',e',f',g',h',x))
882
883 let tup9_opt a b c d e f g h i =
884 let a = Option.value ~default a in
885 let b = Option.value ~default b in
886 let c = Option.value ~default c in
887 let d = Option.value ~default d in
888 let e = Option.value ~default e in
889 let f = Option.value ~default f in
890 let g = Option.value ~default g in
891 let h = Option.value ~default h in
892 let i = Option.value ~default i in
893 tup9 a b c d e f g h i
615894 end
616895
617896 (** {2 Observe Values} *)
8741153 (_opt_or c.shrink Shrink.nil)
8751154 (_opt_or d.shrink Shrink.nil))
8761155 (Gen.quad a.gen b.gen c.gen d.gen)
1156
1157 let tup2 a b=
1158 make
1159 ?small:(_opt_map_2 ~f:(fun a b (a', b') -> a a'+b b') a.small b.small)
1160 ~print:(Print.tup2_opt a.print b.print)
1161 ~shrink:(Shrink.pair (_opt_or a.shrink Shrink.nil) (_opt_or b.shrink Shrink.nil))
1162 (Gen.tup2 a.gen b.gen)
1163
1164 let tup3 a b c =
1165 make
1166 ?small:(_opt_map_3 ~f:(fun a b c (a', b', c') ->
1167 a a'+b b'+c c') a.small b.small c.small)
1168 ~print:(Print.tup3_opt a.print b.print c.print)
1169 ~shrink:(Shrink.tup3_opt a.shrink b.shrink c.shrink)
1170 (Gen.tup3 a.gen b.gen c.gen)
1171
1172 let tup4 a b c d =
1173 make
1174 ?small:(_opt_map_4 ~f:(fun a b c d (a', b', c', d') ->
1175 a a'+b b'+c c'+d d') a.small b.small c.small d.small)
1176 ~print:(Print.tup4_opt a.print b.print c.print d.print)
1177 ~shrink:(Shrink.tup4_opt a.shrink b.shrink c.shrink d.shrink)
1178 (Gen.tup4 a.gen b.gen c.gen d.gen)
1179
1180 let tup5 a b c d e =
1181 make
1182 ?small:(_opt_map_5 ~f:(fun a b c d e (a', b', c', d', e') ->
1183 a a'+b b'+c c'+d d'+e e') a.small b.small c.small d.small e.small)
1184 ~print:(Print.tup5_opt a.print b.print c.print d.print e.print)
1185 ~shrink:(Shrink.tup5_opt a.shrink b.shrink c.shrink d.shrink e.shrink)
1186 (Gen.tup5 a.gen b.gen c.gen d.gen e.gen)
1187
1188 let tup6 a b c d e f =
1189 make
1190 ?small:(_opt_map_6 ~f:(fun a b c d e f (a', b', c', d', e', f') ->
1191 a a'+b b'+c c'+d d'+e e'+f f') a.small b.small c.small d.small e.small f.small)
1192 ~print:(Print.tup6_opt a.print b.print c.print d.print e.print f.print)
1193 ~shrink:(Shrink.tup6_opt a.shrink b.shrink c.shrink d.shrink e.shrink f.shrink)
1194 (Gen.tup6 a.gen b.gen c.gen d.gen e.gen f.gen)
1195
1196 let tup7 a b c d e f g =
1197 make
1198 ?small:(_opt_map_7 ~f:(fun a b c d e f g (a', b', c', d', e', f', g') ->
1199 a a'+b b'+c c'+d d'+e e'+f f'+g g')
1200 a.small b.small c.small d.small e.small f.small g.small)
1201 ~print:(Print.tup7_opt
1202 a.print b.print c.print d.print e.print f.print g.print)
1203 ~shrink:(Shrink.tup7_opt
1204 a.shrink b.shrink c.shrink d.shrink e.shrink f.shrink g.shrink)
1205 (Gen.tup7 a.gen b.gen c.gen d.gen e.gen f.gen g.gen)
1206
1207 let tup8 a b c d e f g h =
1208 make
1209 ?small:(_opt_map_8 ~f:(fun a b c d e f g h (a', b', c', d', e', f', g', h') ->
1210 a a'+b b'+c c'+d d'+e e'+f f'+g g'+h h')
1211 a.small b.small c.small d.small e.small f.small g.small h.small)
1212 ~print:(Print.tup8_opt
1213 a.print b.print c.print d.print e.print f.print g.print h.print)
1214 ~shrink:(Shrink.tup8_opt
1215 a.shrink b.shrink c.shrink d.shrink e.shrink f.shrink g.shrink h.shrink)
1216 (Gen.tup8 a.gen b.gen c.gen d.gen e.gen f.gen g.gen h.gen)
1217
1218 let tup9 a b c d e f g h i =
1219 make
1220 ?small:(_opt_map_9 ~f:(fun a b c d e f g h i (a', b', c', d', e', f', g', h', i') ->
1221 a a'+b b'+c c'+d d'+e e'+f f'+g g'+h h'+i i')
1222 a.small b.small c.small d.small e.small f.small g.small h.small i.small)
1223 ~print:(Print.tup9_opt
1224 a.print b.print c.print d.print e.print f.print g.print h.print i.print)
1225 ~shrink:(Shrink.tup9_opt
1226 a.shrink b.shrink c.shrink d.shrink e.shrink f.shrink g.shrink h.shrink i.shrink)
1227 (Gen.tup9 a.gen b.gen c.gen d.gen e.gen f.gen g.gen h.gen i.gen)
8771228
8781229 let option ?ratio a =
8791230 let g = Gen.opt ?ratio a.gen
13281679
13291680 let make_cell ?if_assumptions_fail
13301681 ?count ?long_factor ?max_gen
1331 ?max_fail ?small:_removed_in_qcheck_2 ?name arb law
1682 ?max_fail ?small:_removed_in_qcheck_2 ?retries ?name arb law
13321683 =
13331684 let {gen; shrink; print; collect; stats; _} = arb in
1334 QCheck2.Test.make_cell_from_QCheck1 ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?name ~gen ?shrink ?print ?collect ~stats law
1335
1336 let make ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?small ?name arb law =
1337 QCheck2.Test.Test (make_cell ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?small ?name arb law)
1685 QCheck2.Test.make_cell_from_QCheck1 ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?retries ?name ~gen ?shrink ?print ?collect ~stats law
1686
1687 let make ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?small ?retries ?name arb law =
1688 QCheck2.Test.Test (make_cell ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?small ?retries ?name arb law)
13381689
13391690 let fail_report = QCheck2.Test.fail_report
13401691
292292 @since 0.5.2 *)
293293
294294 val int_bound : int -> int t
295 (** Uniform integer generator producing integers within [0... bound].
295 (** Uniform integer generator producing integers between [0] and [bound]
296 (inclusive).
296297 For [bound < 2^{30} - 1] uses [Random.State.int] for integer generation.
297298 @raise Invalid_argument if the argument is negative. *)
298299
299300 val int_range : int -> int -> int t
300 (** Uniform integer generator producing integers within [low,high].
301 (** Uniform integer generator producing integers within [low,high] (inclusive).
301302 @raise Invalid_argument if [low > high]. *)
302303
303304 val graft_corners : 'a t -> 'a list -> unit -> 'a t
352353 (** Generates quadruples.
353354 @since 0.5.1 *)
354355
356 (** {3 Tuple of generators} *)
357
358 (** {4 Shrinks on [gen1], then [gen2], then ... } *)
359
360 val tup2 : 'a t -> 'b t -> ('a * 'b) t
361
362 val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
363
364 val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
365
366 val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
367
368 val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
369 ('a * 'b * 'c * 'd * 'e * 'f) t
370
371 val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
372 ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
373
374 val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
375 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
376
377 val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
378 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
379
355380 val char : char t
356381 (** Generates characters upto character code 255. *)
357382
358 val printable : char t (** Generates printable characters. *)
383 val printable : char t (** Generates printable ascii characters in the range 32 to 127 *)
359384
360385 val numeral : char t (** Generates numeral characters. *)
361386
566591 val comap : ('a -> 'b) -> 'b t -> 'a t
567592 (** [comap f p] maps [p], a printer of type ['b], to a printer of type ['a] by
568593 first converting a printed value using [f : 'a -> 'b]. *)
594
595 val tup2 : 'a t -> 'b t -> ('a * 'b) t
596 (** 2-tuple printer. Expects printers for each component. *)
597
598 val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
599 (** 3-tuple printer. Expects printers for each component. *)
600
601 val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
602 (** 4-tuple printer. Expects printers for each component. *)
603
604 val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
605 (** 5-tuple printer. Expects printers for each component. *)
606
607 val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
608 ('a * 'b * 'c * 'd * 'e * 'f) t
609 (** 6-tuple printer. Expects printers for each component. *)
610
611 val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
612 ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
613 (** 7-tuple printer. Expects printers for each component. *)
614
615 val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
616 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
617 (** 8-tuple printer. Expects printers for each component. *)
618
619 val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
620 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
621 (** 9-tuple printer. Expects printers for each component. *)
569622 end
570623
571624 (** {2 Iterators}
681734
682735 val quad : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
683736 (** Similar to {!pair} *)
737
738 val tup2 : 'a t -> 'b t -> ('a * 'b) t
739 (** [tup2 a b] uses [a] to shrink the first element of tuples,
740 then tries to shrink the second element using [b].
741 It is often better, when generating tuples, to put the "simplest"
742 element first (atomic type rather than list, etc.) because it will be
743 shrunk earlier. In particular, putting functions last might help. *)
744
745 val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
746 (** Similar to {!tup2} *)
747
748 val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
749 (** Similar to {!tup2} *)
750
751 val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
752 (** Similar to {!tup2} *)
753
754 val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
755 ('a * 'b * 'c * 'd * 'e * 'f) t
756 (** Similar to {!tup2} *)
757
758 val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
759 ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
760 (** Similar to {!tup2} *)
761
762 val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
763 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
764 (** Similar to {!tup2} *)
765
766 val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
767 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
768 (** Similar to {!tup2} *)
684769 end
685770
686771 (** {2 Observe Values} *)
903988 val make_cell :
904989 ?if_assumptions_fail:([`Fatal | `Warning] * float) ->
905990 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int ->
906 ?small:('a -> int) -> ?name:string -> 'a arbitrary -> ('a -> bool) ->
907 'a cell
991 ?small:('a -> int) -> ?retries:int -> ?name:string ->
992 'a arbitrary -> ('a -> bool) -> 'a cell
908993 (** [make_cell arb prop] builds a test that checks property [prop] on instances
909994 of the generator [arb].
910995 @param name the name of the test.
911996 @param count number of test cases to run, counting only
912997 the test cases which satisfy preconditions.
998 @param retries number of times to retry the tested property while shrinking.
913999 @param long_factor the factor by which to multiply count, max_gen and
9141000 max_fail when running a long test (default: 1).
9151001 @param max_gen maximum number of times the generation function
9501036 val make :
9511037 ?if_assumptions_fail:([`Fatal | `Warning] * float) ->
9521038 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int ->
953 ?small:('a -> int) -> ?name:string -> 'a arbitrary -> ('a -> bool) -> t
1039 ?small:('a -> int) -> ?retries:int -> ?name:string -> 'a arbitrary ->
1040 ('a -> bool) -> t
9541041 (** [make arb prop] builds a test that checks property [prop] on instances
9551042 of the generator [arb].
9561043 See {!make_cell} for a description of the parameters.
9721059 ?rand:Random.State.t -> 'a cell -> 'a TestResult.t
9731060
9741061 val check_cell_exn :
975 ?long:bool -> ?call:'a callback -> ?step:'a step ->
1062 ?long:bool -> ?call:'a callback ->
1063 ?step:'a step -> ?handler:'a handler ->
9761064 ?rand:Random.State.t -> 'a cell -> unit
9771065
9781066 val check_exn : ?long:bool -> ?rand:Random.State.t -> t -> unit
11081196 valid latin-1). *)
11091197
11101198 val printable_char : char arbitrary
1111 (** Uniformly distributed over a subset of chars. *)
1112 (* FIXME: describe which subset. *)
1199 (** Uniformly distributed over a subset of printable ascii chars.
1200 Ascii character codes 32 to 127.
1201 *)
11131202
11141203 val numeral_char : char arbitrary
11151204 (** Uniformly distributed over ['0'..'9']. *)
11161205
11171206 val string_gen_of_size : int Gen.t -> char Gen.t -> string arbitrary
1207 (** Builds a string generator from a (non-negative) size generator and a character generator. *)
11181208
11191209 val string_gen : char Gen.t -> string arbitrary
1120 (** Generates strings with a distribution of length of [small_nat]. *)
1210 (** Generates strings with a distribution of length of {!Gen.nat}. *)
11211211
11221212 val string : string arbitrary
1123 (** Generates strings with a distribution of length of [small_nat]
1213 (** Generates strings with a distribution of length of {!Gen.nat}
11241214 and distribution of characters of [char]. *)
11251215
11261216 val small_string : string arbitrary
11311221 @since 0.5.3 *)
11321222
11331223 val string_of_size : int Gen.t -> string arbitrary
1134 (** Generates strings with distribution of characters if [char]. *)
1224 (** Generates strings with distribution of characters of [char]. *)
11351225
11361226 val printable_string : string arbitrary
1137 (** Generates strings with a distribution of length of [small_nat]
1227 (** Generates strings with a distribution of length of {!Gen.nat}
11381228 and distribution of characters of [printable_char]. *)
11391229
11401230 val printable_string_of_size : int Gen.t -> string arbitrary
11411231 (** Generates strings with distribution of characters of [printable_char]. *)
11421232
11431233 val small_printable_string : string arbitrary
1234 (** Generates strings with a length of [small_nat]
1235 and distribution of characters of [printable_char]. *)
11441236
11451237 val numeral_string : string arbitrary
1146 (** Generates strings with a distribution of length of [small_nat]
1238 (** Generates strings with a distribution of length of {!Gen.nat}
11471239 and distribution of characters of [numeral_char]. *)
11481240
11491241 val numeral_string_of_size : int Gen.t -> string arbitrary
11501242 (** Generates strings with a distribution of characters of [numeral_char]. *)
11511243
11521244 val list : 'a arbitrary -> 'a list arbitrary
1153 (** Generates lists with length generated by [small_nat]. *)
1245 (** Generates lists with length generated by {!Gen.nat}. *)
11541246
11551247 val list_of_size : int Gen.t -> 'a arbitrary -> 'a list arbitrary
11561248 (** Generates lists with length from the given distribution. *)
11571249
11581250 val array : 'a arbitrary -> 'a array arbitrary
1159 (** Generates arrays with length generated by [small_nat]. *)
1251 (** Generates arrays with length generated by {!Gen.nat}. *)
11601252
11611253 val array_of_size : int Gen.t -> 'a arbitrary -> 'a array arbitrary
11621254 (** Generates arrays with length from the given distribution. *)
11731265 (** Combines four generators into a generator of 4-tuples.
11741266 Order matters for shrinking, see {!Shrink.pair} and the likes *)
11751267
1268 (** {3 Tuple of generators} *)
1269
1270 (** {4 Shrinks on [gen1], then [gen2], then ... } *)
1271
1272 val tup2 :
1273 'a arbitrary ->
1274 'b arbitrary ->
1275 ('a * 'b) arbitrary
1276 (** Combines two generators into a 2-tuple generator.
1277 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1278 Prints as many elements as available printers *)
1279
1280 val tup3 :
1281 'a arbitrary ->
1282 'b arbitrary ->
1283 'c arbitrary ->
1284 ('a * 'b * 'c) arbitrary
1285 (** Combines three generators into a 3-tuple generator.
1286 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1287 Prints as many elements as available printers *)
1288
1289 val tup4 :
1290 'a arbitrary ->
1291 'b arbitrary ->
1292 'c arbitrary ->
1293 'd arbitrary ->
1294 ('a * 'b * 'c * 'd) arbitrary
1295 (** Combines four generators into a 4-tuple generator.
1296 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1297 Prints as many elements as available printers *)
1298
1299 val tup5 : 'a arbitrary ->
1300 'b arbitrary ->
1301 'c arbitrary ->
1302 'd arbitrary ->
1303 'e arbitrary ->
1304 ('a * 'b * 'c * 'd * 'e) arbitrary
1305 (** Combines five generators into a 5-tuple generator.
1306 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1307 Prints as many elements as available printers *)
1308
1309 val tup6 :
1310 'a arbitrary ->
1311 'b arbitrary ->
1312 'c arbitrary ->
1313 'd arbitrary ->
1314 'e arbitrary ->
1315 'f arbitrary ->
1316 ('a * 'b * 'c * 'd * 'e * 'f) arbitrary
1317 (** Combines six generators into a 6-tuple generator.
1318 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1319 Prints as many elements as available printers *)
1320
1321 val tup7 :
1322 'a arbitrary ->
1323 'b arbitrary ->
1324 'c arbitrary ->
1325 'd arbitrary ->
1326 'e arbitrary ->
1327 'f arbitrary ->
1328 'g arbitrary ->
1329 ('a * 'b * 'c * 'd * 'e * 'f * 'g) arbitrary
1330 (** Combines seven generators into a 7-tuple generator.
1331 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1332 Prints as many elements as available printers *)
1333
1334 val tup8 :
1335 'a arbitrary ->
1336 'b arbitrary ->
1337 'c arbitrary ->
1338 'd arbitrary ->
1339 'e arbitrary ->
1340 'f arbitrary ->
1341 'g arbitrary ->
1342 'h arbitrary ->
1343 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) arbitrary
1344 (** Combines eight generators into a 8-tuple generator.
1345 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1346 Prints as many elements as available printers *)
1347
1348 val tup9 :
1349 'a arbitrary ->
1350 'b arbitrary ->
1351 'c arbitrary ->
1352 'd arbitrary ->
1353 'e arbitrary ->
1354 'f arbitrary ->
1355 'g arbitrary ->
1356 'h arbitrary ->
1357 'i arbitrary ->
1358 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) arbitrary
1359 (** Combines nine generators into a 9-tuple generator.
1360 Order of elements can matter (w.r.t shrinking, see {!Shrink.tup2})
1361 Prints as many elements as available printers *)
1362
11761363 val option : ?ratio:float -> 'a arbitrary -> 'a option arbitrary
11771364 (** Choose between returning Some random value with optional ratio, or None. *)
11781365
11791366 val fun1_unsafe : 'a arbitrary -> 'b arbitrary -> ('a -> 'b) arbitrary
11801367 (** Generator of functions of arity 1.
11811368 The functions are always pure and total functions:
1182 - when given the same argument (as decided by Pervasives.(=)), it returns the same value
1369 - when given the same argument (as decided by Stdlib.(=)), it returns the same value
11831370 - it never does side effects, like printing or never raise exceptions etc.
11841371 The functions generated are really printable.
11851372
599599 let quad (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) : ('a * 'b * 'c * 'd) t =
600600 (fun a b c d -> (a, b, c, d)) <$> g1 <*> g2 <*> g3 <*> g4
601601
602 let tup2 = pair
603
604 let tup3 = triple
605
606 let tup4 = quad
607
608 let tup5 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) : ('a * 'b * 'c * 'd * 'e) t =
609 (fun a b c d e -> (a, b, c, d, e)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5
610
611 let tup6 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) : ('a * 'b * 'c * 'd * 'e * 'f) t =
612 (fun a b c d e f -> (a, b, c, d, e, f)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6
613
614 let tup7 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g) t =
615 (fun a b c d e f g -> (a, b, c, d, e, f, g)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7
616
617 let tup8 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) (g8 : 'h t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t =
618 (fun a b c d e f g h -> (a, b, c, d, e, f, g, h)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7 <*> g8
619
620 let tup9 (g1 : 'a t) (g2 : 'b t) (g3 : 'c t) (g4 : 'd t) (g5 : 'e t) (g6 : 'f t) (g7 : 'g t) (g8 : 'h t) (g9 : 'i t) : ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t =
621 (fun a b c d e f g h i -> (a, b, c, d, e, f, g, h, i)) <$> g1 <*> g2 <*> g3 <*> g4 <*> g5 <*> g6 <*> g7 <*> g8 <*> g9
622
602623 (** Don't reuse {!int_range} which is much less performant (many more checks because of the possible range and origins). As a [string] generator may call this hundreds or even thousands of times for a single value, it's worth optimizing. *)
603624 let char : char t = fun st ->
604625 let c = RS.int st 256 in
767788 let contramap f p x = p (f x)
768789
769790 let comap = contramap
791
792 let default = fun _ -> "<no printer>"
793
794 let tup2 p_a p_b (a, b) =
795 Printf.sprintf "(%s, %s)" (p_a a) (p_b b)
796
797 let tup2_opt p_a p_b (a, b) =
798 let p_a = Option.value ~default p_a in
799 let p_b = Option.value ~default p_b in
800 tup2 p_a p_b (a, b)
801
802 let tup3 p_a p_b (p_c) (a, b, c) =
803 Printf.sprintf "(%s, %s, %s)" (p_a a) (p_b b) (p_c c)
804
805 let tup3_opt p_a p_b p_c (a, b, c) =
806 let p_a = Option.value ~default p_a in
807 let p_b = Option.value ~default p_b in
808 let p_c = Option.value ~default p_c in
809 tup3 p_a p_b p_c (a, b, c)
810
811 let tup4 p_a p_b p_c p_d (a, b, c, d) =
812 Printf.sprintf "(%s, %s, %s, %s)"
813 (p_a a) (p_b b)
814 (p_c c) (p_d d)
815
816 let tup4_opt p_a p_b p_c p_d (a, b, c, d) =
817 let p_a = Option.value ~default p_a in
818 let p_b = Option.value ~default p_b in
819 let p_c = Option.value ~default p_c in
820 let p_d = Option.value ~default p_d in
821 tup4 p_a p_b p_c p_d (a, b, c, d)
822
823 let tup5 p_a p_b p_c p_d p_e (a, b, c, d, e) =
824 Printf.sprintf "(%s, %s, %s, %s, %s)"
825 (p_a a) (p_b b)
826 (p_c c) (p_d d)
827 (p_e e)
828
829 let tup5_opt p_a p_b p_c p_d p_e (a, b, c, d, e) =
830 let p_a = Option.value ~default p_a in
831 let p_b = Option.value ~default p_b in
832 let p_c = Option.value ~default p_c in
833 let p_d = Option.value ~default p_d in
834 let p_e = Option.value ~default p_e in
835 tup5 p_a p_b p_c p_d p_e (a, b, c, d, e)
836
837 let tup6 p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f) =
838 Printf.sprintf "(%s, %s, %s, %s, %s, %s)"
839 (p_a a) (p_b b)
840 (p_c c) (p_d d)
841 (p_e e) (p_f f)
842
843 let tup6_opt p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f) =
844 let p_a = Option.value ~default p_a in
845 let p_b = Option.value ~default p_b in
846 let p_c = Option.value ~default p_c in
847 let p_d = Option.value ~default p_d in
848 let p_e = Option.value ~default p_e in
849 let p_f = Option.value ~default p_f in
850 tup6 p_a p_b p_c p_d p_e p_f (a, b, c, d, e, f)
851
852 let tup7 p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g) =
853 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s)"
854 (p_a a) (p_b b)
855 (p_c c) (p_d d)
856 (p_e e) (p_f f)
857 (p_g g)
858
859 let tup7_opt p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g) =
860 let p_a = Option.value ~default p_a in
861 let p_b = Option.value ~default p_b in
862 let p_c = Option.value ~default p_c in
863 let p_d = Option.value ~default p_d in
864 let p_e = Option.value ~default p_e in
865 let p_f = Option.value ~default p_f in
866 let p_g = Option.value ~default p_g in
867 tup7 p_a p_b p_c p_d p_e p_f p_g (a, b, c, d, e, f, g)
868
869 let tup8 p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h) =
870 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s, %s)"
871 (p_a a) (p_b b)
872 (p_c c) (p_d d)
873 (p_e e) (p_f f)
874 (p_g g) (p_h h)
875
876 let tup8_opt p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h) =
877 let p_a = Option.value ~default p_a in
878 let p_b = Option.value ~default p_b in
879 let p_c = Option.value ~default p_c in
880 let p_d = Option.value ~default p_d in
881 let p_e = Option.value ~default p_e in
882 let p_f = Option.value ~default p_f in
883 let p_g = Option.value ~default p_g in
884 let p_h = Option.value ~default p_h in
885 tup8 p_a p_b p_c p_d p_e p_f p_g p_h (a, b, c, d, e, f, g, h)
886
887 let tup9 p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i) =
888 Printf.sprintf "(%s, %s, %s, %s, %s, %s, %s, %s, %s)"
889 (p_a a) (p_b b)
890 (p_c c) (p_d d)
891 (p_e e) (p_f f)
892 (p_g g) (p_h h)
893 (p_i i)
894
895 let tup9_opt p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i) =
896 let p_a = Option.value ~default p_a in
897 let p_b = Option.value ~default p_b in
898 let p_c = Option.value ~default p_c in
899 let p_d = Option.value ~default p_d in
900 let p_e = Option.value ~default p_e in
901 let p_f = Option.value ~default p_f in
902 let p_g = Option.value ~default p_g in
903 let p_h = Option.value ~default p_h in
904 let p_i = Option.value ~default p_i in
905 tup9 p_a p_b p_c p_d p_e p_f p_g p_h p_i (a, b, c, d, e, f, g, h, i)
770906 end
771907
772908 (** {2 Observe Values} *)
12241360 long_factor : int; (* multiplicative factor for long test count *)
12251361 max_gen : int; (* max number of instances to generate (>= count) *)
12261362 max_fail : int; (* max number of failures *)
1363 retries : int; (* max number of retries during shrinking *)
12271364 law : 'a -> bool; (* the law to check *)
12281365 gen : 'a Gen.t; (* how to generate/shrink instances *)
12291366 print : 'a Print.t option; (* how to print values *)
12721409
12731410 let make_cell ?(if_assumptions_fail=default_if_assumptions_fail)
12741411 ?(count) ?(long_factor=1) ?max_gen
1275 ?(max_fail=1) ?(name=fresh_name()) ?print ?collect ?(stats=[]) gen law
1412 ?(max_fail=1) ?(retries=1) ?(name=fresh_name()) ?print ?collect ?(stats=[]) gen law
12761413 =
12771414 let count = global_count count in
12781415 let max_gen = match max_gen with None -> count + 200 | Some x->x in
12841421 stats;
12851422 max_gen;
12861423 max_fail;
1424 retries;
12871425 name;
12881426 count;
12891427 long_factor;
12931431
12941432 let make_cell_from_QCheck1 ?(if_assumptions_fail=default_if_assumptions_fail)
12951433 ?(count) ?(long_factor=1) ?max_gen
1296 ?(max_fail=1) ?(name=fresh_name()) ~gen ?shrink ?print ?collect ~stats law
1434 ?(max_fail=1) ?(retries=1) ?(name=fresh_name()) ~gen ?shrink ?print ?collect ~stats law
12971435 =
12981436 let count = global_count count in
12991437 (* Make a "fake" QCheck2 arbitrary with no shrinking *)
13071445 stats;
13081446 max_gen;
13091447 max_fail;
1448 retries;
13101449 name;
13111450 count;
13121451 long_factor;
13141453 qcheck1_shrink = shrink;
13151454 }
13161455
1317 let make ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?name ?print ?collect ?stats gen law =
1318 Test (make_cell ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?name ?print ?collect ?stats gen law)
1456 let make ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?retries ?name ?print ?collect ?stats gen law =
1457 Test (make_cell ?if_assumptions_fail ?count ?long_factor ?max_gen ?max_fail ?retries ?name ?print ?collect ?stats gen law)
13191458
13201459 let test_get_count (Test cell) = get_count cell
13211460
14061545 | Run_ok
14071546 | Run_fail of string list
14081547
1409 let run_law law x =
1548 (* run_law is a helper function for testing a property [law] on a
1549 generated input [x].
1550
1551 When passed a ~retries number n>1, the tested property is checked
1552 n times for each shrunk input candidate. The default value is 1,
1553 thus causing no change in behaviour.
1554
1555 Retrying a property can be useful when testing non-deterministic
1556 code with QCheck, e.g., for multicore execution. The idea is
1557 described in
1558 'Testing a Database for Race Conditions with QuickCheck'
1559 Hughes and Bolinder, Erlang 2011, Sec.6:
1560
1561 "As we explained in section 4, we ensure that tests fail when
1562 races are present simply by repeating each test a large number of
1563 times, and by running on a dual core machine. We obtained the
1564 minimal failing cases in the previous section by repeating each
1565 test 100 times during shrinking: thus we stopped shrinking a test
1566 case only when all of its candidate shrinkings passed 100 tests
1567 in a row." *)
1568 let run_law ~retries law x =
1569 let rec loop i = match law x with
1570 | false -> Run_fail []
1571 | true ->
1572 if i<=1 then Run_ok else loop (i-1) in
14101573 try
1411 if law x then Run_ok else Run_fail []
1574 loop retries
14121575 with User_fail msg -> Run_fail [msg]
14131576
14141577 (* QCheck1-compatibility code *)
14381601 try
14391602 incr count;
14401603 st.handler st.test.name st.test (Shrinking (steps, !count, x));
1441 begin match run_law st.test.law x with
1604 begin match run_law ~retries:st.test.retries st.test.law x with
14421605 | Run_fail m when not is_err -> Some (Tree.pure x, Shrink_fail, m)
14431606 | _ -> None
14441607 end
14531616 try
14541617 incr count;
14551618 st.handler st.test.name st.test (Shrinking (steps, !count, x));
1456 begin match run_law st.test.law x with
1619 begin match run_law ~retries:st.test.retries st.test.law x with
14571620 | Run_fail m when not is_err -> Some (x_tree, Shrink_fail, m)
14581621 | _ -> None
14591622 end
15311694 let res =
15321695 try
15331696 state.handler state.test.name state.test (Testing input);
1534 begin match run_law state.test.law input with
1697 begin match run_law ~retries:1 state.test.law input with
15351698 | Run_ok ->
15361699 (* one test ok *)
15371700 decr_count state;
17671930 | R.Failed_other {msg} ->
17681931 raise (Test_fail (cell.name, [msg]))
17691932
1770 let check_cell_exn ?long ?call ?step ?rand cell =
1771 let res = check_cell ?long ?call ?step ?rand cell in
1933 let check_cell_exn ?long ?call ?step ?handler ?rand cell =
1934 let res = check_cell ?long ?call ?step ?handler ?rand cell in
17721935 check_result cell res
17731936
17741937 let check_exn ?long ?rand (Test cell) = check_cell_exn ?long ?rand cell
624624
625625 @since 0.5.1
626626 *)
627
628 (** {3 Tuple of generators} *)
629
630 (** {4 Shrinks on [gen1], then [gen2], then ... } *)
631
632 val tup2 : 'a t -> 'b t -> ('a * 'b) t
633
634 val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
635
636 val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
637
638 val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
639
640 val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> ('a * 'b * 'c * 'd * 'e * 'f) t
641
642 val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
643
644 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
645
646 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
627647
628648 (** {3 Convert a structure of generator to a generator of structure} *)
629649
10351055
10361056 val comap : ('b -> 'a) -> 'a t -> 'b t
10371057 (** @deprecated use {!contramap} instead. *)
1058
1059 val tup2 : 'a t -> 'b t -> ('a * 'b) t
1060 (** 2-tuple printer. Expects printers for each component. *)
1061
1062 val tup3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
1063 (** 3-tuple printer. Expects printers for each component. *)
1064
1065 val tup4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
1066 (** 4-tuple printer. Expects printers for each component. *)
1067
1068 val tup5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
1069 (** 5-tuple printer. Expects printers for each component. *)
1070
1071 val tup6 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t ->
1072 ('a * 'b * 'c * 'd * 'e * 'f) t
1073 (** 6-tuple printer. Expects printers for each component. *)
1074
1075 val tup7 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t ->
1076 ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
1077 (** 7-tuple printer. Expects printers for each component. *)
1078
1079 val tup8 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t ->
1080 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
1081 (** 8-tuple printer. Expects printers for each component. *)
1082
1083 val tup9 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t ->
1084 ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) t
1085 (** 9-tuple printer. Expects printers for each component. *)
10381086 end
10391087
10401088 (** Shrinking helper functions. *)
15361584
15371585 val make_cell :
15381586 ?if_assumptions_fail:([`Fatal | `Warning] * float) ->
1539 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int -> ?name:string ->
1540 ?print:'a Print.t -> ?collect:('a -> string) -> ?stats:('a stat list) ->
1587 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int -> ?retries:int ->
1588 ?name:string -> ?print:'a Print.t -> ?collect:('a -> string) -> ?stats:('a stat list) ->
15411589 'a Gen.t -> ('a -> bool) ->
15421590 'a cell
15431591 (** [make_cell gen prop] builds a test that checks property [prop] on instances
15521600 preconditions (should be >= count).
15531601 @param max_fail maximum number of failures before we stop generating
15541602 inputs. This is useful if shrinking takes too much time.
1603 @param retries number of times to retry the tested property while shrinking.
15551604 @param if_assumptions_fail the minimum
15561605 fraction of tests that must satisfy the precondition for a success
15571606 to be considered valid.
15671616 val make_cell_from_QCheck1 :
15681617 ?if_assumptions_fail:([`Fatal | `Warning] * float) ->
15691618 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int ->
1570 ?name:string -> gen:(Random.State.t -> 'a) -> ?shrink:('a -> ('a -> unit) -> unit) ->
1619 ?retries:int -> ?name:string -> gen:(Random.State.t -> 'a) -> ?shrink:('a -> ('a -> unit) -> unit) ->
15711620 ?print:('a -> string) -> ?collect:('a -> string) -> stats:'a stat list -> ('a -> bool) ->
15721621 'a cell
15731622 (** ⚠️ Do not use, this is exposed for internal reasons only. ⚠️
15971646
15981647 val make :
15991648 ?if_assumptions_fail:([`Fatal | `Warning] * float) ->
1600 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int -> ?name:string ->
1601 ?print:('a Print.t) -> ?collect:('a -> string) -> ?stats:('a stat list) ->
1649 ?count:int -> ?long_factor:int -> ?max_gen:int -> ?max_fail:int -> ?retries:int ->
1650 ?name:string -> ?print:('a Print.t) -> ?collect:('a -> string) -> ?stats:('a stat list) ->
16021651 'a Gen.t -> ('a -> bool) -> t
16031652 (** [make gen prop] builds a test that checks property [prop] on instances
16041653 of the generator [gen].
16911740 *)
16921741
16931742 val check_cell_exn :
1694 ?long:bool -> ?call:'a callback -> ?step:'a step ->
1743 ?long:bool -> ?call:'a callback ->
1744 ?step:'a step -> ?handler:'a handler ->
16951745 ?rand:Random.State.t -> 'a cell -> unit
16961746 (** Same as {!check_cell} but calls {!check_result} on the result.
16971747 @raise Test_error if [res = Error _]
0 open Ppxlib
1
2 (** This module contains all generators from QCheck used to
3 derive a type declaration *)
4
5 (** {2. Type} *)
6
7 let ty = Ldot (Ldot (Lident "QCheck", "Gen"), "t")
8
9 (** {2. Primitive generators} *)
10
11 let unit loc = [%expr QCheck.Gen.unit]
12
13 let int loc = [%expr QCheck.Gen.int]
14
15 let string loc = [%expr QCheck.Gen.string]
16
17 let char loc = [%expr QCheck.Gen.char]
18
19 let bool loc = [%expr QCheck.Gen.bool]
20
21 let float loc = [%expr QCheck.Gen.float]
22
23 let int32 loc = [%expr QCheck.Gen.ui32]
24
25 let int64 loc = [%expr QCheck.Gen.ui64]
26
27 let option ~loc e = [%expr QCheck.Gen.opt [%e e]]
28
29 let list ~loc e = [%expr QCheck.Gen.list [%e e]]
30
31 let array ~loc e = [%expr QCheck.Gen.array [%e e]]
32
33 (** {2. Generator combinators} *)
34
35 let pure ~loc x = [%expr QCheck.Gen.pure [%e x]]
36
37 let frequency ~loc l =
38 match l with
39 | [%expr [([%e? _], [%e? x])]] -> x
40 | _ ->
41 [%expr QCheck.Gen.frequency [%e l]]
42
43 let map ~loc pat expr gen =
44 [%expr QCheck.Gen.map (fun [%p pat] -> [%e expr]) [%e gen]]
45
46 let pair ~loc a b =
47 [%expr QCheck.Gen.pair [%e a] [%e b]]
48
49 let triple ~loc a b c =
50 [%expr QCheck.Gen.triple [%e a] [%e b] [%e c]]
51
52 let quad ~loc a b c d=
53 [%expr QCheck.Gen.quad [%e a] [%e b] [%e c] [%e d]]
54
55 let sized ~loc e =
56 [%expr QCheck.Gen.sized @@ [%e e]]
57
58 let fix ~loc e =
59 [%expr QCheck.Gen.fix [%e e]]
60
61 (** Observable generators *)
62 module Observable = struct
63 (** {2. Primitive generators} *)
64 let unit loc = [%expr QCheck.Observable.unit]
65
66 let int loc = [%expr QCheck.Observable.int]
67
68 let string loc = [%expr QCheck.Observable.string]
69
70 let char loc = [%expr QCheck.Observable.char]
71
72 let bool loc = [%expr QCheck.Observable.bool]
73
74 let float loc = [%expr QCheck.Observable.float]
75
76 let int32 loc = [%expr QCheck.Observable.int32]
77
78 let int64 loc = [%expr QCheck.Observable.int64]
79
80 let option ~loc e = [%expr QCheck.Observable.option [%e e]]
81
82 let list ~loc e = [%expr QCheck.Observable.list [%e e]]
83
84 let array ~loc e = [%expr QCheck.Observable.array [%e e]]
85
86 (** {2. Observable combinators} *)
87 let pair ~loc a b =
88 [%expr QCheck.Observable.pair [%e a] [%e b]]
89
90 let triple ~loc a b c =
91 [%expr QCheck.Observable.triple [%e a] [%e b] [%e c]]
92
93 let quad ~loc a b c d=
94 [%expr QCheck.Observable.quad [%e a] [%e b] [%e c] [%e d]]
95 end
0 # ppx_deriving_qcheck
1
2 ## Generator
3 Derive `QCheck.Gen.t` from a type declaration
4
5 ```ocaml
6 type tree = Leaf of int | Node of tree * tree
7 [@@deriving qcheck]
8
9 let rec rev tree = match tree with
10 | Leaf _ -> tree
11 | Node (left, right) -> Node (rev right, rev left)
12
13 let test =
14 QCheck.Test.make
15 ~name:"tree -> rev (rev tree) = tree"
16 (QCheck.make gen_tree)
17 (fun tree -> rev (rev tree) = tree)
18 ```
19
20 For `type tree` we derive two generators:
21 - `val gen_tree : tree Gen.t` and
22 - `val gen_tree_sized : int -> tree Gen.t`
23
24 For non-recursive types the latter is however not derived.
25
26 For types with the name `t` (i.e. `type t = ...`) which is a common idiom in OCaml code,
27 the deriver omits the name from the derived generators,
28 thus producing `val gen : t Gen.t` and optionally `val gen_sized : int -> t Gen.t`.
29
30 ### Overwrite generator
31 If you wan't to specify your own `generator` for any type you can
32 add an attribute to the type:
33
34 ```ocaml
35 type t = (int : [@gen QCheck.Gen.(0 -- 10)])
36 [@@deriving qcheck]
37
38 (* produces ==> *)
39
40 let gen : t QCheck.Gen.t = QCheck.Gen.(0 -- 10)
41 ```
42
43 This attribute has 2 advantages:
44 * Use your own generator for a specific type (see above)
45 * There is no generator available for the type
46 ```ocaml
47 type my_foo =
48 | Foo of my_other_type
49 | Bar of bool
50 [@@deriving qcheck]
51 ^^^^^^^^^^^^^^^^
52 Error: Unbound value gen_my_other_type
53
54 (* Possible fix *)
55 let gen_my_other_type = (* add your implementation here *)
56
57 type my_foo =
58 | Foo of my_other_type [@gen gen_my_other_type]
59 | Bar of bool
60 [@@deriving qcheck]
61 ```
62
63 ## How to use
64
65 Add to your OCaml libraries with dune
66 ```ocaml
67 ...
68 (preprocess (pps ppx_deriving_qcheck)))
69 ...
70 ```
71
72 ## Supported types
73
74 ### Primitive types
75
76 * Unit
77 ```ocaml
78 type t = unit [@@deriving qcheck]
79
80 (* ==> *)
81
82 let gen = QCheck.Gen.unit
83 ```
84
85 * Bool
86 ```ocaml
87 type t = bool [@@deriving qcheck]
88
89 (* ==> *)
90
91 let gen = QCheck.Gen.bool
92 ```
93
94 * Integer
95 ```ocaml
96 type t = int [@@deriving qcheck]
97
98 (* ==> *)
99
100 let gen = QCheck.Gen.int
101 ```
102
103 * Float
104 ```ocaml
105 type t = float [@@deriving qcheck]
106
107 (* ==> *)
108
109 let gen = QCheck.Gen.float
110 ```
111
112 * String
113 ```ocaml
114 type t = string [@@deriving qcheck]
115
116 (* ==> *)
117
118 let gen = QCheck.Gen.string
119 ```
120
121 * Char
122 ```ocaml
123 type t = char [@@deriving qcheck]
124
125 (* ==> *)
126
127 let gen = QCheck.Gen.char
128 ```
129
130 * Option
131 ```ocaml
132 type 'a t = 'a option [@@deriving qcheck]
133
134 (* ==> *)
135
136 let gen gen_a = QCheck.Gen.option gen_a
137 ```
138
139 * List
140 ```ocaml
141 type 'a t = 'a list [@@deriving qcheck]
142
143 (* ==> *)
144
145 let gen gen_a = QCheck.Gen.list gen_a
146 ```
147
148 * Array
149 ```ocaml
150 type 'a t = 'a array [@@deriving qcheck]
151
152 (* ==> *)
153
154 let gen gen_a = QCheck.Gen.array gen_a
155 ```
156
157 ### Tuples of size `n`
158
159 * n = 2
160 ```ocaml
161 type t = int * int [@@deriving qcheck]
162
163 (* ==> *)
164
165 let gen = QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.int
166 ```
167
168 * n = 3
169 ```ocaml
170 type t = int * int * int [@@deriving qcheck]
171
172 (* ==> *)
173
174 let gen = QCheck.Gen.triple QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int
175 ```
176
177 * n = 4
178 ```ocaml
179 type t = int * int * int * int [@@deriving qcheck]
180
181 (* ==> *)
182
183 let gen = QCheck.Gen.quad QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int
184 ```
185
186 * n > 4, tuples are split between pairs, for instance n = 8
187 ```ocaml
188 type t = int * int * int * int * int * int * int * int [@@deriving qcheck]
189
190 (* ==> *)
191
192 let gen =
193 QCheck.Gen.pair
194 (QCheck.Gen.quad QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int)
195 (QCheck.Gen.quad QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int)
196 ```
197
198 ## Records
199 ```ocaml
200 type service = {
201 service_name : string;
202 port : int;
203 protocol : string;
204 } [@@deriving qcheck]
205
206 (* ==> *)
207
208 let gen_service =
209 QCheck.Gen.map
210 (fun (gen0, gen1, gen2) ->
211 { service_name = gen0; port = gen1; protocol = gen2 })
212 (QCheck.Gen.triple QCheck.Gen.string QCheck.Gen.int QCheck.Gen.string)
213 ```
214
215 ## Variants
216 * Variants
217 ```ocaml
218 type color = Red | Blue | Green
219 [@@deriving qcheck]
220
221 (* ==> *)
222
223 let gen_color =
224 QCheck.Gen.frequency
225 [(1, (QCheck.Gen.pure Red));
226 (1, (QCheck.Gen.pure Blue));
227 (1, (QCheck.Gen.pure Green))]
228 ```
229
230 * Polymorphic variants
231 ```ocaml
232 type color = [ `Red | `Blue | `Green ]
233 [@@deriving qcheck]
234
235 (* ==> *)
236
237 let gen_color =
238 (QCheck.Gen.frequency
239 [(1, (QCheck.Gen.pure `Red));
240 (1, (QCheck.Gen.pure `Blue));
241 (1, (QCheck.Gen.pure `Green))] : color QCheck.Gen.t)
242 ```
243
244 ## Recursive variants
245 * Recursive variants
246 ```ocaml
247 type tree = Leaf of int | Node of tree * tree
248 [@@deriving qcheck]
249
250 (* ==> *)
251
252 let rec gen_tree_sized n =
253 match n with
254 | 0 -> QCheck.Gen.map (fun gen0 -> Leaf gen0) QCheck.Gen.int
255 | n ->
256 QCheck.Gen.frequency
257 [(1, (QCheck.Gen.map (fun gen0 -> Leaf gen0) QCheck.Gen.int));
258 (1,
259 (QCheck.Gen.map (fun (gen0, gen1) -> Node (gen0, gen1))
260 (QCheck.Gen.pair (self (n / 2)) (self (n / 2)))))]))
261
262 let gen_tree = QCheck.Gen.sized @@ gen_tree_sized
263 ```
264
265 * Recursive polymorphic variants
266 ```ocaml
267 type tree = [ `Leaf of int | `Node of tree * tree ]
268 [@@deriving qcheck]
269
270 (* ==> *)
271
272 let gen_tree =
273 (QCheck.Gen.sized @@ QCheck.Gen.fix (fun self -> function
274 | 0 ->
275 QCheck.Gen.frequency [
276 ( 1, QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int);
277 ]
278 | n ->
279 QCheck.Gen.frequency [
280 ( 1, QCheck.Gen.map (fun gen0 -> `Leaf gen0) QCheck.Gen.int);
281 ( 1,
282 QCheck.Gen.map (fun gen0 -> `Node gen0)
283 (QCheck.Gen.map
284 (fun (gen0, gen1) -> (gen0, gen1))
285 (QCheck.Gen.pair (self (n / 2)) (self (n / 2)))))
286 ])
287 : tree QCheck.Gen.t)
288 ```
289
290 ## Mutual recursive types
291 ```ocaml
292 type tree = Node of (int * forest)
293 and forest = Nil | Cons of (tree * forest)
294 [@@deriving qcheck]
295
296 (* ==> *)
297
298 let rec gen_tree () =
299 QCheck.Gen.frequency
300 [(1,
301 (QCheck.Gen.map (fun gen0 -> Node gen0)
302 (QCheck.Gen.map (fun (gen0, gen1) -> (gen0, gen1))
303 (QCheck.Gen.pair QCheck.Gen.int (gen_forest ())))))]
304
305 and gen_forest () =
306 QCheck.Gen.sized @@
307 (QCheck.Gen.fix
308 (fun self -> function
309 | 0 -> QCheck.Gen.frequency [(1, (QCheck.Gen.pure Nil))]
310 | n ->
311 QCheck.Gen.frequency
312 [(1, (QCheck.Gen.pure Nil));
313 (1,
314 (QCheck.Gen.map (fun gen0 -> Cons gen0)
315 (QCheck.Gen.map (fun (gen0, gen1) -> (gen0, gen1))
316 (QCheck.Gen.pair (gen_tree ()) (self (n / 2))))))]))
317
318 let gen_tree = gen_tree ()
319
320 let gen_forest = gen_forest ()
321 ```
322
323 ## Unsupported types
324
325 ### GADT
326 Deriving a GADT currently produces an ill-typed generator.
327
328 ### Let us know
329 If you encounter a unsupported type (that should be), please let us know by creating
330 an issue.
0 open Ppxlib
1
2 (** [curry_args args body] adds parameter to [body]
3
4 e.g.:
5 curry_args [gen_a; gen_b] () => fun gen_a -> fun gen_b -> ()
6 *)
7 let rec curry_args ~loc args body =
8 match args with
9 | [] -> body
10 | x :: xs -> [%expr fun [%p x] -> [%e curry_args ~loc xs body]]
11
12 (** [apply_args args body] applies parameters to [body]
13
14 e.g.:
15 apply_args [gen_a; gen_b] f => f gen_a gen_b
16 *)
17 let apply_args ~loc args body =
18 let rec aux acc = function
19 | [] -> acc
20 | [arg] -> [%expr [%e acc] [%e arg]]
21 | arg :: args -> aux [%expr [%e acc] [%e arg]] args
22 in
23 aux body args
0 open Ppxlib
1
2 (** [find_first_attribute xs name] returns the first attribute found in [xs]
3 named [name] *)
4 let find_attribute_opt xs name =
5 List.find_opt (fun attribute -> attribute.attr_name.txt = name) xs
6
7 let get_expr_payload x =
8 match x.attr_payload with
9 | PStr [ { pstr_desc = Pstr_eval (e, _); _ } ] -> Some [%expr [%e e]]
10 | _ -> None
11
12 let gen ct =
13 Option.fold ~none:None ~some:get_expr_payload
14 @@ find_attribute_opt ct.ptyp_attributes "gen"
15
16 let weight xs =
17 Option.fold ~none:None ~some:get_expr_payload
18 @@ find_attribute_opt xs "weight"
0 open Ppxlib
1 (** This file handles every attributes to be found in a core_type definition *)
2
3 val gen : core_type -> expression option
4 (** [gen loc ct] look for an attribute "gen" in [ct]
5
6 example:
7 {[
8 type t =
9 | A of int
10 | B of (int [@gen QCheck.int32])
11 ]}
12
13 It allows the user to specify which generator he wants for a specific type.
14 Returns the generator as an expression and returns None if no attribute
15 is present *)
16
17 val weight : attributes -> expression option
18 (** [weight loc ct] look for an attribute "weight" in [ct]
19
20 example:
21 {[
22 type t =
23 | A [@weight 5]
24 | B [@weight 6]
25 | C
26 ]}
27 It allows the user to specify the weight of a type case. *)
0 (library
1 (name ppx_deriving_qcheck)
2 (public_name ppx_deriving_qcheck)
3 (libraries ppxlib)
4 (preprocess (pps ppxlib.metaquot))
5 (ppx_runtime_libraries qcheck-core)
6 (kind ppx_deriver))
0 open Ppxlib
1 module G = QCheck_generators
2 module O = G.Observable
3
4 (** {1. ppx_deriving_qcheck} *)
5
6 (** ppx_deriving_qcheck is a ppx deriver for QCheck generators. It does a
7 traversal map on type declarations annoted with [QCheck].
8
9 Example:
10 {[
11 module Tree : sig
12 type t
13
14 val gen : t QCheck.Gen.t
15 end = struct
16 type t = Leaf | Node of int * t * t
17 [@@deriving qcheck]
18 end
19 ]}
20 *)
21
22 (** {2. Misc. helpers} *)
23
24 (** [name s] produces the generator name based on [s] *)
25 let name ?(sized = false) s =
26 let prefix = "gen" in
27 (match s with "t" -> prefix | s -> prefix ^ "_" ^ s) ^
28 (if sized then "_sized" else "")
29
30 (** [pat ~loc s] creates a pattern for a generator based on {!name}. *)
31 let pat ~loc ?sized s =
32 let (module A) = Ast_builder.make loc in
33 let s = name ?sized s in
34 A.pvar s
35
36 (** {2. Recursive generators} *)
37
38 (** Recursive generators must be treated separatly:
39
40 {[
41 type 'a list = Cons of 'a * 'a list | Nil
42 ]}
43
44 becomes:
45
46 {[
47 let rec gen_list_sized gen_a n =
48 match n with
49 | 0 -> pure Nil
50 | n -> map2 (fun x xs -> Cons (x, xs) gen_a (gen_list_sized gen_a (n/2))
51
52 let gen_list_sized gen_a = sized @@ (gen_list_sized gen_a)
53 ]}
54
55 In the basic derivation {[ 'a list ]} would be translated to {[gen_list]}.
56 However, we want the generator to call itsef.
57 *)
58
59 module Env = struct
60 (** [env] contains:
61 - the list of recursive types during the derivation
62 - the list of types to derive (i.e. mutual types)
63 - the current type to derive *)
64 type env = {
65 rec_types : string list;
66 curr_types : string list;
67 curr_type : string;
68 }
69
70 let is_rec env x = List.mem x env.rec_types
71 end
72
73 let rec longident_to_str = function
74 | Lident s -> s
75 | Ldot (lg, s) -> Printf.sprintf "%s.%s" (longident_to_str lg) s
76 | Lapply (lg1, lg2) ->
77 Printf.sprintf "%s %s" (longident_to_str lg1) (longident_to_str lg2)
78
79 let rec is_rec_typ env = function
80 | { ptyp_desc = Ptyp_constr ({ txt = x; _ }, _); _ } ->
81 List.exists (fun typ_name -> longident_to_str x = typ_name) env.Env.curr_types
82 | { ptyp_desc = Ptyp_tuple xs; _ } -> List.exists (is_rec_typ env) xs
83 | { ptyp_desc = Ptyp_variant (rws, _, _); _ } ->
84 List.exists (is_rec_row_field env) rws
85 | _ -> false
86
87 and is_rec_row_field env rw =
88 match rw.prf_desc with
89 | Rtag (lab, _, cts) ->
90 List.exists (fun typ_name -> lab.txt = typ_name) env.Env.curr_types ||
91 List.exists (is_rec_typ env) cts
92 | Rinherit ct -> is_rec_typ env ct
93
94 let is_rec_constr_decl env cd =
95 match cd.pcd_args with
96 | Pcstr_tuple cts -> List.exists (is_rec_typ env) cts
97 | _ -> false
98
99 (** [is_rec_type_decl env typ] looks for elements of [env.curr_types]
100 recursively in [typ]. *)
101 let is_rec_type_decl env typ =
102 let in_type_kind =
103 match typ.ptype_kind with
104 | Ptype_variant cstrs -> List.exists (is_rec_constr_decl env) cstrs
105 | _ -> false
106 in
107 let in_manifest =
108 match typ.ptype_manifest with
109 | Some x -> is_rec_typ env x
110 | None -> false
111 in
112 in_type_kind || in_manifest
113
114
115 (** is_n_used looks for `n` (size indication) in an expression.
116
117 For instance:
118 {[
119 type foo = A of bar | B of bar
120 and bar = Any
121 [@@deriving qcheck]
122
123 let rec gen_sized_foo n =
124 let open QCheck.Gen in
125 frequency [
126 (map (fun x -> A x) gen_bar);
127 (map (fun x -> B x) gen_bar);
128 ]
129 and gen_bar = p
130 let open QCheck.Gen in
131 pure Any
132 ]}
133
134 The type [foo] is recursive because it has a dependency to [bar] but does
135 not use the fuel as there is no "leaves" for this type.
136
137 We begin by looking for occurences of variables `n`, iff we did not find
138 any occurences, we replace `n` by `_n` in the generator's parameters. Thus,
139 avoiding an unused variable.
140 *)
141 exception N_is_used
142
143 class is_n_used (expr : expression) =
144 object(self)
145 inherit Ast_traverse.map as super
146
147 method! expression expr =
148 match expr with
149 | [%expr n ] ->
150 raise N_is_used
151 | _ -> super#expression expr
152
153 method go () =
154 match self#expression expr |> ignore with
155 | exception N_is_used -> true
156 | () -> false
157 end
158
159 let is_n_used expr = (new is_n_used expr)#go ()
160
161 (** {2. Generator constructors} *)
162
163 (** [gen_longident lg args] creates a generator using [lg].
164
165 The longident can either be a:
166 - Lident s: We transform to gen_s (or gen if s = "t")
167 - Ldot (lg, s): We transform to qualified generator (e.g. B.gen)
168 *)
169 let gen_longident ~loc ~env lg args =
170 let (module A) = Ast_builder.make loc in
171 match lg with
172 | Lident s ->
173 if Env.is_rec env s then
174 name ~sized:true s |> A.evar |>
175 Args.apply_args ~loc args |>
176 Args.apply_args ~loc [ [%expr (n / 2)] ]
177 else
178 name s |> A.evar |> Args.apply_args ~loc args
179 | Ldot (lg, s) ->
180 A.(pexp_ident (Located.mk @@ Ldot (lg, name s))) |>
181 Args.apply_args ~loc args
182 | Lapply (_, _) -> raise (Invalid_argument "gen received an Lapply")
183
184 (** [gen_sized typ_name is_rec to_gen xs] uses [is_rec] to determine recursive
185 nodes in [xs].
186
187 If no recursive node is found, the type is _not_ recursive, we build a
188 generator using frequency.
189
190 However, if recursive nodes are found, we build a tree like generator using
191 {!gen_sized}.
192
193 The function is generalized for variants and polymorphic variants:
194
195 {[
196 type t = Leaf | Node of int * t * t
197
198 (* or *)
199
200 type t = [`Leaf | `Node of int * t * t]
201 ]}
202
203 Therefore, [is_rec] and [to_gen] are different for variants and polymorphic
204 variants. *)
205 let gen_sized ~loc (is_rec : 'a -> bool) (to_gen : 'a -> expression) (xs : 'a list) =
206 let (module A) = Ast_builder.make loc in
207 let leaves =
208 List.filter (fun x -> not (is_rec x)) xs |> List.map to_gen
209 in
210 let nodes = List.filter is_rec xs in
211
212 if List.length nodes = 0 then
213 G.frequency ~loc (A.elist leaves)
214 else if List.length leaves = 0 then
215 let nodes = List.map to_gen nodes in
216 G.frequency ~loc (A.elist nodes)
217 else
218 let nodes = List.map to_gen nodes in
219 let leaves = A.elist leaves |> G.frequency ~loc
220 and nodes = A.elist (leaves @ nodes) |> G.frequency ~loc in
221 [%expr
222 match n with
223 | 0 -> [%e leaves]
224 | _ -> [%e nodes]
225 ]
226
227 (** [gen_tuple ~loc ?f tys] transforms list of type [tys] into a tuple generator.
228
229 [f] can be used to transform tuples, for instance:
230 {[
231 type t = Foo of int * int
232 ]}
233
234 Without [f]:
235 {[
236 let gen = QCheck.Gen.(map (fun (x, y) -> (x, y)) (pair int int))
237 ]}
238
239 With [f], building Foo:
240 {[
241 let gen = QCheck.Gen.(map (fun (x, y) -> Foo (x, y)) (pair int int))
242 ]}
243 *)
244 let gen_tuple ~loc ?(f = fun x -> x) tys =
245 let tuple = Tuple.from_list tys in
246 let gen = Tuple.to_gen ~loc tuple in
247 let expr = Tuple.to_expr ~loc tuple |> f in
248 let pat = Tuple.to_pat ~loc tuple in
249 G.map ~loc pat expr gen
250
251 (** [gen_record loc gens ?f label_decls] transforms [gens] and [label_decls] to
252 a record generator.
253
254 Similarly to {!gen_tuple}, we can use [f] to transform records, for instance:
255 {[
256 type t = Foo of { left : int; right : int }
257 ]}
258
259 Without [f]:
260 {[
261 let gen = QCheck.Gen.(map (fun (x, y) -> {left = x; right = y}) (pair int int))
262 ]}
263
264 With [f], building Foo:
265 {[
266 let gen = QCheck.Gen.(map (fun (x, y) -> Foo {left = x; right = y}) (pair int int))
267 ]}
268
269 *)
270 let gen_record ~loc ~gens ?(f = fun x -> x) xs =
271 let (module A) = Ast_builder.make loc in
272 let tuple = Tuple.from_list gens in
273 let gen = Tuple.to_gen ~loc tuple in
274 let pat = Tuple.to_pat ~loc tuple in
275 (* TODO: this should be handled in {!Tuple} *)
276 let gens =
277 List.mapi
278 (fun i _ ->
279 let s = Printf.sprintf "gen%d" i in
280 A.evar s)
281 gens
282 in
283 let fields =
284 List.map2
285 (fun { pld_name; _ } value ->
286 (A.Located.mk @@ Lident pld_name.txt, value))
287 xs gens
288 in
289 let expr = A.pexp_record fields None |> f in
290
291 G.map ~loc pat expr gen
292
293 (** {2. Core derivation} *)
294
295 (** [gen_from_type typ] performs the AST traversal and derivation to qcheck generators *)
296 let rec gen_from_type ~loc ~env typ =
297 Option.value (Attributes.gen typ)
298 ~default:
299 (match typ with
300 | [%type: unit] -> G.unit loc
301 | [%type: int] -> G.int loc
302 | [%type: string] | [%type: String.t] -> G.string loc
303 | [%type: char] -> G.char loc
304 | [%type: bool] -> G.bool loc
305 | [%type: float] -> G.float loc
306 | [%type: int32] | [%type: Int32.t] -> G.int32 loc
307 | [%type: int64] | [%type: Int64.t] -> G.int64 loc
308 | [%type: [%t? typ] option] -> G.option ~loc (gen_from_type ~loc ~env typ)
309 | [%type: [%t? typ] list] -> G.list ~loc (gen_from_type ~loc ~env typ)
310 | [%type: [%t? typ] array] -> G.array ~loc (gen_from_type ~loc ~env typ)
311 | { ptyp_desc = Ptyp_tuple typs; _ } ->
312 let tys = List.map (gen_from_type ~loc ~env) typs in
313 gen_tuple ~loc tys
314 | { ptyp_desc = Ptyp_constr ({ txt = ty; _ }, args); _ } ->
315 let args = List.map (gen_from_type ~loc ~env) args in
316 gen_longident ~loc ~env ty args
317 | { ptyp_desc = Ptyp_var s; _ } ->
318 gen_longident ~loc ~env (Lident s) []
319 | { ptyp_desc = Ptyp_variant (rws, _, _); _ } ->
320 gen_from_variant ~loc ~env rws
321 | { ptyp_desc = Ptyp_arrow (_, left, right); _ } ->
322 gen_from_arrow ~loc ~env left right
323 | _ ->
324 Ppxlib.Location.raise_errorf ~loc
325 "This type is not supported in ppx_deriving_qcheck")
326
327 and gen_from_constr ~loc ~env { pcd_name; pcd_args; pcd_attributes; _ } =
328 let (module A) = Ast_builder.make loc in
329 let constr_decl =
330 A.constructor_declaration ~name:pcd_name ~args:pcd_args ~res:None
331 in
332 let mk_constr expr = A.econstruct constr_decl (Some expr) in
333 let weight = Attributes.weight pcd_attributes in
334 let gen =
335 match pcd_args with
336 | Pcstr_tuple [] | Pcstr_record [] ->
337 G.pure ~loc @@ A.econstruct constr_decl None
338 | Pcstr_tuple xs ->
339 let tys = List.map (gen_from_type ~loc ~env) xs in
340 gen_tuple ~loc ~f:mk_constr tys
341 | Pcstr_record xs ->
342 let tys = List.map (fun x -> gen_from_type ~loc ~env x.pld_type) xs in
343 gen_record ~loc ~f:mk_constr ~gens:tys xs
344 in
345
346 A.pexp_tuple [ Option.value ~default:[%expr 1] weight; gen ]
347
348 and gen_from_variant ~loc ~env rws =
349 let (module A) = Ast_builder.make loc in
350 let is_rec = is_rec_row_field env in
351 let to_gen (row : row_field) : expression =
352 let w =
353 Attributes.weight row.prf_attributes |> Option.value ~default:[%expr 1]
354 in
355 let gen =
356 match row.prf_desc with
357 | Rinherit typ -> gen_from_type ~loc ~env typ
358 | Rtag (label, _, []) -> G.pure ~loc @@ A.pexp_variant label.txt None
359 | Rtag (label, _, typs) ->
360 let f expr = A.pexp_variant label.txt (Some expr) in
361 gen_tuple ~loc ~f (List.map (gen_from_type ~loc ~env) typs)
362 in
363 [%expr [%e w], [%e gen]]
364 in
365 let gen = gen_sized ~loc is_rec to_gen rws in
366 let typ_t = A.ptyp_constr (A.Located.mk @@ Lident env.curr_type) [] in
367 let typ_gen = A.Located.mk G.ty in
368 let typ = A.ptyp_constr typ_gen [ typ_t ] in
369 [%expr ([%e gen] : [%t typ])]
370
371 and gen_from_arrow ~loc ~env left right =
372 let rec observable = function
373 | [%type: unit] -> O.unit loc
374 | [%type: bool] -> O.bool loc
375 | [%type: int] -> O.int loc
376 | [%type: float] -> O.float loc
377 | [%type: string] -> O.string loc
378 | [%type: char] -> O.char loc
379 | [%type: [%t? typ] option] -> O.option ~loc (observable typ)
380 | [%type: [%t? typ] array] -> O.array ~loc (observable typ)
381 | [%type: [%t? typ] list] -> O.list ~loc (observable typ)
382 | { ptyp_desc = Ptyp_tuple xs; _ } ->
383 let obs = List.map observable xs in
384 Tuple.from_list obs |> Tuple.to_obs ~loc
385 | { ptyp_loc = loc; _ } ->
386 Ppxlib.Location.raise_errorf ~loc
387 "This type is not supported in ppx_deriving_qcheck"
388 in
389 let rec aux = function
390 | { ptyp_desc = Ptyp_arrow (_, x, xs); _ } ->
391 let res, xs = aux xs in
392 let obs = observable x in
393 (res, [%expr [%e obs] @-> [%e xs]])
394 | x -> (gen_from_type ~loc ~env x, [%expr o_nil])
395 in
396 let x, obs = aux right in
397 (* TODO: export this in qcheck_generators for https://github.com/c-cube/qcheck/issues/190 *)
398 let arb = [%expr QCheck.make [%e x]] in
399 [%expr
400 QCheck.fun_nary QCheck.Tuple.([%e observable left] @-> [%e obs]) [%e arb]
401 |> QCheck.gen]
402
403 (** [gen_from_type_declaration loc td] creates a generator from the type declaration.
404
405 It returns either `Recursive or `Normal.
406
407 - `Normal of expression:
408 The derived generator is not recursive, we return only the generator.
409
410 - `Recursive of expression * expression
411 The derived generator was recursive (i.e. val gen : n -> t Gen.t), we return
412 the sized generator version, and a normal generator using this last with
413 [Gen.sized].
414 *)
415 let gen_from_type_declaration ~loc ~env td =
416 let (module A) = Ast_builder.make loc in
417 let ty = env.Env.curr_type in
418 let is_rec = Env.is_rec env ty in
419
420 let args =
421 List.map
422 (fun (typ, _) ->
423 match typ.ptyp_desc with
424 | Ptyp_var s -> (pat ~loc s, name s |> A.evar)
425 | _ -> assert false)
426 td.ptype_params
427 in
428 let (args_pat, args_expr) = List.split args in
429
430 let gen =
431 match td.ptype_kind with
432 | Ptype_variant xs ->
433 let is_rec cd = is_rec_constr_decl env cd in
434 gen_sized ~loc is_rec (gen_from_constr ~loc ~env) xs
435 | Ptype_record xs ->
436 let gens = List.map (fun x -> gen_from_type ~loc ~env x.pld_type) xs in
437 gen_record ~loc ~gens xs
438 | _ ->
439 let typ = Option.get td.ptype_manifest in
440 gen_from_type ~loc ~env typ
441 in
442
443 let pat_gen = pat ~loc ty in
444 if not is_rec then
445 let gen = Args.curry_args ~loc args_pat gen in
446 `Normal [%stri let [%p pat_gen] = [%e gen]]
447 else
448 let args =
449 if is_n_used gen then args_pat @ [A.pvar "n"]
450 else args_pat @ [A.pvar "_n"]
451 in
452 let gen = Args.curry_args ~loc args gen in
453 let pat_gen_sized = pat ~loc ~sized:true ty in
454 let gen_sized = name ~sized:true ty |> A.evar in
455 let gen_normal =
456 Args.curry_args ~loc args_pat
457 (G.sized ~loc (Args.apply_args ~loc args_expr gen_sized))
458 in
459 `Recursive (
460 [%stri let rec [%p pat_gen_sized] = [%e gen]],
461 [%stri let [%p pat_gen] = [%e gen_normal]]
462 )
463
464 let mutually_recursive_gens ~loc gens =
465 let (module A) = Ast_builder.make loc in
466 let to_mutualize_gens =
467 List.map (function
468 | `Recursive (x, _) -> x
469 | `Normal x -> x) gens
470 in
471 let normal_gens =
472 List.filter_map (function
473 | `Recursive (_, x) -> Some x
474 | `Normal _ -> None) gens
475 in
476 let gens =
477 List.map (function
478 | [%stri let [%p? pat] = [%e? expr]]
479 | [%stri let rec [%p? pat] = [%e? expr]] ->
480 A.value_binding ~pat ~expr
481 | _ -> assert false) to_mutualize_gens
482 in
483 let mutual_gens = A.pstr_value Recursive gens in
484 mutual_gens :: normal_gens
485
486 (** [derive_gen ~loc xs] creates generators for type declaration in [xs]. *)
487 let derive_gen ~loc (xs : rec_flag * type_declaration list) : structure =
488 let open Env in
489 let add_if_rec env typ x =
490 if is_rec_type_decl env typ then
491 { env with rec_types = x :: env.rec_types}
492 else env
493 in
494 match xs with
495 | (_, [ x ]) ->
496 let typ_name = x.ptype_name.txt in
497 let env = { curr_type = typ_name; rec_types = []; curr_types = [typ_name] } in
498 let env = add_if_rec env x typ_name in
499 (match gen_from_type_declaration ~loc ~env x with
500 | `Recursive (gen_sized, gen) -> [gen_sized; gen]
501 | `Normal gen -> [gen])
502 | _, xs ->
503 let typ_names = List.map (fun x -> x.ptype_name.txt) xs in
504 let env = { curr_type = ""; rec_types = []; curr_types = typ_names } in
505 let env =
506 List.fold_left
507 (fun env x -> add_if_rec env x x.ptype_name.txt)
508 env xs
509 in
510 let gens =
511 List.map (fun x ->
512 let env = { env with curr_type = x.ptype_name.txt }in
513 gen_from_type_declaration ~loc ~env x) xs
514 in
515 mutually_recursive_gens ~loc gens
516
517 (** {2. Ppxlib machinery} *)
518
519 let create_gen ~ctxt (decls : rec_flag * type_declaration list) : structure =
520 let loc = Expansion_context.Deriver.derived_item_loc ctxt in
521 derive_gen ~loc decls
522
523 let gen_expander = Deriving.Generator.V2.make_noarg create_gen
524
525 let _ = Deriving.add "qcheck" ~str_type_decl:gen_expander
0 open Ppxlib
1
2 val derive_gen : loc:location -> rec_flag * type_declaration list -> structure
3 (** [derive_gen loc xs] derives a generator for each type_declaration in [xs] *)
0 open Ppxlib
1 module G = QCheck_generators
2 module O = G.Observable
3
4 (** {1. Tuple } *)
5
6 (** This module implements nested tuples based on QCheck tuples generators (or observables):
7 - [Gen.pair]
8 - [Gen.triple]
9 - [Gen.quad]
10
11 It can be used to nest large tuples in a generator.
12 - e.g.
13 {[
14 type t = int * int * int
15 ]}
16
17 Lets say QCheck does not have combinator to generate a triple. One has to write:
18
19 {[
20 let gen = QCheck.Gen.(map (fun ((x, y), z) -> (x, y, z) (pair (pair int int) int))
21 ]}
22
23 We copy this nesting mechanism with this module.
24 *)
25
26 type 'a t =
27 | Pair of 'a t * 'a t
28 | Triple of 'a * 'a * 'a
29 | Quad of 'a * 'a * 'a * 'a
30 | Elem of 'a
31
32 (** [from_list l] builds an {!'a t}, if len of [l] is greater than 4, the list
33 is split into a [Pair] of generators. *)
34 let rec from_list = function
35 | [ a; b; c; d ] -> Quad (a, b, c, d)
36 | [ a; b; c ] -> Triple (a, b, c)
37 | [ a; b ] -> Pair (Elem a, Elem b)
38 | [ a ] -> Elem a
39 | l ->
40 let n = List.length l / 2 in
41 let i = ref 0 in
42 let l1 =
43 List.filter
44 (fun _ ->
45 let x = !i in
46 i := x + 1;
47 x < n)
48 l
49 in
50 i := 0;
51 let l2 =
52 List.filter
53 (fun _ ->
54 let x = !i in
55 i := x + 1;
56 x >= n)
57 l
58 in
59 Pair (from_list l1, from_list l2)
60
61 let rec to_list = function
62 | Quad (a, b, c, d) -> [ a; b; c; d ]
63 | Triple (a, b, c) -> [ a; b; c ]
64 | Pair (a, b) -> to_list a @ to_list b
65 | Elem a -> [ a ]
66
67 (** [to_expr ~loc t] creates a tuple expression based on [t].
68 [t] is transformed to a list, and each element from the list becomes
69 a variable referencing a generator.
70
71 - e.g.
72 to_expr (Pair (_, _)) => (gen0, gen1)
73 *)
74 let to_expr ~loc t =
75 let l = to_list t in
76 let (module A) = Ast_builder.make loc in
77 List.mapi
78 (fun i _ ->
79 let s = Printf.sprintf "gen%d" i in
80 A.evar s)
81 l
82 |> A.pexp_tuple
83
84 (** [nest pair triple quad t] creates a generator expression for [t] using
85
86 - [pair] to combine Pair (_, _)
87 - [triple] to combine Triple (_, _, )
88 - [quad] to combine Quad (_, _, _, _)
89 *)
90 let rec nest ~pair ~triple ~quad = function
91 | Quad (a, b, c, d) -> quad a b c d
92 | Triple (a, b, c) -> triple a b c
93 | Pair (a, b) ->
94 pair
95 (nest ~pair ~triple ~quad a)
96 (nest ~pair ~triple ~quad b)
97 | Elem a -> a
98
99 (** [to_gen t] creates a Gen.t with generators' combinators *)
100 let to_gen ~loc t =
101 nest ~pair:(G.pair ~loc) ~triple:(G.triple ~loc) ~quad:(G.quad ~loc) t
102
103 (** [to_obs t] creates a Obs.t with obsersvables' combinators *)
104 let to_obs ~loc t =
105 nest ~pair:(O.pair ~loc) ~triple:(O.triple ~loc) ~quad:(O.quad ~loc) t
106
107 let to_pat ~loc t =
108 let fresh_id =
109 let id = ref 0 in
110 fun () ->
111 let x = !id in
112 let () = id := x + 1 in
113 Printf.sprintf "gen%d" x
114 in
115 let (module A) = Ast_builder.make loc in
116 let rec aux = function
117 | Quad (_, _, _, _) ->
118 let a = A.pvar @@ fresh_id () in
119 let b = A.pvar @@ fresh_id () in
120 let c = A.pvar @@ fresh_id () in
121 let d = A.pvar @@ fresh_id () in
122 [%pat? [%p a], [%p b], [%p c], [%p d]]
123 | Triple (_, _, _) ->
124 let a = A.pvar @@ fresh_id () in
125 let b = A.pvar @@ fresh_id () in
126 let c = A.pvar @@ fresh_id () in
127 [%pat? [%p a], [%p b], [%p c]]
128 | Pair (a, b) ->
129 let a = aux a in
130 let b = aux b in
131 [%pat? [%p a], [%p b]]
132 | Elem _ -> A.pvar @@ fresh_id ()
133 in
134 aux t
218218 | None -> Printf.fprintf out "<no printer provided>"
219219 | Some print -> Printf.fprintf out "%s" (print x)
220220
221 let debug_shrinking_choices_aux ~colors out name i cell x =
221 let debug_shrinking_choices ~colors ~out ~name cell ~step x =
222222 Printf.fprintf out "\n~~~ %a %s\n\n"
223223 (Color.pp_str_c ~colors `Cyan) "Shrink" (String.make 69 '~');
224224 Printf.fprintf out
225225 "Test %s successfully shrunk counter example (step %d) to:\n\n%a\n%!"
226 name i
226 name step
227227 (debug_shrinking_counter_example cell) x
228
229 let debug_shrinking_choices
230 ~colors ~debug_shrink ~debug_shrink_list name cell i x =
231 match debug_shrink with
232 | None -> ()
233 | Some out ->
234 begin match debug_shrink_list with
235 | [] ->
236 debug_shrinking_choices_aux ~colors out name i cell x
237 | l when List.mem name l ->
238 debug_shrinking_choices_aux ~colors out name i cell x
239 | _ -> ()
240 end
241
242228
243229 let default_handler
244230 ~colors ~debug_shrink ~debug_shrink_list
255241 in
256242 (* debug shrinking choices *)
257243 begin match r with
258 | QCheck2.Test.Shrunk (i, x) ->
259 debug_shrinking_choices
260 ~colors ~debug_shrink ~debug_shrink_list name cell i x
244 | QCheck2.Test.Shrunk (step, x) ->
245 begin match debug_shrink with
246 | None -> ()
247 | Some out ->
248 let go =
249 match debug_shrink_list with
250 | [] -> true
251 | test_list -> List.mem name test_list
252 in
253 if not go then ()
254 else
255 debug_shrinking_choices
256 ~colors ~out ~name cell ~step x
257 end
261258 | _ ->
262259 ()
263260 end;
8686 val default_handler : handler_gen
8787 (** The default handler used. *)
8888
89 val debug_shrinking_choices:
90 colors:bool ->
91 out:out_channel ->
92 name:string -> 'a QCheck2.Test.cell -> step:int -> 'a -> unit
93 (** The function used by the default handler to debug shrinking choices.
94 This can be useful to outside users trying to reproduce some of the
95 base-runner behavior.
96
97 @since 0.19
98 *)
8999
90100 (** {2 Run a Suite of Tests and Get Results} *)
91101
6464 ]
6565 (Gen.int_bound 120) (fun _ -> true)
6666
67 let retries =
68 Test.make ~name:"with shrinking retries" ~retries:10 ~print:Print.int
69 Gen.small_nat (fun i -> Printf.printf "%i %!" i; i mod 3 <> 1)
70
6771 let bad_assume_warn =
6872 Test.make ~name:"WARN_unlikely_precond" ~count:2_000 ~print:Print.int
6973 Gen.int
7882 (fun x ->
7983 QCheck.assume (x mod 100 = 1);
8084 true)
85
86 let tests = [
87 passing;
88 failing;
89 error;
90 collect;
91 stats;
92 retries;
93 bad_assume_warn;
94 bad_assume_fail;
95 ]
96
8197 end
8298
8399 (* positive tests of the various generators *)
129145 ~name:"tree_rev_is_involutive"
130146 IntTree.gen_tree
131147 (fun tree -> IntTree.(rev_tree (rev_tree tree)) = tree)
148
149 let test_tup2 =
150 Test.make ~count:10
151 ~name:"forall x in (0, 1): x = (0, 1)"
152 Gen.(tup2 (pure 0) (pure 1))
153 (fun x -> x = (0, 1))
154
155 let test_tup3 =
156 Test.make ~count:10
157 ~name:"forall x in (0, 1, 2): x = (0, 1, 2)"
158 Gen.(tup3 (pure 0) (pure 1) (pure 2))
159 (fun x -> x = (0, 1, 2))
160
161 let test_tup4 =
162 Test.make ~count:10
163 ~name:"forall x in (0, 1, 2, 3): x = (0, 1, 2, 3)"
164 Gen.(tup4 (pure 0) (pure 1) (pure 2) (pure 3))
165 (fun x -> x = (0, 1, 2, 3))
166
167 let test_tup5 =
168 Test.make ~count:10
169 ~name:"forall x in (0, 1, 2, 3, 4): x = (0, 1, 2, 3, 4)"
170 Gen.(tup5 (pure 0) (pure 1) (pure 2) (pure 3) (pure 4))
171 (fun x -> x = (0, 1, 2, 3, 4))
172
173 let test_tup6 =
174 Test.make ~count:10
175 ~name:"forall x in (0, 1, 2, 3, 4, 5): x = (0, 1, 2, 3, 4, 5)"
176 Gen.(tup6 (pure 0) (pure 1) (pure 2) (pure 3) (pure 4) (pure 5))
177 (fun x -> x = (0, 1, 2, 3, 4, 5))
178
179 let test_tup7 =
180 Test.make ~count:10
181 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6): x = (0, 1, 2, 3, 4, 5, 6)"
182 Gen.(tup7
183 (pure 0) (pure 1) (pure 2) (pure 3) (pure 4)
184 (pure 5) (pure 6))
185 (fun x -> x = (0, 1, 2, 3, 4, 5, 6))
186
187 let test_tup8 =
188 Test.make ~count:10
189 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6, 7): x = (0, 1, 2, 3, 4, 5, 6, 7)"
190 Gen.(tup8
191 (pure 0) (pure 1) (pure 2) (pure 3) (pure 4)
192 (pure 5) (pure 6) (pure 7))
193 (fun x -> x = (0, 1, 2, 3, 4, 5, 6, 7))
194
195 let test_tup9 =
196 Test.make ~count:10
197 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6, 7, 8): x = (0, 1, 2, 3, 4, 5, 6, 7, 8)"
198 Gen.(tup9
199 (pure 0) (pure 1) (pure 2) (pure 3) (pure 4)
200 (pure 5) (pure 6) (pure 7) (pure 8))
201 (fun x -> x = (0, 1, 2, 3, 4, 5, 6, 7, 8))
202
203 let tests = [
204 char_dist_issue_23;
205 char_test;
206 nat_test;
207 string_test;
208 list_test;
209 list_repeat_test;
210 array_repeat_test;
211 passing_tree_rev;
212 test_tup2;
213 test_tup3;
214 test_tup4;
215 test_tup5;
216 test_tup6;
217 test_tup7;
218 test_tup8;
219 test_tup9;
220 ]
132221 end
133222
134223 (* negative tests that exercise shrinking behaviour *)
235324 Test.make ~name:"tree contains only 42" ~print:IntTree.print_tree
236325 IntTree.gen_tree
237326 (fun tree -> IntTree.contains_only_n tree 42)
327
328 let test_tup2 =
329 Test.make
330 ~print:Print.(tup2 int int)
331 ~name:"forall (a, b) in nat: a < b"
332 Gen.(tup2 small_int small_int)
333 (fun (a, b) -> a < b)
334
335 let test_tup3 =
336 Test.make
337 ~print:Print.(tup3 int int int)
338 ~name:"forall (a, b, c) in nat: a < b < c"
339 Gen.(tup3 small_int small_int small_int)
340 (fun (a, b, c) -> a < b && b < c)
341
342 let test_tup4 =
343 Test.make
344 ~print:Print.(tup4 int int int int)
345 ~name:"forall (a, b, c, d) in nat: a < b < c < d"
346 Gen.(tup4 small_int small_int small_int small_int)
347 (fun (a, b, c, d) -> a < b && b < c && c < d)
348
349 let test_tup5 =
350 Test.make
351 ~print:Print.(tup5 int int int int int)
352 ~name:"forall (a, b, c, d, e) in nat: a < b < c < d < e"
353 Gen.(tup5 small_int small_int small_int small_int small_int)
354 (fun (a, b, c, d, e) -> a < b && b < c && c < d && d < e)
355
356 let test_tup6 =
357 Test.make
358 ~print:Print.(tup6 int int int int int int)
359 ~name:"forall (a, b, c, d, e, f) in nat: a < b < c < d < e < f"
360 Gen.(tup6 small_int small_int small_int small_int small_int small_int)
361 (fun (a, b, c, d, e, f) -> a < b && b < c && c < d && d < e && e < f)
362
363 let test_tup7 =
364 Test.make
365 ~print:Print.(tup7 int int int int int int int)
366 ~name:"forall (a, b, c, d, e, f, g) in nat: a < b < c < d < e < f < g"
367 Gen.(tup7 small_int small_int small_int small_int small_int small_int small_int)
368 (fun (a, b, c, d, e, f, g) -> a < b && b < c && c < d && d < e && e < f && f < g)
369
370 let test_tup8 =
371 Test.make
372 ~print:Print.(tup8 int int int int int int int int)
373 ~name:"forall (a, b, c, d, e, f, g, h) in nat: a < b < c < d < e < f < g < h"
374 Gen.(tup8 small_int small_int small_int small_int small_int small_int small_int small_int)
375 (fun (a, b, c, d, e, f, g, h) -> a < b && b < c && c < d && d < e && e < f && f < g && g < h)
376
377 let test_tup9 =
378 Test.make
379 ~print:Print.(tup9 int int int int int int int int int)
380 ~name:"forall (a, b, c, d, e, f, g, h, i) in nat: a < b < c < d < e < f < g < h < i"
381 Gen.(tup9 small_int small_int small_int small_int small_int small_int small_int small_int small_int)
382 (fun (a, b, c, d, e, f, g, h, i) -> a < b && b < c && c < d && d < e && e < f && f < g && g < h && h < i)
383
384 let tests = [
385 (*test_fac_issue59;*)
386 big_bound_issue59;
387 long_shrink;
388 ints_arent_0_mod_3;
389 ints_are_0;
390 ints_smaller_209609;
391 nats_smaller_5001;
392 char_is_never_abcdef;
393 strings_are_empty;
394 string_never_has_000_char;
395 string_never_has_255_char;
396 lists_are_empty_issue_64;
397 list_shorter_10;
398 list_shorter_432;
399 list_shorter_4332;
400 list_equal_dupl;
401 list_unique_elems;
402 tree_contains_only_42;
403 test_tup2;
404 test_tup3;
405 test_tup4;
406 test_tup5;
407 test_tup6;
408 test_tup7;
409 test_tup8;
410 test_tup9;
411 ]
238412 end
239413
240414 (* tests function generator and shrinker *)
312486 let f = Fn.apply f in
313487 List.fold_left f acc (is @ js)
314488 = List.fold_left f (List.fold_left f acc is) is) (*Typo*)
489
490 let tests = [
491 fail_pred_map_commute;
492 fail_pred_strings;
493 prop_foldleft_foldright;
494 prop_foldleft_foldright_uncurry;
495 prop_foldleft_foldright_uncurry_funlast;
496 fold_left_test;
497 ]
315498 end
316499
317500 (* tests of (inner) find_example(_gen) behaviour *)
336519 let find_ex_uncaught_issue_99_2_succeed =
337520 Test.make ~name:"should_succeed_#99_2" ~count:10
338521 Gen.int (fun i -> i <= max_int)
522
523 let tests = [
524 find_ex;
525 find_ex_uncaught_issue_99_1_fail;
526 find_ex_uncaught_issue_99_2_succeed;
527 ]
339528 end
340529
341530 (* tests of statistics and histogram display *)
400589 let tree_depth_test =
401590 let depth = ("depth", IntTree.depth) in
402591 Test.make ~name:"tree's depth" ~count:1000 ~stats:[depth] IntTree.gen_tree (fun _ -> true)
592
593 let tests =
594 [
595 bool_dist;
596 char_dist;
597 tree_depth_test
598 ]
599 @ string_len_tests
600 @ list_len_tests
601 @ array_len_tests
602 @ int_dist_tests
603
403604 end
404605
405606 (* Calling runners *)
406607
407608 let () = QCheck_base_runner.set_seed 1234
408609 let _ =
409 QCheck_base_runner.run_tests ~colors:false ([
410 Overall.passing;
411 Overall.failing;
412 Overall.error;
413 Overall.collect;
414 Overall.stats;
415 Overall.bad_assume_warn;
416 Overall.bad_assume_fail;
417 Generator.char_dist_issue_23;
418 Generator.char_test;
419 Generator.nat_test;
420 Generator.string_test;
421 Generator.list_test;
422 Generator.list_repeat_test;
423 Generator.array_repeat_test;
424 Generator.passing_tree_rev;
425 (*Shrink.test_fac_issue59;*)
426 Shrink.big_bound_issue59;
427 Shrink.long_shrink;
428 Shrink.ints_arent_0_mod_3;
429 Shrink.ints_are_0;
430 Shrink.ints_smaller_209609;
431 Shrink.nats_smaller_5001;
432 Shrink.char_is_never_abcdef;
433 Shrink.strings_are_empty;
434 Shrink.string_never_has_000_char;
435 Shrink.string_never_has_255_char;
436 Shrink.lists_are_empty_issue_64;
437 Shrink.list_shorter_10;
438 Shrink.list_shorter_432;
439 Shrink.list_shorter_4332;
440 Shrink.list_equal_dupl;
441 Shrink.list_unique_elems;
442 Shrink.tree_contains_only_42;
443 Function.fail_pred_map_commute;
444 Function.fail_pred_strings;
445 Function.prop_foldleft_foldright;
446 Function.prop_foldleft_foldright_uncurry;
447 Function.prop_foldleft_foldright_uncurry_funlast;
448 Function.fold_left_test;
449 FindExample.find_ex;
450 FindExample.find_ex_uncaught_issue_99_1_fail;
451 FindExample.find_ex_uncaught_issue_99_2_succeed;
452 Stats.bool_dist;
453 Stats.char_dist;
454 Stats.tree_depth_test ]
455 @ Stats.string_len_tests
456 @ Stats.list_len_tests
457 @ Stats.array_len_tests
458 @ Stats.int_dist_tests)
610 QCheck_base_runner.run_tests ~colors:false (
611 Overall.tests @
612 Generator.tests @
613 Shrink.tests @
614 Function.tests @
615 FindExample.tests @
616 Stats.tests)
459617
460618 let () = QCheck_base_runner.set_seed 153870556
461619 let _ = QCheck_base_runner.run_tests ~colors:false [Stats.int_dist_empty_bucket]
6666 ])
6767 (fun _ -> true)
6868
69 let retries =
70 Test.make ~name:"with shrinking retries" ~retries:10
71 small_nat (fun i -> Printf.printf "%i %!" i; i mod 3 <> 1)
72
6973 let bad_assume_warn =
7074 Test.make ~name:"WARN_unlikely_precond" ~count:2_000
7175 int
8084 (fun x ->
8185 QCheck.assume (x mod 100 = 1);
8286 true)
87
88 let tests = [
89 passing;
90 failing;
91 error;
92 collect;
93 stats;
94 retries;
95 bad_assume_warn;
96 bad_assume_fail;
97 ]
8398 end
8499
85100 (* positive tests of the various generators
211226 Array.length arr = m
212227 && Array.for_all (fun k -> 0 < k) arr
213228 && Array.fold_left (+) 0 arr = n)
229
230 let test_tup2 =
231 Test.make ~count:10
232 ~name:"forall x in (0, 1): x = (0, 1)"
233 (tup2 (always 0) (always 1))
234 (fun x -> x = (0, 1))
235
236 let test_tup3 =
237 Test.make ~count:10
238 ~name:"forall x in (0, 1, 2): x = (0, 1, 2)"
239 (tup3 (always 0) (always 1) (always 2))
240 (fun x -> x = (0, 1, 2))
241
242 let test_tup4 =
243 Test.make ~count:10
244 ~name:"forall x in (0, 1, 2, 3): x = (0, 1, 2, 3)"
245 (tup4 (always 0) (always 1) (always 2) (always 3))
246 (fun x -> x = (0, 1, 2, 3))
247
248 let test_tup5 =
249 Test.make ~count:10
250 ~name:"forall x in (0, 1, 2, 3, 4): x = (0, 1, 2, 3, 4)"
251 (tup5 (always 0) (always 1) (always 2) (always 3) (always 4))
252 (fun x -> x = (0, 1, 2, 3, 4))
253
254 let test_tup6 =
255 Test.make ~count:10
256 ~name:"forall x in (0, 1, 2, 3, 4, 5): x = (0, 1, 2, 3, 4, 5)"
257 (tup6 (always 0) (always 1) (always 2) (always 3) (always 4) (always 5))
258 (fun x -> x = (0, 1, 2, 3, 4, 5))
259
260 let test_tup7 =
261 Test.make ~count:10
262 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6): x = (0, 1, 2, 3, 4, 5, 6)"
263 (tup7
264 (always 0) (always 1) (always 2) (always 3) (always 4)
265 (always 5) (always 6))
266 (fun x -> x = (0, 1, 2, 3, 4, 5, 6))
267
268 let test_tup8 =
269 Test.make ~count:10
270 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6, 7): x = (0, 1, 2, 3, 4, 5, 6, 7)"
271 (tup8
272 (always 0) (always 1) (always 2) (always 3) (always 4)
273 (always 5) (always 6) (always 7))
274 (fun x -> x = (0, 1, 2, 3, 4, 5, 6, 7))
275
276 let test_tup9 =
277 Test.make ~count:10
278 ~name:"forall x in (0, 1, 2, 3, 4, 5, 6, 7, 8): x = (0, 1, 2, 3, 4, 5, 6, 7, 8)"
279 (tup9
280 (always 0) (always 1) (always 2) (always 3) (always 4)
281 (always 5) (always 6) (always 7) (always 8))
282 (fun x -> x = (0, 1, 2, 3, 4, 5, 6, 7, 8))
283
284 let tests = [
285 char_dist_issue_23;
286 char_test;
287 nat_test;
288 string_test;
289 list_test;
290 list_repeat_test;
291 array_repeat_test;
292 passing_tree_rev;
293 nat_split2_spec;
294 pos_split2_spec;
295 range_subset_spec;
296 nat_split_n_way;
297 nat_split_smaller;
298 pos_split;
299 test_tup2;
300 test_tup3;
301 test_tup4;
302 test_tup5;
303 test_tup6;
304 test_tup7;
305 test_tup8;
306 test_tup9;
307 ]
214308 end
215309
216310 (* negative tests that exercise shrinking behaviour *)
310404 (list small_int)
311405 (fun xs -> let ys = List.sort_uniq Int.compare xs in
312406 print_list xs; List.length xs = List.length ys)
407
408 let test_tup2 =
409 Test.make
410 ~name:"forall (a, b) in nat: a < b"
411 (tup2 small_int small_int)
412 (fun (a, b) -> a < b)
413
414 let test_tup3 =
415 Test.make
416 ~name:"forall (a, b, c) in nat: a < b < c"
417 (tup3 small_int small_int small_int)
418 (fun (a, b, c) -> a < b && b < c)
419
420 let test_tup4 =
421 Test.make
422 ~name:"forall (a, b, c, d) in nat: a < b < c < d"
423 (tup4 small_int small_int small_int small_int)
424 (fun (a, b, c, d) -> a < b && b < c && c < d)
425
426 let test_tup5 =
427 Test.make
428 ~name:"forall (a, b, c, d, e) in nat: a < b < c < d < e"
429 (tup5 small_int small_int small_int small_int small_int)
430 (fun (a, b, c, d, e) -> a < b && b < c && c < d && d < e)
431
432 let test_tup6 =
433 Test.make
434 ~name:"forall (a, b, c, d, e, f) in nat: a < b < c < d < e < f"
435 (tup6 small_int small_int small_int small_int small_int small_int)
436 (fun (a, b, c, d, e, f) -> a < b && b < c && c < d && d < e && e < f)
437
438 let test_tup7 =
439 Test.make
440 ~name:"forall (a, b, c, d, e, f, g) in nat: a < b < c < d < e < f < g"
441 (tup7 small_int small_int small_int small_int small_int small_int small_int)
442 (fun (a, b, c, d, e, f, g) -> a < b && b < c && c < d && d < e && e < f && f < g)
443
444 let test_tup8 =
445 Test.make
446 ~name:"forall (a, b, c, d, e, f, g, h) in nat: a < b < c < d < e < f < g < h"
447 (tup8 small_int small_int small_int small_int small_int small_int small_int small_int)
448 (fun (a, b, c, d, e, f, g, h) -> a < b && b < c && c < d && d < e && e < f && f < g && g < h)
449
450 let test_tup9 =
451 Test.make
452 ~name:"forall (a, b, c, d, e, f, g, h, i) in nat: a < b < c < d < e < f < g < h < i"
453 (tup9 small_int small_int small_int small_int small_int small_int small_int small_int small_int)
454 (fun (a, b, c, d, e, f, g, h, i) -> a < b && b < c && c < d && d < e && e < f && f < g && g < h && h < i)
455
456 let tests = [
457 (*test_fac_issue59;*)
458 big_bound_issue59;
459 long_shrink;
460 ints_arent_0_mod_3;
461 ints_are_0;
462 ints_smaller_209609;
463 nats_smaller_5001;
464 char_is_never_abcdef;
465 strings_are_empty;
466 string_never_has_000_char;
467 string_never_has_255_char;
468 lists_are_empty_issue_64;
469 list_shorter_10;
470 list_shorter_432;
471 list_shorter_4332;
472 list_equal_dupl;
473 list_unique_elems;
474 test_tup2;
475 test_tup3;
476 test_tup4;
477 test_tup5;
478 test_tup6;
479 test_tup7;
480 test_tup8;
481 test_tup9;
482 ]
313483 end
314484
315485 (* tests function generator and shrinker *)
383553 let f = Fn.apply f in
384554 List.fold_left f acc (is @ js)
385555 = List.fold_left f (List.fold_left f acc is) is) (*Typo*)
556
557 let tests = [
558 fail_pred_map_commute;
559 fail_pred_strings;
560 prop_foldleft_foldright;
561 prop_foldleft_foldright_uncurry;
562 prop_foldleft_foldright_uncurry_funlast;
563 fold_left_test;
564 ]
386565 end
387566
388567 (* tests of (inner) find_example(_gen) behaviour *)
406585 let find_ex_uncaught_issue_99_2_succeed =
407586 Test.make ~name:"should_succeed_#99_2" ~count:10
408587 int (fun i -> i <= max_int)
588
589 let tests = [
590 find_ex;
591 find_ex_uncaught_issue_99_1_fail;
592 find_ex_uncaught_issue_99_2_succeed;
593 ]
409594 end
410595
411596 (* tests of statistics and histogram display *)
474659 Test.make ~name:"range_subset_spec" ~count:5_000
475660 (add_stat ("dist", fun a -> a.(0)) (make (Gen.range_subset ~size:1 0 20)))
476661 (fun a -> Array.length a = 1)
662
663 let tests =
664 [
665 bool_dist;
666 char_dist;
667 tree_depth_test;
668 range_subset_test
669 ]
670 @ string_len_tests
671 @ list_len_tests
672 @ array_len_tests
673 @ int_dist_tests
477674 end
478675
479676 (* Calling runners *)
480677
481678 let () = QCheck_base_runner.set_seed 1234
482679 let _ =
483 QCheck_base_runner.run_tests ~colors:false ([
484 Overall.passing;
485 Overall.failing;
486 Overall.error;
487 Overall.collect;
488 Overall.stats;
489 Overall.bad_assume_warn;
490 Overall.bad_assume_fail;
491 Generator.char_dist_issue_23;
492 Generator.char_test;
493 Generator.nat_test;
494 Generator.string_test;
495 Generator.list_test;
496 Generator.list_repeat_test;
497 Generator.array_repeat_test;
498 Generator.passing_tree_rev;
499 Generator.nat_split2_spec;
500 Generator.pos_split2_spec;
501 Generator.range_subset_spec;
502 Generator.nat_split_n_way;
503 Generator.nat_split_smaller;
504 Generator.pos_split;
505 (*Shrink.test_fac_issue59;*)
506 Shrink.big_bound_issue59;
507 Shrink.long_shrink;
508 Shrink.ints_arent_0_mod_3;
509 Shrink.ints_are_0;
510 Shrink.ints_smaller_209609;
511 Shrink.nats_smaller_5001;
512 Shrink.char_is_never_abcdef;
513 Shrink.strings_are_empty;
514 Shrink.string_never_has_000_char;
515 Shrink.string_never_has_255_char;
516 Shrink.lists_are_empty_issue_64;
517 Shrink.list_shorter_10;
518 Shrink.list_shorter_432;
519 Shrink.list_shorter_4332;
520 Shrink.list_equal_dupl;
521 Shrink.list_unique_elems;
522 Function.fail_pred_map_commute;
523 Function.fail_pred_strings;
524 Function.prop_foldleft_foldright;
525 Function.prop_foldleft_foldright_uncurry;
526 Function.prop_foldleft_foldright_uncurry_funlast;
527 Function.fold_left_test;
528 FindExample.find_ex;
529 FindExample.find_ex_uncaught_issue_99_1_fail;
530 FindExample.find_ex_uncaught_issue_99_2_succeed;
531 Stats.bool_dist;
532 Stats.char_dist;
533 Stats.tree_depth_test;
534 Stats.range_subset_test]
535 @ Stats.string_len_tests
536 @ Stats.list_len_tests
537 @ Stats.array_len_tests
538 @ Stats.int_dist_tests)
680 QCheck_base_runner.run_tests ~colors:false (
681 Overall.tests @
682 Generator.tests @
683 Shrink.tests @
684 Function.tests @
685 FindExample.tests @
686 Stats.tests)
539687
540688 let () = QCheck_base_runner.set_seed 153870556
541689 let _ = QCheck_base_runner.run_tests ~colors:false [Stats.int_dist_empty_bucket]
00 random seed: 1234
1 2724675603984413065
1 50 7 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 2724675603984413065
22 0
33 1362337801992206532
44 0
220220 110..115: ####################################################### 9
221221 116..121: ################## 3
222222
223 --- Failure --------------------------------------------------------------------
224
225 Test with shrinking retries failed (0 shrink steps):
226
227 7
228
223229 !!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
224230
225231 Warning for test WARN_unlikely_precond:
344350 Test tree contains only 42 failed (2 shrink steps):
345351
346352 Leaf 0
353
354 --- Failure --------------------------------------------------------------------
355
356 Test forall (a, b) in nat: a < b failed (6 shrink steps):
357
358 (0, 0)
359
360 --- Failure --------------------------------------------------------------------
361
362 Test forall (a, b, c) in nat: a < b < c failed (3 shrink steps):
363
364 (0, 0, 0)
365
366 --- Failure --------------------------------------------------------------------
367
368 Test forall (a, b, c, d) in nat: a < b < c < d failed (4 shrink steps):
369
370 (0, 0, 0, 0)
371
372 --- Failure --------------------------------------------------------------------
373
374 Test forall (a, b, c, d, e) in nat: a < b < c < d < e failed (5 shrink steps):
375
376 (0, 0, 0, 0, 0)
377
378 --- Failure --------------------------------------------------------------------
379
380 Test forall (a, b, c, d, e, f) in nat: a < b < c < d < e < f failed (6 shrink steps):
381
382 (0, 0, 0, 0, 0, 0)
383
384 --- Failure --------------------------------------------------------------------
385
386 Test forall (a, b, c, d, e, f, g) in nat: a < b < c < d < e < f < g failed (7 shrink steps):
387
388 (0, 0, 0, 0, 0, 0, 0)
389
390 --- Failure --------------------------------------------------------------------
391
392 Test forall (a, b, c, d, e, f, g, h) in nat: a < b < c < d < e < f < g < h failed (8 shrink steps):
393
394 (0, 0, 0, 0, 0, 0, 0, 0)
395
396 --- Failure --------------------------------------------------------------------
397
398 Test forall (a, b, c, d, e, f, g, h, i) in nat: a < b < c < d < e < f < g < h < i failed (9 shrink steps):
399
400 (0, 0, 0, 0, 0, 0, 0, 0, 0)
347401
348402 --- Failure --------------------------------------------------------------------
349403
933987 4150517416584649600.. 4611686018427387903: ################# 189
934988 ================================================================================
935989 1 warning(s)
936 failure (27 tests failed, 1 tests errored, ran 67 tests)
990 failure (36 tests failed, 1 tests errored, ran 84 tests)
937991 random seed: 153870556
938992
939993 +++ Stats for int_dist_empty_bucket ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00 random seed: 1234
1 2724675603984413065
1 50 7 4 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 2724675603984413065
22 1362337801992206533
33 681168900996103267
44 340584450498051634
155155 110..115: ####################################################### 9
156156 116..121: ################## 3
157157
158 --- Failure --------------------------------------------------------------------
159
160 Test with shrinking retries failed (1 shrink steps):
161
162 4
163
158164 !!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
159165
160166 Warning for test WARN_unlikely_precond:
273279 Test lists have unique elems failed (7 shrink steps):
274280
275281 [7; 7]
282
283 --- Failure --------------------------------------------------------------------
284
285 Test forall (a, b) in nat: a < b failed (13 shrink steps):
286
287 (0, 0)
288
289 --- Failure --------------------------------------------------------------------
290
291 Test forall (a, b, c) in nat: a < b < c failed (15 shrink steps):
292
293 (0, 0, 0)
294
295 --- Failure --------------------------------------------------------------------
296
297 Test forall (a, b, c, d) in nat: a < b < c < d failed (23 shrink steps):
298
299 (0, 0, 0, 0)
300
301 --- Failure --------------------------------------------------------------------
302
303 Test forall (a, b, c, d, e) in nat: a < b < c < d < e failed (28 shrink steps):
304
305 (0, 0, 0, 0, 0)
306
307 --- Failure --------------------------------------------------------------------
308
309 Test forall (a, b, c, d, e, f) in nat: a < b < c < d < e < f failed (30 shrink steps):
310
311 (0, 0, 0, 0, 0, 0)
312
313 --- Failure --------------------------------------------------------------------
314
315 Test forall (a, b, c, d, e, f, g) in nat: a < b < c < d < e < f < g failed (31 shrink steps):
316
317 (0, 0, 0, 0, 0, 0, 0)
318
319 --- Failure --------------------------------------------------------------------
320
321 Test forall (a, b, c, d, e, f, g, h) in nat: a < b < c < d < e < f < g < h failed (35 shrink steps):
322
323 (0, 0, 0, 0, 0, 0, 0, 0)
324
325 --- Failure --------------------------------------------------------------------
326
327 Test forall (a, b, c, d, e, f, g, h, i) in nat: a < b < c < d < e < f < g < h < i failed (42 shrink steps):
328
329 (0, 0, 0, 0, 0, 0, 0, 0, 0)
276330
277331 --- Failure --------------------------------------------------------------------
278332
888942 4150517416584649600.. 4611686018427387903: ################# 189
889943 ================================================================================
890944 1 warning(s)
891 failure (26 tests failed, 1 tests errored, ran 73 tests)
945 failure (35 tests failed, 1 tests errored, ran 90 tests)
892946 random seed: 153870556
893947
894948 +++ Stats for int_dist_empty_bucket ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0 (tests
1 (names
2 test_textual
3 test_primitives
4 test_qualified_names
5 test_recursive
6 test_tuple
7 test_variants
8 test_record)
9 (libraries qcheck-alcotest ppxlib ppx_deriving_qcheck qcheck)
10 (preprocess (pps ppxlib.metaquot ppx_deriving_qcheck)))
0 open QCheck
1
2 (** {1. Helpers} *)
3
4 let seed = [| 42 |]
5
6 let generate gen = Gen.generate ~n:20 ~rand:(Random.State.make seed) gen
7
8 (** [test_compare msg eq gen_ref gen_cand] will generate with the same seed
9 [gen_ref] and [gen_cand], and test with Alcotest that both generators
10 generates the same values. *)
11 let test_compare ~msg ~eq gen_ref gen_candidate =
12 let expected = generate gen_ref in
13 let actual = generate gen_candidate in
14 Alcotest.(check (list eq)) msg expected actual
0 open QCheck
1 open Helpers
2
3 (** {1. Test primitives derivation} *)
4
5 (** {2. Tests} *)
6
7 type int' = int [@@deriving qcheck]
8
9 let test_int () =
10 test_compare ~msg:"Gen.int <=> deriving int" ~eq:Alcotest.int Gen.int gen_int'
11
12 type unit' = unit [@@deriving qcheck]
13
14 (* Pretty useless though, but, meh *)
15 let test_unit () =
16 test_compare ~msg:"Gen.unit <=> deriving unit" ~eq:Alcotest.unit Gen.unit gen_unit'
17
18 type string' = string [@@deriving qcheck]
19
20 let test_string () =
21 test_compare ~msg:"Gen.string <=> deriving string" ~eq:Alcotest.string Gen.string gen_string'
22
23 type char' = char [@@deriving qcheck]
24
25 let test_char () =
26 test_compare ~msg:"Gen.char <=> deriving char" ~eq:Alcotest.char Gen.char gen_char'
27
28 type bool' = bool [@@deriving qcheck]
29
30 let test_bool () =
31 test_compare ~msg:"Gen.bool <=> deriving bool" ~eq:Alcotest.bool Gen.bool gen_bool'
32
33 type float' = float [@@deriving qcheck]
34
35 let test_float () =
36 test_compare ~msg:"Gen.float <=> deriving float" ~eq:(Alcotest.float 0.) Gen.float gen_float'
37
38 type int32' = int32 [@@deriving qcheck]
39
40 let test_int32 () =
41 test_compare ~msg:"Gen.int32 <=> deriving int32" ~eq:Alcotest.int32 Gen.ui32 gen_int32'
42
43 type int64' = int64 [@@deriving qcheck]
44
45 let test_int64 () =
46 test_compare ~msg:"Gen.int64 <=> deriving int64" ~eq:Alcotest.int64 Gen.ui64 gen_int64'
47
48 type 'a option' = 'a option [@@deriving qcheck]
49
50 let test_option () =
51 let zero = Gen.pure 0 in
52 test_compare ~msg:"Gen.opt <=> deriving opt"
53 ~eq:Alcotest.(option int)
54 (Gen.opt zero) (gen_option' zero)
55
56 type 'a array' = 'a array [@@deriving qcheck]
57
58 let test_array () =
59 let zero = Gen.pure 0 in
60 test_compare ~msg:"Gen.array <=> deriving array"
61 ~eq:Alcotest.(array int)
62 (Gen.array zero) (gen_array' zero)
63
64 type 'a list' = 'a list [@@deriving qcheck]
65
66 let test_list () =
67 let zero = Gen.pure 0 in
68 test_compare ~msg:"Gen.list <=> deriving list"
69 ~eq:Alcotest.(list int)
70 (Gen.list zero) (gen_list' zero)
71
72 (** {2. Execute tests} *)
73
74 let () = Alcotest.run "Test_Primitives"
75 [("Primitives",
76 Alcotest.[
77 test_case "test_int" `Quick test_int;
78 test_case "test_unit" `Quick test_unit;
79 test_case "test_string" `Quick test_string;
80 test_case "test_char" `Quick test_char;
81 test_case "test_bool" `Quick test_bool;
82 test_case "test_float" `Quick test_float;
83 test_case "test_int32" `Quick test_int32;
84 test_case "test_int64" `Quick test_int64;
85 test_case "test_option" `Quick test_option;
86 test_case "test_array" `Quick test_array;
87 test_case "test_list" `Quick test_list;
88 ])]
0 open QCheck
1 open Helpers
2
3 module type S = sig
4 type t = int
5
6 val gen : int QCheck.Gen.t
7 end
8
9 module Q : S = struct
10 type t = int [@@deriving qcheck]
11 end
12
13 module F (X : S) = struct
14 type t = X.t [@@deriving qcheck]
15 end
16
17 module G = F (Q)
18
19 type t = Q.t [@@deriving qcheck]
20
21 type u = G.t [@@deriving qcheck]
22
23 let test_module () =
24 test_compare ~msg:"Gen.int <=> deriving Q.t" ~eq:Alcotest.int Gen.int gen
25
26 let test_functor () =
27 test_compare ~msg:"Gen.int <=> deriving F.t" ~eq:Alcotest.int Gen.int gen_u
28
29 (** {2. Execute tests} *)
30
31 let () = Alcotest.run "Test_Qualified_names"
32 [("Qualified names",
33 Alcotest.[
34 test_case "test_module" `Quick test_module;
35 test_case "test_functor" `Quick test_functor
36 ])]
0 open QCheck
1 open Helpers
2
3 type env = {
4 rec_types : string list;
5 curr_types : string list;
6 curr_type : string
7 }
8 [@@deriving qcheck]
9
10 let pp_env fmt {rec_types; curr_types; curr_type} =
11 let open Format in
12 fprintf fmt {|{
13 rec_types = [%a];
14 curr_types = [%a];
15 curr_type = [%s];
16 }|}
17 (pp_print_list pp_print_string) rec_types
18 (pp_print_list pp_print_string) curr_types
19 curr_type
20
21 let eq_env = Alcotest.of_pp pp_env
22
23 let gen_env_ref =
24 let open Gen in
25 map3 (fun rec_types curr_types curr_type ->
26 { rec_types; curr_types; curr_type })
27 (list string) (list string) string
28
29 let test_env () =
30 test_compare ~msg:"gen_env ref <=> deriving env"
31 ~eq:eq_env gen_env_ref gen_env
32
33 type color = Color of { red : float; green : float; blue : float }
34 [@@deriving qcheck]
35
36 let pp_color fmt (Color {red; green; blue}) =
37 let open Format in
38 fprintf fmt {|Color {
39 red = %a;
40 green = %a;
41 blue = %a;
42 }|}
43 pp_print_float red
44 pp_print_float green
45 pp_print_float blue
46
47 let eq_color = Alcotest.of_pp pp_color
48
49 let gen_color_ref =
50 let open Gen in
51 map3 (fun red green blue -> Color {red; green; blue}) float float float
52
53 let test_color () =
54 test_compare ~msg:"gen_color ref <=> deriving color"
55 ~eq:eq_color gen_color_ref gen_color
56
57 (** {2. Execute tests} *)
58
59 let () = Alcotest.run "Test_Record"
60 [("Record",
61 Alcotest.[
62 test_case "test_env" `Quick test_env;
63 test_case "test_color" `Quick test_color;
64 ])]
0 open QCheck
1 open Helpers
2
3 type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree
4 [@@deriving qcheck]
5
6 let rec pp_tree pp fmt x =
7 let open Format in
8 match x with
9 | Leaf ->
10 fprintf fmt "Leaf"
11 | Node (x, l, r) ->
12 fprintf fmt "Node (%a, %a, %a)"
13 pp x
14 (pp_tree pp) l
15 (pp_tree pp) r
16
17 let eq_tree pp = Alcotest.of_pp (pp_tree pp)
18
19 let gen_tree_ref gen =
20 let open Gen in
21 sized @@ fix (fun self ->
22 function
23 | 0 -> pure Leaf
24 | n ->
25 oneof [
26 pure Leaf;
27 map3 (fun x l r -> Node (x,l,r)) gen (self (n/2)) (self (n/2));
28 ])
29
30 let gen_tree_candidate = gen_tree
31
32 let test_tree_ref () =
33 let gen = Gen.int in
34 test_compare ~msg:"gen tree <=> derivation tree"
35 ~eq:(eq_tree Format.pp_print_int)
36 (gen_tree_ref gen) (gen_tree gen)
37
38 let test_leaf =
39 Test.make
40 ~name:"gen_tree_sized 0 = Node (_, Leaf, Leaf)"
41 (make (gen_tree_sized Gen.int 0))
42 (function
43 | Leaf -> true
44 | Node (_, Leaf, Leaf) -> true
45 | _ -> false)
46 |>
47 QCheck_alcotest.to_alcotest
48
49 (* A slight error has been found here:
50 If the type is named `list` then `'a list` will be derived with the
51 QCheck generator `list` instead of the `gen_list_sized`.
52
53 This could lead to a design choice:
54 - do we allow overriding primitive types?
55 - do we prioritize `Env.curr_types` over primitive types?
56 *)
57 type 'a my_list = Cons of 'a * 'a my_list | Nil
58 [@@deriving qcheck]
59
60 let rec length = function
61 | Nil -> 0
62 | Cons (_, xs) -> 1 + length xs
63
64 let test_length =
65 Test.make
66 ~name:"gen_list_sized n >>= fun l -> length l <= n"
67 small_int
68 (fun n ->
69 let l = Gen.(generate1 (gen_my_list_sized Gen.int n)) in
70 length l <= n)
71 |>
72 QCheck_alcotest.to_alcotest
73
74 let () = Alcotest.run "Test_Recursive"
75 [("Recursive",
76 Alcotest.[
77 test_case "test_tree_ref" `Quick test_tree_ref;
78 test_leaf
79 ])]
0 (** Module test for ppx_deriving_qcheck *)
1 open Ppxlib
2
3 (** Primitive types tests *)
4 let loc = Location.none
5
6 let f = Ppx_deriving_qcheck.derive_gen ~loc
7
8 let f' xs = List.map f xs |> List.concat
9
10 let extract stri =
11 match stri.pstr_desc with Pstr_type (x, y) -> (x, y) | _ -> assert false
12
13 let extract' xs = List.map extract xs
14
15 let check_eq ~expected ~actual name =
16 let f = Ppxlib.Pprintast.string_of_structure in
17 Alcotest.(check string) name (f expected) (f actual)
18
19 let test_int () =
20 let expected = [ [%stri let gen = QCheck.Gen.int] ] in
21
22 let actual = f @@ extract [%stri type t = int] in
23
24 check_eq ~expected ~actual "deriving int"
25
26 let test_float () =
27 let expected = [ [%stri let gen = QCheck.Gen.float] ] in
28 let actual = f @@ extract [%stri type t = float] in
29
30 check_eq ~expected ~actual "deriving float"
31
32 let test_char () =
33 let expected = [ [%stri let gen = QCheck.Gen.char] ] in
34 let actual = f @@ extract [%stri type t = char] in
35
36 check_eq ~expected ~actual "deriving char"
37
38 let test_string () =
39 let expected = [ [%stri let gen = QCheck.Gen.string] ] in
40 let actual = f @@ extract [%stri type t = string] in
41
42 check_eq ~expected ~actual "deriving string"
43
44 let test_unit () =
45 let expected = [ [%stri let gen = QCheck.Gen.unit] ] in
46 let actual = f @@ extract [%stri type t = unit] in
47
48 check_eq ~expected ~actual "deriving unit"
49
50 let test_bool () =
51 let expected = [ [%stri let gen = QCheck.Gen.bool] ] in
52 let actual = f @@ extract [%stri type t = bool] in
53
54 check_eq ~expected ~actual "deriving bool"
55
56 let test_int32 () =
57 let expected = [ [%stri let gen = QCheck.Gen.ui32] ] in
58 let actual = f @@ extract [%stri type t = int32] in
59
60 check_eq ~expected ~actual "deriving int32"
61
62 let test_int32' () =
63 let expected = [ [%stri let gen = QCheck.Gen.ui32] ] in
64 let actual = f @@ extract [%stri type t = Int32.t] in
65
66 check_eq ~expected ~actual "deriving int32'"
67
68 let test_int64 () =
69 let expected = [ [%stri let gen = QCheck.Gen.ui64] ] in
70 let actual = f @@ extract [%stri type t = int64] in
71
72 check_eq ~expected ~actual "deriving int64"
73
74 let test_int64' () =
75 let expected = [ [%stri let gen = QCheck.Gen.ui64] ] in
76 let actual = f @@ extract [%stri type t = Int64.t] in
77
78 check_eq ~expected ~actual "deriving int64'"
79
80 (* let test_bytes () =
81 * let expected =
82 * [
83 * [%stri
84 * let gen =
85 * QCheck.map
86 * (fun n -> Bytes.create n)
87 * QCheck.(0 -- Sys.max_string_length)];
88 * ]
89 * in
90 * let actual = f @@ extract [%stri type t = Bytes.t ] in
91 *
92 * check_eq ~expected ~actual "deriving int64" *)
93
94 let test_tuple () =
95 let actual =
96 f'
97 @@ extract'
98 [
99 [%stri type t = int * int];
100 [%stri type t = int * int * int];
101 [%stri type t = int * int * int * int];
102 [%stri type t = int * int * int * int * int];
103 [%stri type t = int * int * int * int * int * int];
104 ]
105 in
106 let expected =
107 [
108 [%stri
109 let gen =
110 QCheck.Gen.map
111 (fun (gen0, gen1) -> (gen0, gen1))
112 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.int)];
113 [%stri
114 let gen =
115 QCheck.Gen.map
116 (fun (gen0, gen1, gen2) -> (gen0, gen1, gen2))
117 (QCheck.Gen.triple QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int)];
118 [%stri
119 let gen =
120 QCheck.Gen.map
121 (fun (gen0, gen1, gen2, gen3) -> (gen0, gen1, gen2, gen3))
122 (QCheck.Gen.quad
123 QCheck.Gen.int
124 QCheck.Gen.int
125 QCheck.Gen.int
126 QCheck.Gen.int)];
127 [%stri
128 let gen =
129 QCheck.Gen.map
130 (fun ((gen0, gen1), (gen2, gen3, gen4)) ->
131 (gen0, gen1, gen2, gen3, gen4))
132 (QCheck.Gen.pair
133 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.int)
134 (QCheck.Gen.triple QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int))];
135 [%stri
136 let gen =
137 QCheck.Gen.map
138 (fun ((gen0, gen1, gen2), (gen3, gen4, gen5)) ->
139 (gen0, gen1, gen2, gen3, gen4, gen5))
140 (QCheck.Gen.pair
141 (QCheck.Gen.triple QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int)
142 (QCheck.Gen.triple QCheck.Gen.int QCheck.Gen.int QCheck.Gen.int))];
143 ]
144 in
145
146 check_eq ~expected ~actual "deriving tuples"
147
148 let test_option () =
149 let expected = [ [%stri let gen = QCheck.Gen.opt QCheck.Gen.int] ] in
150 let actual = f' @@ extract' [ [%stri type t = int option] ] in
151 check_eq ~expected ~actual "deriving option"
152
153 let test_array () =
154 let expected = [ [%stri let gen = QCheck.Gen.array QCheck.Gen.int] ] in
155 let actual = f' @@ extract' [ [%stri type t = int array] ] in
156 check_eq ~expected ~actual "deriving option"
157
158 let test_list () =
159 let expected = [ [%stri let gen = QCheck.Gen.list QCheck.Gen.string] ] in
160
161 let actual = f' @@ extract' [ [%stri type t = string list] ] in
162 check_eq ~expected ~actual "deriving list"
163
164 let test_alpha () =
165 let expected =
166 [
167 [%stri let gen gen_a = gen_a];
168 [%stri let gen gen_a = QCheck.Gen.list gen_a];
169 [%stri let gen gen_a = QCheck.Gen.map (fun gen0 -> A gen0) gen_a];
170 [%stri
171 let gen gen_a gen_b =
172 QCheck.Gen.map
173 (fun (gen0, gen1) -> A (gen0, gen1))
174 (QCheck.Gen.pair gen_a gen_b)];
175 [%stri
176 let gen gen_left gen_right =
177 QCheck.Gen.map
178 (fun (gen0, gen1) -> (gen0, gen1))
179 (QCheck.Gen.pair gen_left gen_right)];
180 [%stri
181 let gen_int_tree = gen_tree QCheck.Gen.int
182 ]
183 ]
184 in
185 let actual =
186 f'
187 @@ extract'
188 [
189 [%stri type 'a t = 'a];
190 [%stri type 'a t = 'a list];
191 [%stri type 'a t = A of 'a];
192 [%stri type ('a, 'b) t = A of 'a * 'b];
193 [%stri type ('left, 'right) t = 'left * 'right];
194 [%stri type int_tree = int tree]
195 ]
196 in
197 check_eq ~expected ~actual "deriving alpha"
198
199 let test_equal () =
200 let expected =
201 [
202 [%stri
203 let gen =
204 QCheck.Gen.frequency
205 [
206 (1, QCheck.Gen.pure A);
207 (1, QCheck.Gen.pure B);
208 (1, QCheck.Gen.pure C);
209 ]];
210 [%stri
211 let gen_t' =
212 QCheck.Gen.frequency
213 [
214 (1, QCheck.Gen.pure A);
215 (1, QCheck.Gen.pure B);
216 (1, QCheck.Gen.pure C);
217 ]];
218 ]
219 in
220 let actual =
221 f'
222 @@ extract'
223 [ [%stri type t = A | B | C]; [%stri type t' = t = A | B | C] ]
224 in
225 check_eq ~expected ~actual "deriving equal"
226
227 let test_dependencies () =
228 let expected =
229 [
230 [%stri
231 let gen =
232 QCheck.Gen.frequency
233 [
234 (1, QCheck.Gen.map (fun gen0 -> Int gen0) SomeModule.gen);
235 ( 1,
236 QCheck.Gen.map
237 (fun gen0 -> Float gen0)
238 SomeModule.SomeOtherModule.gen );
239 ]];
240 [%stri let gen = gen_something];
241 ]
242 in
243 let actual =
244 f'
245 @@ extract'
246 [
247 [%stri
248 type t =
249 | Int of SomeModule.t
250 | Float of SomeModule.SomeOtherModule.t];
251 [%stri type t = (Something.t[@gen gen_something])];
252 ]
253 in
254
255 check_eq ~expected ~actual "deriving dependencies"
256
257 let test_konstr () =
258 let expected =
259 [
260 [%stri let gen = QCheck.Gen.map (fun gen0 -> A gen0) QCheck.Gen.int];
261 [%stri
262 let gen =
263 QCheck.Gen.frequency
264 [
265 (1, QCheck.Gen.map (fun gen0 -> B gen0) QCheck.Gen.int);
266 (1, QCheck.Gen.map (fun gen0 -> C gen0) QCheck.Gen.int);
267 ]];
268 [%stri
269 let gen =
270 QCheck.Gen.frequency
271 [
272 (1, QCheck.Gen.map (fun gen0 -> X gen0) gen_t1);
273 (1, QCheck.Gen.map (fun gen0 -> Y gen0) gen_t2);
274 (1, QCheck.Gen.map (fun gen0 -> Z gen0) QCheck.Gen.string);
275 ]];
276 [%stri
277 let gen =
278 QCheck.Gen.frequency
279 [ (1, QCheck.Gen.pure Left); (1, QCheck.Gen.pure Right) ]];
280 [%stri
281 let gen =
282 QCheck.Gen.frequency
283 [
284 (1, QCheck.Gen.map (fun gen0 -> Simple gen0) QCheck.Gen.int);
285 ( 1,
286 QCheck.Gen.map
287 (fun (gen0, gen1) -> Double (gen0, gen1))
288 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.int) );
289 ( 1,
290 QCheck.Gen.map
291 (fun (gen0, gen1, gen2) -> Triple (gen0, gen1, gen2))
292 (QCheck.Gen.triple
293 QCheck.Gen.int
294 QCheck.Gen.int
295 QCheck.Gen.int) );
296 ]];
297 ]
298 in
299 let actual =
300 f'
301 @@ extract'
302 [
303 [%stri type t = A of int];
304 [%stri type t = B of int | C of int];
305 [%stri type t = X of t1 | Y of t2 | Z of string];
306 [%stri type t = Left | Right];
307 [%stri
308 type t =
309 | Simple of int
310 | Double of int * int
311 | Triple of int * int * int];
312 ]
313 in
314 check_eq ~expected ~actual "deriving constructors"
315
316 let test_record () =
317 let expected =
318 [
319 [%stri
320 let gen =
321 QCheck.Gen.map
322 (fun (gen0, gen1) -> { a = gen0; b = gen1 })
323 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.string)];
324 [%stri
325 let gen =
326 QCheck.Gen.map
327 (fun (gen0, gen1) -> { a = gen0; b = gen1 })
328 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.string)];
329 [%stri
330 let gen =
331 QCheck.Gen.frequency
332 [
333 (1, QCheck.Gen.map (fun gen0 -> A gen0) gen_t');
334 ( 1,
335 QCheck.Gen.map
336 (fun (gen0, gen1) -> B { left = gen0; right = gen1 })
337 (QCheck.Gen.pair QCheck.Gen.int QCheck.Gen.int) );
338 ]];
339 ]
340 in
341 let actual =
342 f'
343 @@ extract'
344 [
345 [%stri type t = { a : int; b : string }];
346 [%stri type t = { mutable a : int; mutable b : string }];
347 [%stri type t = A of t' | B of { left : int; right : int }];
348 ]
349 in
350 check_eq ~expected ~actual "deriving record"
351
352 let test_variant () =
353 let expected =
354 [
355 [%stri
356 let gen =
357 (QCheck.Gen.frequency
358 [
359 (1, QCheck.Gen.pure `A);
360 (1, QCheck.Gen.map (fun gen0 -> `B gen0) QCheck.Gen.int);
361 (1, QCheck.Gen.map (fun gen0 -> `C gen0) QCheck.Gen.string);
362 ]
363 : t QCheck.Gen.t)];
364 [%stri
365 let gen_t' =
366 (QCheck.Gen.frequency [ (1, QCheck.Gen.pure `B); (1, gen) ]
367 : t' QCheck.Gen.t)];
368 ]
369 in
370 let actual =
371 f'
372 @@ extract'
373 [
374 [%stri type t = [ `A | `B of int | `C of string ]];
375 [%stri type t' = [ `B | t ]];
376 ]
377 in
378 check_eq ~expected ~actual "deriving variant"
379
380 let test_tree () =
381 let expected =
382 [
383 [%stri
384 let rec gen_tree_sized gen_a n =
385 match n with
386 | 0 -> QCheck.Gen.pure Leaf
387 | _ ->
388 QCheck.Gen.frequency
389 [
390 (1, QCheck.Gen.pure Leaf);
391 ( 1,
392 QCheck.Gen.map
393 (fun (gen0, gen1, gen2) -> Node (gen0, gen1, gen2))
394 (QCheck.Gen.triple
395 gen_a
396 ((gen_tree_sized gen_a) (n / 2))
397 ((gen_tree_sized gen_a) (n / 2))) );
398 ]
399 ];
400 [%stri
401 let gen_tree gen_a = QCheck.Gen.sized @@ (gen_tree_sized gen_a)
402 ];
403 ]
404 in
405 let actual =
406 f
407 @@ extract [%stri type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree];
408 in
409 check_eq ~expected ~actual "deriving tree"
410
411 let test_expr () =
412 let expected =
413 [
414 [%stri
415 let rec gen_expr_sized n =
416 match n with
417 | 0 -> QCheck.Gen.map (fun gen0 -> Value gen0) QCheck.Gen.int
418 | _ ->
419 QCheck.Gen.frequency
420 [
421 ( 1,
422 QCheck.Gen.map (fun gen0 -> Value gen0) QCheck.Gen.int
423 );
424 ( 1,
425 QCheck.Gen.map
426 (fun (gen0, gen1, gen2) -> If (gen0, gen1, gen2))
427 (QCheck.Gen.triple
428 (gen_expr_sized (n / 2))
429 (gen_expr_sized (n / 2))
430 (gen_expr_sized (n / 2))) );
431 ( 1,
432 QCheck.Gen.map
433 (fun (gen0, gen1) -> Eq (gen0, gen1))
434 (QCheck.Gen.pair (gen_expr_sized (n / 2)) (gen_expr_sized (n / 2))) );
435 ( 1,
436 QCheck.Gen.map
437 (fun (gen0, gen1) -> Lt (gen0, gen1))
438 (QCheck.Gen.pair (gen_expr_sized (n / 2)) (gen_expr_sized (n / 2))) );
439 ]
440 ];
441 [%stri
442 let gen_expr = QCheck.Gen.sized @@ gen_expr_sized
443 ]
444 ]
445 in
446 let actual =
447 f @@ extract
448 [%stri
449 type expr =
450 | Value of int
451 | If of expr * expr * expr
452 | Eq of expr * expr
453 | Lt of expr * expr]
454 in
455 check_eq ~expected ~actual "deriving expr"
456
457 let test_forest () =
458 let expected =
459 [
460 [%stri
461 let rec gen_tree_sized gen_a n =
462 QCheck.Gen.map
463 (fun gen0 -> Node gen0)
464 (QCheck.Gen.map
465 (fun (gen0, gen1) -> (gen0, gen1))
466 (QCheck.Gen.pair gen_a ((gen_forest_sized gen_a) (n / 2))))
467
468 and gen_forest_sized gen_a n =
469 match n with
470 | 0 -> QCheck.Gen.pure Nil
471 | _ ->
472 QCheck.Gen.frequency
473 [
474 (1, QCheck.Gen.pure Nil);
475 ( 1,
476 QCheck.Gen.map
477 (fun gen0 -> Cons gen0)
478 (QCheck.Gen.map
479 (fun (gen0, gen1) -> (gen0, gen1))
480 (QCheck.Gen.pair
481 ((gen_tree_sized gen_a) (n / 2))
482 ((gen_forest_sized gen_a) (n / 2)))) );
483 ]
484 ];
485 [%stri let gen_tree gen_a = QCheck.Gen.sized @@ (gen_tree_sized gen_a)];
486 [%stri let gen_forest gen_a = QCheck.Gen.sized @@ (gen_forest_sized gen_a)];
487 ]
488 in
489 let actual =
490 f
491 @@ extract
492 [%stri
493 type 'a tree = Node of ('a * 'a forest)
494
495 and 'a forest = Nil | Cons of ('a tree * 'a forest)]
496 in
497 check_eq ~expected ~actual "deriving forest"
498
499 let test_fun_primitives () =
500 let expected =
501 [
502 [%stri
503 let gen =
504 QCheck.fun_nary
505 QCheck.Tuple.(
506 QCheck.Observable.int @-> QCheck.Observable.int @-> o_nil)
507 (QCheck.make QCheck.Gen.string)
508 |> QCheck.gen];
509 [%stri
510 let gen =
511 QCheck.fun_nary
512 QCheck.Tuple.(
513 QCheck.Observable.float @-> QCheck.Observable.float @-> o_nil)
514 (QCheck.make QCheck.Gen.string)
515 |> QCheck.gen];
516 [%stri
517 let gen =
518 QCheck.fun_nary
519 QCheck.Tuple.(
520 QCheck.Observable.string @-> QCheck.Observable.string @-> o_nil)
521 (QCheck.make QCheck.Gen.string)
522 |> QCheck.gen];
523 [%stri
524 let gen =
525 QCheck.fun_nary
526 QCheck.Tuple.(
527 QCheck.Observable.bool @-> QCheck.Observable.bool @-> o_nil)
528 (QCheck.make QCheck.Gen.string)
529 |> QCheck.gen];
530 [%stri
531 let gen =
532 QCheck.fun_nary
533 QCheck.Tuple.(
534 QCheck.Observable.char @-> QCheck.Observable.char @-> o_nil)
535 (QCheck.make QCheck.Gen.string)
536 |> QCheck.gen];
537 [%stri
538 let gen =
539 QCheck.fun_nary
540 QCheck.Tuple.(QCheck.Observable.unit @-> o_nil)
541 (QCheck.make QCheck.Gen.string)
542 |> QCheck.gen];
543 ]
544 in
545
546 let actual =
547 f'
548 @@ extract'
549 [
550 [%stri type t = int -> int -> string];
551 [%stri type t = float -> float -> string];
552 [%stri type t = string -> string -> string];
553 [%stri type t = bool -> bool -> string];
554 [%stri type t = char -> char -> string];
555 [%stri type t = unit -> string];
556 ]
557 in
558 check_eq ~expected ~actual "deriving fun primitives"
559
560 let test_fun_n () =
561 let expected =
562 [
563 [%stri
564 let gen =
565 QCheck.fun_nary
566 QCheck.Tuple.(
567 QCheck.Observable.bool @-> QCheck.Observable.int
568 @-> QCheck.Observable.float @-> QCheck.Observable.string
569 @-> QCheck.Observable.char @-> o_nil)
570 (QCheck.make QCheck.Gen.unit)
571 |> QCheck.gen];
572 ]
573 in
574 let actual =
575 f @@ extract [%stri type t = bool -> int -> float -> string -> char -> unit]
576 in
577 check_eq ~expected ~actual "deriving fun n"
578
579 let test_fun_option () =
580 let expected =
581 [
582 [%stri
583 let gen =
584 QCheck.fun_nary
585 QCheck.Tuple.(
586 QCheck.Observable.option QCheck.Observable.int @-> o_nil)
587 (QCheck.make QCheck.Gen.unit)
588 |> QCheck.gen];
589 ]
590 in
591 let actual = f @@ extract [%stri type t = int option -> unit] in
592 check_eq ~expected ~actual "deriving fun option"
593
594 let test_fun_list () =
595 let expected =
596 [
597 [%stri
598 let gen =
599 QCheck.fun_nary
600 QCheck.Tuple.(
601 QCheck.Observable.list QCheck.Observable.int @-> o_nil)
602 (QCheck.make QCheck.Gen.unit)
603 |> QCheck.gen];
604 ]
605 in
606 let actual = f @@ extract [%stri type t = int list -> unit] in
607 check_eq ~expected ~actual "deriving fun list"
608
609 let test_fun_array () =
610 let expected =
611 [
612 [%stri
613 let gen =
614 QCheck.fun_nary
615 QCheck.Tuple.(
616 QCheck.Observable.array QCheck.Observable.int @-> o_nil)
617 (QCheck.make QCheck.Gen.unit)
618 |> QCheck.gen];
619 ]
620 in
621 let actual = f @@ extract [%stri type t = int array -> unit] in
622 check_eq ~expected ~actual "deriving fun array"
623
624 let test_fun_tuple () =
625 let expected =
626 [
627 [%stri
628 let gen =
629 QCheck.fun_nary
630 QCheck.Tuple.(
631 QCheck.Observable.pair QCheck.Observable.int QCheck.Observable.int
632 @-> o_nil)
633 (QCheck.make QCheck.Gen.unit)
634 |> QCheck.gen];
635 [%stri
636 let gen =
637 QCheck.fun_nary
638 QCheck.Tuple.(
639 QCheck.Observable.triple
640 QCheck.Observable.int
641 QCheck.Observable.int
642 QCheck.Observable.int
643 @-> o_nil)
644 (QCheck.make QCheck.Gen.unit)
645 |> QCheck.gen];
646 [%stri
647 let gen =
648 QCheck.fun_nary
649 QCheck.Tuple.(
650 QCheck.Observable.quad
651 QCheck.Observable.int
652 QCheck.Observable.int
653 QCheck.Observable.int
654 QCheck.Observable.int
655 @-> o_nil)
656 (QCheck.make QCheck.Gen.unit)
657 |> QCheck.gen];
658 ]
659 in
660 let actual =
661 f'
662 @@ extract'
663 [
664 [%stri type t = int * int -> unit];
665 [%stri type t = int * int * int -> unit];
666 [%stri type t = int * int * int * int -> unit];
667 ]
668 in
669 check_eq ~expected ~actual "deriving fun tuple"
670
671 let test_weight_konstrs () =
672 let expected =
673 [
674 [%stri
675 let gen =
676 QCheck.Gen.frequency
677 [
678 (5, QCheck.Gen.pure A);
679 (6, QCheck.Gen.pure B);
680 (1, QCheck.Gen.pure C);
681 ]];
682 ]
683 in
684 let actual =
685 f @@ extract [%stri type t = A [@weight 5] | B [@weight 6] | C]
686 in
687 check_eq ~expected ~actual "deriving weight konstrs"
688
689 (* Regression test: https://github.com/c-cube/qcheck/issues/187 *)
690 let test_recursive_poly_variant () =
691 let expected =
692 [
693 [%stri
694 let rec gen_tree_sized gen_a n =
695 (match n with
696 | 0 -> QCheck.Gen.map (fun gen0 -> `Leaf gen0) gen_a
697 | _ ->
698 QCheck.Gen.frequency
699 [
700 ( 1,
701 QCheck.Gen.map (fun gen0 -> `Leaf gen0) gen_a
702 );
703 ( 1,
704 QCheck.Gen.map
705 (fun gen0 -> `Node gen0)
706 (QCheck.Gen.map
707 (fun (gen0, gen1) -> (gen0, gen1))
708 (QCheck.Gen.pair
709 ((gen_tree_sized gen_a) (n / 2))
710 ((gen_tree_sized gen_a) (n / 2))))
711 );
712 ]
713 : tree QCheck.Gen.t)];
714 [%stri
715 let gen_tree gen_a = QCheck.Gen.sized @@ (gen_tree_sized gen_a)
716 ]
717 ]
718 in
719 let actual =
720 f @@ extract [%stri type 'a tree = [ `Leaf of 'a | `Node of 'a tree * 'a tree ]]
721 in
722 check_eq ~expected ~actual "deriving recursive polymorphic variants"
723
724 (* Regression test: https://github.com/c-cube/qcheck/issues/213 *)
725 let test_unused_variable () =
726 let expected =
727 [
728 [%stri
729 let rec gen_c_sized n =
730 match n with
731 | 0 -> QCheck.Gen.pure A
732 | _ ->
733 QCheck.Gen.frequency
734 [(1, (QCheck.Gen.pure A));
735 (1, (QCheck.Gen.map (fun gen0 -> B gen0) gen_myint))]
736 and gen_myint = QCheck.Gen.nat
737 ];
738 [%stri
739 let gen_c = QCheck.Gen.sized @@ gen_c_sized
740 ];
741 [%stri
742 let rec gen_c_sized _n =
743 QCheck.Gen.frequency
744 [(1, (QCheck.Gen.map (fun gen0 -> A gen0) gen_myint));
745 (1, (QCheck.Gen.map (fun gen0 -> B gen0) gen_myint))]
746 and gen_myint = QCheck.Gen.nat
747 ];
748 [%stri
749 let gen_c = QCheck.Gen.sized @@ gen_c_sized
750 ];
751 ]
752 in
753 let actual =
754 f' @@ extract' [
755 [%stri
756 type c =
757 | A
758 | B of myint
759 and myint = int [@gen QCheck.Gen.nat] ];
760 [%stri
761 type c =
762 | A of myint
763 | B of myint
764 and myint = int [@gen QCheck.Gen.nat] ];
765 ]
766 in
767 check_eq ~expected ~actual "deriving variant with unused fuel parameter"
768
769
770 let () =
771 Alcotest.(
772 run
773 "ppx_deriving_qcheck tests"
774 [
775 ( "deriving generator good",
776 [
777 test_case "deriving int" `Quick test_int;
778 test_case "deriving float" `Quick test_float;
779 test_case "deriving char" `Quick test_char;
780 test_case "deriving string" `Quick test_string;
781 test_case "deriving unit" `Quick test_unit;
782 test_case "deriving bool" `Quick test_bool;
783 test_case "deriving int32" `Quick test_int32;
784 test_case "deriving int32'" `Quick test_int32';
785 test_case "deriving int64" `Quick test_int64;
786 test_case "deriving int64'" `Quick test_int64';
787 (* test_case "deriving bytes" `Quick test_bytes; *)
788 test_case "deriving tuple" `Quick test_tuple;
789 test_case "deriving option" `Quick test_option;
790 test_case "deriving array" `Quick test_array;
791 test_case "deriving list" `Quick test_list;
792 test_case "deriving constructors" `Quick test_konstr;
793 test_case "deriving dependencies" `Quick test_dependencies;
794 test_case "deriving record" `Quick test_record;
795 test_case "deriving equal" `Quick test_equal;
796 test_case "deriving tree like" `Quick test_tree;
797 test_case "deriving expr like" `Quick test_expr;
798 test_case "deriving alpha" `Quick test_alpha;
799 test_case "deriving variant" `Quick test_variant;
800 test_case "deriving weight constructors" `Quick test_weight_konstrs;
801 test_case "deriving forest" `Quick test_forest;
802 test_case "deriving fun primitives" `Quick test_fun_primitives;
803 test_case "deriving fun option" `Quick test_fun_option;
804 test_case "deriving fun array" `Quick test_fun_array;
805 test_case "deriving fun list" `Quick test_fun_list;
806 test_case "deriving fun n" `Quick test_fun_n;
807 test_case "deriving fun tuple" `Quick test_fun_tuple;
808 test_case
809 "deriving rec poly variants"
810 `Quick
811 test_recursive_poly_variant;
812 test_case
813 "deriving variant with unused fuel parameter"
814 `Quick
815 test_unused_variable;
816 ] );
817 ])
0 open QCheck
1
2 type a = char [@gen QCheck.Gen.pure 'a']
3 [@@deriving qcheck]
4
5 type b = char [@gen QCheck.Gen.pure 'b']
6 [@@deriving qcheck]
7
8 type c = char [@gen QCheck.Gen.pure 'c']
9 [@@deriving qcheck]
10
11 type d = char [@gen QCheck.Gen.pure 'd']
12 [@@deriving qcheck]
13
14 type e = char [@gen QCheck.Gen.pure 'e']
15 [@@deriving qcheck]
16
17 type f = char [@gen QCheck.Gen.pure 'f']
18 [@@deriving qcheck]
19
20 type g = char [@gen QCheck.Gen.pure 'g']
21 [@@deriving qcheck]
22
23 type h = char [@gen QCheck.Gen.pure 'h']
24 [@@deriving qcheck]
25
26 type i = char [@gen QCheck.Gen.pure 'i']
27 [@@deriving qcheck]
28
29 type tup2 = a * b
30 [@@deriving qcheck]
31
32 type tup3 = a * b * c
33 [@@deriving qcheck]
34
35 type tup4 = a * b * c * d
36 [@@deriving qcheck]
37
38 type tup5 = a * b * c * d * e
39 [@@deriving qcheck]
40
41 type tup6 = a * b * c * d * e * f
42 [@@deriving qcheck]
43
44 type tup7 = a * b * c * d * e * f * g
45 [@@deriving qcheck]
46
47 type tup8 = a * b * c * d * e * f * g * h
48 [@@deriving qcheck]
49
50 let test_tup2 =
51 Test.make ~count:10
52 ~name:"forall x in ('a', 'b'): x = ('a', 'b')"
53 (make gen_tup2)
54 (fun x -> x = ('a', 'b'))
55
56 let test_tup3 =
57 Test.make ~count:10
58 ~name:"forall x in ('a', 'b', 'c'): x = ('a', 'b', 'c')"
59 (make gen_tup3)
60 (fun x -> x = ('a', 'b', 'c'))
61
62 let test_tup4 =
63 Test.make ~count:10
64 ~name:"forall x in ('a', 'b', 'c', 'd'): x = ('a', 'b', 'c', 'd')"
65 (make gen_tup4)
66 (fun x -> x = ('a', 'b', 'c', 'd'))
67
68 let test_tup5 =
69 Test.make ~count:10
70 ~name:"forall x in ('a', 'b', 'c', 'd', 'e'): x = ('a', 'b', 'c', 'd', 'e')"
71 (make gen_tup5)
72 (fun x -> x = ('a', 'b', 'c', 'd', 'e'))
73
74 let test_tup6 =
75 Test.make ~count:10
76 ~name:"forall x in ('a', 'b', 'c', 'd', 'e', 'f'): x = ('a', 'b', 'c', 'd', 'e', 'f')"
77 (make gen_tup6)
78 (fun x -> x = ('a', 'b', 'c', 'd', 'e', 'f'))
79
80 let test_tup7 =
81 Test.make ~count:10
82 ~name:"forall x in ('a', 'b', 'c', 'd', 'e', 'f', 'g'): x = ('a', 'b', 'c', 'd', 'e', 'f', 'g')"
83 (make gen_tup7)
84 (fun x -> x = ('a', 'b', 'c', 'd', 'e', 'f', 'g'))
85
86 let test_tup8 =
87 Test.make ~count:10
88 ~name:"forall x in ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'): x = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')"
89 (make gen_tup8)
90 (fun x -> x = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'))
91
92 let tests = [
93 test_tup2;
94 test_tup3;
95 test_tup4;
96 test_tup5;
97 test_tup6;
98 test_tup7;
99 test_tup8;
100 ]
101
102 let tests = List.map (QCheck_alcotest.to_alcotest) tests
103
104 (** {2. Execute tests} *)
105 let () = Alcotest.run "Test_Tuple" [("Tuple", tests)]
0 open QCheck
1 open Helpers
2
3 (** {1. Test variants and polymorphic variants derivation} *)
4
5 (** {2. Variants} *)
6
7 type colors = Red | Green | Blue [@@deriving qcheck]
8
9 let pp_colors fmt x =
10 let open Format in
11 match x with
12 | Red -> fprintf fmt "Red"
13 | Green -> fprintf fmt "Green"
14 | Blue -> fprintf fmt "Blue"
15
16 let eq_colors = Alcotest.of_pp pp_colors
17
18 let gen = Gen.oneofl [Red; Green; Blue]
19
20 let test_variants () =
21 test_compare ~msg:"Gen.oneofl <=> deriving variants" ~eq:eq_colors gen gen_colors
22
23 type poly_colors = [`Red | `Green | `Blue] [@@deriving qcheck]
24
25 let pp_poly_colors fmt x =
26 let open Format in
27 match x with
28 | `Red -> fprintf fmt "`Red"
29 | `Green -> fprintf fmt "`Green"
30 | `Blue -> fprintf fmt "`Blue"
31
32 let eq_poly_colors = Alcotest.of_pp pp_poly_colors
33
34 let gen_poly : poly_colors Gen.t = Gen.oneofl [`Red; `Green; `Blue]
35
36 let test_poly_variants () =
37 test_compare ~msg:"Gen.oneofl <=> deriving variants"
38 ~eq:eq_poly_colors gen_poly gen_poly_colors
39
40 (** {2. Tests weight} *)
41
42 type letters =
43 | A [@weight 0]
44 | B
45 [@@deriving qcheck]
46
47 let test_weight =
48 Test.make ~name:"gen_letters always produces B"
49 (make gen_letters)
50 (function
51 | A -> false
52 | B -> true)
53 |>
54 QCheck_alcotest.to_alcotest
55
56 type poly_letters = [
57 | `A [@weight 0]
58 | `B
59 ]
60 [@@deriving qcheck]
61
62 let test_weight_poly =
63 Test.make ~name:"gen_poly_letters always produces B"
64 (make gen_poly_letters)
65 (function
66 | `A -> false
67 | `B -> true)
68 |>
69 QCheck_alcotest.to_alcotest
70
71 (** {2. Execute tests} *)
72
73 let () = Alcotest.run "Test_Variant"
74 [("Variants",
75 Alcotest.[
76 test_case "test_variants" `Quick test_variants;
77 test_case "test_poly_variants" `Quick test_poly_variants;
78 test_weight;
79 test_weight_poly
80 ])]