package async
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 85open! 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)