Skip to content

Long integer shrinking from within toplevel/utop #59

@jmid

Description

@jmid

Consider the following code:

open QCheck

let rec fac n = match n with
  | 0 -> 1
  | n -> n * fac (n - 1)

let test_fac =
  Test.make ~name:"fac mod'"
    (small_int_corners ())
    (fun n -> try (fac n) mod n = 0
              with Division_by_zero -> (n=0))
;;
QCheck_runner.run_tests ~verbose:true [test_fac]

Assume you save the above to a file bug.ml.

If I compile the example test with the bytecode backend I quickly (0.5s) find the bound (262049) for blowing the bytecode stack:

$ ocamlbuild -use-ocamlfind -package qcheck bug.byte
Finished, 3 targets (0 cached) in 00:00:00.
$ ./bug.byte 
random seed: 317373207
generated error fail pass / total     time test name
[✗]    4    1    0    3 /  100     0.5s fac mod'

=== Error ======================================================================

Test fac mod' errored on (138 shrink steps):

262049

exception Stack overflow

================================================================================
failure (0 tests failed, 1 tests errored, ran 1 tests)

Similarly I can quickly (0.4s) find the bound (524115) for blowing the native-code stack:

$ ocamlbuild -use-ocamlfind -package qcheck bug.native
Finished, 4 targets (2 cached) in 00:00:00.
$ ./bug.native 
random seed: 448617552
generated error fail pass / total     time test name
[✗]    4    1    0    3 /  100     0.4s fac mod'

=== Error ======================================================================

Test fac mod' errored on (215 shrink steps):

524115

exception Stack overflow

================================================================================
failure (0 tests failed, 1 tests errored, ran 1 tests)

However, if I try the same thing within the OCaml toplevel or utop -- I consistently get very long shrinking times (237.9s) with many (52578!) shrinking steps - to the point that I thought I had hit an infinite loop:

utop # #require "qcheck";;
─( 17:51:25 )─< command 1 >────────────────────────────────────────────{ counter: 0 }─
utop # #use "bug.ml";;
val fac : int -> int = <fun>
val test_fac : Test.t = QCheck.Test.Test <abstr>
random seed: 175072808
generated error fail pass / total     time test name
[✗]    4    1    0    3 /  100   237.9s fac mod'

=== Error ======================================================================

Test fac mod' errored on (52578 shrink steps):

209609

exception Stack overflow

================================================================================
failure (0 tests failed, 1 tests errored, ran 1 tests)
- : int = 1

Is this example triggering a sore point in the built-in integer shrinker, or is something else going on?
This is on Mac OS X with OCaml 4.07.1 and QCheck 0.9.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions