diff --git a/CHANGELOG.md b/CHANGELOG.md index 23d5fa7f..baa32be8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - `TestResult.stats` `TestResult.warnings` `TestResult.collect` - Clarify documentation for the `int*` and `nat*` generators - Disabled duplicated pretty-printed feedback when using `QCheck_alcotest` runner +- Fixed the overflow bug when `~count > max_int - 200` affecting `Test.{make_cell,make,make_neg}` in both QCheck and QCheck2 ## 0.91 (2025-12-21) diff --git a/src/core/QCheck2.ml b/src/core/QCheck2.ml index f3246fe8..1e20a379 100644 --- a/src/core/QCheck2.ml +++ b/src/core/QCheck2.ml @@ -1618,7 +1618,7 @@ module Test = struct let count = global_count count in let long_factor = global_long_factor long_factor in let positive = not negative in - let max_gen = match max_gen with None -> count + 200 | Some x->x in + let max_gen = match max_gen with None -> max count (count + 200) | Some x->x in { law; gen; @@ -1645,7 +1645,7 @@ module Test = struct let positive = not negative in (* Make a "fake" QCheck2 arbitrary with no shrinking *) let fake_gen = Gen.make_primitive ~gen ~shrink:(fun _ -> Seq.empty) in - let max_gen = match max_gen with None -> count + 200 | Some x->x in + let max_gen = match max_gen with None -> max count (count + 200) | Some x->x in { law; gen = fake_gen; diff --git a/test/core/QCheck2_unit_tests.ml b/test/core/QCheck2_unit_tests.ml index a42a780b..9dad143e 100644 --- a/test/core/QCheck2_unit_tests.ml +++ b/test/core/QCheck2_unit_tests.ml @@ -617,6 +617,23 @@ module TestCount = struct with | _ -> () + (* Regression for https://github.com/c-cube/qcheck/issues/408: + [make_cell] computed [max_gen = count + 200] without checking for + overflow, so [count >= max_int - 199] wrapped to a negative int + and [check_cell] silently ran zero iterations. *) + let test_count_max_int_no_overflow () = + let cell = + QCheck2.(Test.make_cell ~name:"never_true" ~count:max_int + Gen.int (fun _ -> false)) + in + let result = + QCheck2.Test.check_cell ~rand:(Random.State.make [|0|]) cell + in + let tested = QCheck2.TestResult.get_count_gen result in + Alcotest.(check bool) + "check_cell with count=max_int runs at least one iteration" + true (tested >= 1) + let tests = ("Test.make ~count", Alcotest.[ test_case "make with custom count" `Quick test_count_10; @@ -625,6 +642,8 @@ module TestCount = struct test_case "make with 0 count" `Quick test_count_0; test_case "make with negative count should fail" `Quick test_count_negative_fail; + test_case "check_cell with count=max_int does not overflow" + `Quick test_count_max_int_no_overflow; ]) end