package async

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file async_quickcheck.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
open! Core
open! Async_kernel
open Deferred.Infix
module Generator = Quickcheck.Generator
module Observer = Quickcheck.Observer
module Shrinker = Quickcheck.Shrinker

module Configure (Config : Quickcheck.Quickcheck_config) = struct
  include Quickcheck.Configure (Config)

  let shrink_error ~shrinker ~shrink_count ~f input error =
    let rec loop ~shrink_count ~alternates input error =
      match shrink_count with
      | 0 -> return (input, error)
      | _ ->
        let shrink_count = shrink_count - 1 in
        (match Sequence.next alternates with
         | None -> return (input, error)
         | Some (alternate, alternates) ->
           (match%bind f alternate with
            | Ok () -> loop ~shrink_count ~alternates input error
            | Error error ->
              let alternates = Shrinker.shrink shrinker alternate in
              loop ~shrink_count ~alternates alternate error))
    in
    let alternates = Shrinker.shrink shrinker input in
    loop ~shrink_count ~alternates input error
  ;;

  let async_test
        ?seed
        ?sizes
        ?(trials = default_trial_count)
        ?shrinker
        ?(shrink_attempts = default_shrink_attempts)
        ?sexp_of
        ?(examples = [])
        quickcheck_generator
        ~f
    =
    let f x =
      Deferred.Or_error.try_with ~run:`Now ~rest:`Raise ~extract_exn:true (fun () -> f x)
    in
    let test_cases =
      Sequence.append
        (Sequence.of_list examples)
        (Sequence.take (random_sequence ?seed ?sizes quickcheck_generator) trials)
    in
    let%bind failing_case =
      Sequence.delayed_fold
        test_cases
        ~init:()
        ~f:(fun () x ~k ->
          match%bind f x with
          | Error error -> return (Some (x, error))
          | Ok () -> k ())
        ~finish:(fun () -> Deferred.return None)
    in
    let%map shrunken_case =
      match shrinker with
      | None -> return failing_case
      | Some shrinker ->
        let shrink_count =
          match shrink_attempts with
          | `Limit n -> n
          | `Exhaustive -> Int.max_value
        in
        (match failing_case with
         | Some (input, error) ->
           shrink_error ~shrinker ~shrink_count ~f input error >>| Option.some
         | None -> return None)
    in
    match shrunken_case with
    | None -> ()
    | Some (input, error) ->
      let tagged_error =
        match sexp_of with
        | None -> error
        | Some sexp_of_arg -> Error.tag_arg error "random input" input sexp_of_arg
      in
      Error.raise tagged_error
  ;;
end

include Configure (Quickcheck)
OCaml

Innovation. Community. Security.