Pārlūkot izejas kodu

LibTest: Add more numeric generators

Rename unsigned_int generator to number_u32.
Add generators:
- number_u64
- number_f64
- percentage
Martin Janiczek 1 gadu atpakaļ
vecāks
revīzija
d52ffcd830

+ 14 - 0
AK/Random.cpp

@@ -5,6 +5,8 @@
  */
  */
 
 
 #include <AK/Random.h>
 #include <AK/Random.h>
+#include <AK/UFixedBigInt.h>
+#include <AK/UFixedBigIntDivision.h>
 
 
 namespace AK {
 namespace AK {
 
 
@@ -28,4 +30,16 @@ u32 get_random_uniform(u32 max_bounds)
     return random_value % max_bounds;
     return random_value % max_bounds;
 }
 }
 
 
+u64 get_random_uniform_64(u64 max_bounds)
+{
+    // Uses the same algorithm as `get_random_uniform`,
+    // by replacing u64 with u128 and u32 with u64.
+    const u64 max_usable = UINT64_MAX - static_cast<u64>((static_cast<u128>(UINT64_MAX) + 1) % max_bounds);
+    auto random_value = get_random<u64>();
+    for (int i = 0; i < 20 && random_value > max_usable; ++i) {
+        random_value = get_random<u64>();
+    }
+    return random_value % max_bounds;
+}
+
 }
 }

+ 1 - 0
AK/Random.h

@@ -60,6 +60,7 @@ inline T get_random()
 }
 }
 
 
 u32 get_random_uniform(u32 max_bounds);
 u32 get_random_uniform(u32 max_bounds);
+u64 get_random_uniform_64(u64 max_bounds);
 
 
 template<typename Collection>
 template<typename Collection>
 inline void shuffle(Collection& collection)
 inline void shuffle(Collection& collection)

+ 2 - 2
Tests/AK/TestAllOf.cpp

@@ -28,13 +28,13 @@ TEST_CASE(all_but_one_false)
 
 
 RANDOMIZED_TEST_CASE(trivial_all_true)
 RANDOMIZED_TEST_CASE(trivial_all_true)
 {
 {
-    GEN(vec, Gen::vector(0, 10, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(0, 10, []() { return Gen::number_u64(); }));
     EXPECT(all_of(vec.begin(), vec.end(), [](auto) { return true; }));
     EXPECT(all_of(vec.begin(), vec.end(), [](auto) { return true; }));
 }
 }
 
 
 RANDOMIZED_TEST_CASE(trivial_all_false)
 RANDOMIZED_TEST_CASE(trivial_all_false)
 {
 {
-    GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
     EXPECT(!all_of(vec.begin(), vec.end(), [](auto) { return false; }));
     EXPECT(!all_of(vec.begin(), vec.end(), [](auto) { return false; }));
 }
 }
 
 

+ 2 - 2
Tests/AK/TestAnyOf.cpp

@@ -28,13 +28,13 @@ TEST_CASE(all_false)
 
 
 RANDOMIZED_TEST_CASE(trivial_all_true)
 RANDOMIZED_TEST_CASE(trivial_all_true)
 {
 {
-    GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
     EXPECT(any_of(vec.begin(), vec.end(), [](auto) { return true; }));
     EXPECT(any_of(vec.begin(), vec.end(), [](auto) { return true; }));
 }
 }
 
 
 RANDOMIZED_TEST_CASE(trivial_all_false)
 RANDOMIZED_TEST_CASE(trivial_all_false)
 {
 {
-    GEN(vec, Gen::vector(0, 10, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(0, 10, []() { return Gen::number_u64(); }));
     EXPECT(!any_of(vec.begin(), vec.end(), [](auto) { return false; }));
     EXPECT(!any_of(vec.begin(), vec.end(), [](auto) { return false; }));
 }
 }
 
 

+ 9 - 9
Tests/AK/TestBinaryHeap.cpp

@@ -70,35 +70,35 @@ TEST_CASE(large_populate_reverse)
 
 
 RANDOMIZED_TEST_CASE(pop_min_is_min)
 RANDOMIZED_TEST_CASE(pop_min_is_min)
 {
 {
-    GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
 
 
     auto sorted { vec };
     auto sorted { vec };
     AK::quick_sort(sorted);
     AK::quick_sort(sorted);
 
 
-    BinaryHeap<u32, u32, 10> heap;
+    BinaryHeap<u64, u64, 10> heap;
 
 
     // insert in a non-sorted order
     // insert in a non-sorted order
-    for (u32 n : vec) {
+    for (u64 n : vec) {
         heap.insert(n, n);
         heap.insert(n, n);
     }
     }
 
 
     // check in a sorted order
     // check in a sorted order
-    for (u32 sorted_n : sorted) {
+    for (u64 sorted_n : sorted) {
         EXPECT_EQ(heap.pop_min(), sorted_n);
         EXPECT_EQ(heap.pop_min(), sorted_n);
     }
     }
 }
 }
 
 
 RANDOMIZED_TEST_CASE(peek_min_same_as_pop_min)
 RANDOMIZED_TEST_CASE(peek_min_same_as_pop_min)
 {
 {
-    GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
-    BinaryHeap<u32, u32, 10> heap;
-    for (u32 n : vec) {
+    GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
+    BinaryHeap<u64, u64, 10> heap;
+    for (u64 n : vec) {
         heap.insert(n, n);
         heap.insert(n, n);
     }
     }
 
 
     while (!heap.is_empty()) {
     while (!heap.is_empty()) {
-        u32 peeked = heap.peek_min();
-        u32 popped = heap.pop_min();
+        u64 peeked = heap.peek_min();
+        u64 popped = heap.pop_min();
         EXPECT_EQ(peeked, popped);
         EXPECT_EQ(peeked, popped);
     }
     }
 }
 }

+ 5 - 5
Tests/AK/TestBinarySearch.cpp

@@ -122,10 +122,10 @@ TEST_CASE(unsigned_to_signed_regression)
 
 
 RANDOMIZED_TEST_CASE(finds_number_that_is_present)
 RANDOMIZED_TEST_CASE(finds_number_that_is_present)
 {
 {
-    GEN(vec, Gen::vector(1, 16, []() { return Gen::unsigned_int(); }));
-    GEN(i, Gen::unsigned_int(0, vec.size() - 1));
+    GEN(vec, Gen::vector(1, 16, []() { return Gen::number_u64(); }));
+    GEN(i, Gen::number_u64(0, vec.size() - 1));
     AK::quick_sort(vec);
     AK::quick_sort(vec);
-    u32 n = vec[i];
+    u64 n = vec[i];
     auto ptr = binary_search(vec, n);
     auto ptr = binary_search(vec, n);
     EXPECT_NE(ptr, nullptr);
     EXPECT_NE(ptr, nullptr);
     EXPECT_EQ(*ptr, n);
     EXPECT_EQ(*ptr, n);
@@ -133,10 +133,10 @@ RANDOMIZED_TEST_CASE(finds_number_that_is_present)
 
 
 RANDOMIZED_TEST_CASE(doesnt_find_number_that_is_not_present)
 RANDOMIZED_TEST_CASE(doesnt_find_number_that_is_not_present)
 {
 {
-    GEN(vec, Gen::vector(1, 16, []() { return Gen::unsigned_int(); }));
+    GEN(vec, Gen::vector(1, 16, []() { return Gen::number_u64(); }));
     AK::quick_sort(vec);
     AK::quick_sort(vec);
 
 
-    u32 not_present = 0;
+    u64 not_present = 0;
     while (!vec.find(not_present).is_end()) {
     while (!vec.find(not_present).is_end()) {
         ++not_present;
         ++not_present;
     }
     }

+ 6 - 6
Tests/AK/TestBitStream.cpp

@@ -201,7 +201,7 @@ TEST_CASE(bit_reads_beyond_stream_limits)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u8>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
@@ -216,7 +216,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u16>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
@@ -231,7 +231,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u32>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
@@ -246,7 +246,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u8>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
@@ -260,7 +260,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u16>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
@@ -274,7 +274,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
 
 
 RANDOMIZED_TEST_CASE(roundtrip_u32_big_endian)
 RANDOMIZED_TEST_CASE(roundtrip_u32_big_endian)
 {
 {
-    GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
+    GEN(n, Gen::number_u64(NumericLimits<u32>::max()));
 
 
     auto memory_stream = make<AllocatingMemoryStream>();
     auto memory_stream = make<AllocatingMemoryStream>();
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
     BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };

+ 11 - 11
Tests/AK/TestBitmap.cpp

@@ -283,8 +283,8 @@ RANDOMIZED_TEST_CASE(set_get)
 {
 {
     GEN(init, Gen::boolean());
     GEN(init, Gen::boolean());
     GEN(new_value, Gen::boolean());
     GEN(new_value, Gen::boolean());
-    GEN(size, Gen::unsigned_int(1, 64));
-    GEN(i, Gen::unsigned_int(size - 1));
+    GEN(size, Gen::number_u64(1, 64));
+    GEN(i, Gen::number_u64(size - 1));
 
 
     auto bitmap = MUST(Bitmap::create(size, init));
     auto bitmap = MUST(Bitmap::create(size, init));
     bitmap.set(i, new_value);
     bitmap.set(i, new_value);
@@ -295,11 +295,11 @@ RANDOMIZED_TEST_CASE(set_get)
 RANDOMIZED_TEST_CASE(set_range)
 RANDOMIZED_TEST_CASE(set_range)
 {
 {
     GEN(init, Gen::boolean());
     GEN(init, Gen::boolean());
-    GEN(size, Gen::unsigned_int(1, 64));
+    GEN(size, Gen::number_u64(1, 64));
     GEN(new_value, Gen::boolean());
     GEN(new_value, Gen::boolean());
 
 
-    GEN(start, Gen::unsigned_int(size - 1));
-    GEN(len, Gen::unsigned_int(size - start - 1));
+    GEN(start, Gen::number_u64(size - 1));
+    GEN(len, Gen::number_u64(size - start - 1));
 
 
     auto bitmap = MUST(Bitmap::create(size, init));
     auto bitmap = MUST(Bitmap::create(size, init));
     bitmap.set_range(start, len, new_value);
     bitmap.set_range(start, len, new_value);
@@ -313,7 +313,7 @@ RANDOMIZED_TEST_CASE(set_range)
 RANDOMIZED_TEST_CASE(fill)
 RANDOMIZED_TEST_CASE(fill)
 {
 {
     GEN(init, Gen::boolean());
     GEN(init, Gen::boolean());
-    GEN(size, Gen::unsigned_int(1, 64));
+    GEN(size, Gen::number_u64(1, 64));
     GEN(new_value, Gen::boolean());
     GEN(new_value, Gen::boolean());
 
 
     auto bitmap = MUST(Bitmap::create(size, init));
     auto bitmap = MUST(Bitmap::create(size, init));
@@ -334,11 +334,11 @@ TEST_CASE(find_one_anywhere_edge_case)
 RANDOMIZED_TEST_CASE(find_one_anywhere)
 RANDOMIZED_TEST_CASE(find_one_anywhere)
 {
 {
     GEN(init, Gen::boolean());
     GEN(init, Gen::boolean());
-    GEN(size, Gen::unsigned_int(1, 64));
-    GEN(hint, Gen::unsigned_int(size - 1));
+    GEN(size, Gen::number_u64(1, 64));
+    GEN(hint, Gen::number_u64(size - 1));
 
 
     GEN(new_value, Gen::boolean());
     GEN(new_value, Gen::boolean());
-    GEN(i, Gen::unsigned_int(size - 1));
+    GEN(i, Gen::number_u64(size - 1));
 
 
     auto bitmap = MUST(Bitmap::create(size, init));
     auto bitmap = MUST(Bitmap::create(size, init));
     bitmap.set(i, new_value);
     bitmap.set(i, new_value);
@@ -363,10 +363,10 @@ TEST_CASE(find_first_edge_case)
 RANDOMIZED_TEST_CASE(find_first)
 RANDOMIZED_TEST_CASE(find_first)
 {
 {
     GEN(init, Gen::boolean());
     GEN(init, Gen::boolean());
-    GEN(size, Gen::unsigned_int(1, 64));
+    GEN(size, Gen::number_u64(1, 64));
 
 
     GEN(new_value, Gen::boolean());
     GEN(new_value, Gen::boolean());
-    GEN(i, Gen::unsigned_int(size - 1));
+    GEN(i, Gen::number_u64(size - 1));
 
 
     auto bitmap = MUST(Bitmap::create(size, init));
     auto bitmap = MUST(Bitmap::create(size, init));
     bitmap.set(i, new_value);
     bitmap.set(i, new_value);

+ 4 - 4
Tests/AK/TestBuiltinWrappers.cpp

@@ -72,13 +72,13 @@ RANDOMIZED_TEST_CASE(count_leading_zeroes)
 {
 {
     //    count_leading_zeroes(0b000...0001000...000)
     //    count_leading_zeroes(0b000...0001000...000)
     // == count_leading_zeroes(0b000...0001___...___) (where _ is 0 or 1)
     // == count_leading_zeroes(0b000...0001___...___) (where _ is 0 or 1)
-    GEN(e, Gen::unsigned_int(0, 63));
+    GEN(e, Gen::number_u64(0, 63));
     auto power_of_two = 1ULL << e;
     auto power_of_two = 1ULL << e;
 
 
     // We add random one-bits below the leftmost (and only) one-bit.
     // We add random one-bits below the leftmost (and only) one-bit.
     // This shouldn't change the output of count_leading_zeroes because
     // This shouldn't change the output of count_leading_zeroes because
     // the function should only care about the most significant one.
     // the function should only care about the most significant one.
-    GEN(below, Gen::unsigned_int(0, power_of_two - 1));
+    GEN(below, Gen::number_u64(0, power_of_two - 1));
     auto n = power_of_two + below;
     auto n = power_of_two + below;
 
 
     EXPECT_EQ(count_leading_zeroes(n), count_leading_zeroes(power_of_two));
     EXPECT_EQ(count_leading_zeroes(n), count_leading_zeroes(power_of_two));
@@ -89,7 +89,7 @@ RANDOMIZED_TEST_CASE(count_required_bits)
     // count_required_bits(n) == log2(n) + 1
     // count_required_bits(n) == log2(n) + 1
 
 
     // log2(0) is -infinity, we don't care about that
     // log2(0) is -infinity, we don't care about that
-    GEN(n, Gen::unsigned_int(1, NumericLimits<u32>::max()));
+    GEN(n, Gen::number_u32(1, NumericLimits<u32>::max()));
 
 
     size_t expected = AK::log2(static_cast<double>(n)) + 1;
     size_t expected = AK::log2(static_cast<double>(n)) + 1;
 
 
@@ -99,6 +99,6 @@ RANDOMIZED_TEST_CASE(count_required_bits)
 RANDOMIZED_TEST_CASE(bit_scan_forward_count_trailing_zeroes)
 RANDOMIZED_TEST_CASE(bit_scan_forward_count_trailing_zeroes)
 {
 {
     // Behaviour for 0 differs, so we skip it.
     // Behaviour for 0 differs, so we skip it.
-    GEN(n, Gen::unsigned_int(1, 1 << 31));
+    GEN(n, Gen::number_u32(1, 1 << 31));
     EXPECT_EQ(bit_scan_forward(n), count_trailing_zeroes(n) + 1);
     EXPECT_EQ(bit_scan_forward(n), count_trailing_zeroes(n) + 1);
 }
 }

+ 2 - 2
Tests/AK/TestCharacterTypes.cpp

@@ -42,7 +42,7 @@ void randomized_compare_bool_output_over(u32 range, auto& old_function, auto& ne
     for (u32 n = 0; n < 100; ++n) {
     for (u32 n = 0; n < 100; ++n) {
         bool result1 = false;
         bool result1 = false;
         bool result2 = false;
         bool result2 = false;
-        GEN(i, Gen::unsigned_int(range - 1));
+        GEN(i, Gen::number_u64(range - 1));
         EXPECT_EQ(result1 = (old_function(i) > 0), result2 = (new_function(i) > 0));
         EXPECT_EQ(result1 = (old_function(i) > 0), result2 = (new_function(i) > 0));
         if (result1 != result2)
         if (result1 != result2)
             FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));
             FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));
@@ -55,7 +55,7 @@ void randomized_compare_value_output_over(u32 range, auto& old_function, auto& n
     for (u32 n = 0; n < 100; ++n) {
     for (u32 n = 0; n < 100; ++n) {
         i64 result1 = false;
         i64 result1 = false;
         i64 result2 = false;
         i64 result2 = false;
-        GEN(i, Gen::unsigned_int(range - 1));
+        GEN(i, Gen::number_u64(range - 1));
         EXPECT_EQ(result1 = old_function(i), result2 = new_function(i));
         EXPECT_EQ(result1 = old_function(i), result2 = new_function(i));
         if (result1 != result2)
         if (result1 != result2)
             FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));
             FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));

+ 67 - 18
Tests/LibTest/TestGenerator.cpp

@@ -7,46 +7,47 @@
 #include <AK/StdLibExtras.h>
 #include <AK/StdLibExtras.h>
 #include <LibTest/Randomized/Generator.h>
 #include <LibTest/Randomized/Generator.h>
 #include <LibTest/TestCase.h>
 #include <LibTest/TestCase.h>
+#include <math.h>
 
 
 using namespace Test::Randomized;
 using namespace Test::Randomized;
 
 
-RANDOMIZED_TEST_CASE(unsigned_int_max_bounds)
+RANDOMIZED_TEST_CASE(number_u64_max_bounds)
 {
 {
-    GEN(n, Gen::unsigned_int(10));
+    GEN(n, Gen::number_u64(10));
     EXPECT(n <= 10);
     EXPECT(n <= 10);
 }
 }
 
 
-RANDOMIZED_TEST_CASE(unsigned_int_min_max_bounds)
+RANDOMIZED_TEST_CASE(number_u64_min_max_bounds)
 {
 {
-    GEN(n, Gen::unsigned_int(3, 6));
+    GEN(n, Gen::number_u64(3, 6));
     EXPECT(n >= 3 && n <= 6);
     EXPECT(n >= 3 && n <= 6);
 }
 }
 
 
 RANDOMIZED_TEST_CASE(assume)
 RANDOMIZED_TEST_CASE(assume)
 {
 {
-    GEN(n, Gen::unsigned_int(10));
+    GEN(n, Gen::number_u64(10));
     ASSUME(n % 2 == 0); // This will try to generate until it finds an even number
     ASSUME(n % 2 == 0); // This will try to generate until it finds an even number
     EXPECT(n % 2 == 0); // This will then succeed
     EXPECT(n % 2 == 0); // This will then succeed
     // It will give up if the value doesn't pass the ASSUME(...) predicate 15 times in a row.
     // It will give up if the value doesn't pass the ASSUME(...) predicate 15 times in a row.
 }
 }
 
 
-// TODO find a way to test that a test "unsigned_int(3) can't reach 0" fails
-// TODO find a way to test that a test "unsigned_int(3) can't reach 3" fails
-// TODO find a way to test that a test "unsigned_int(3,6) can't reach 3" fails
-// TODO find a way to test that a test "unsigned_int(3,6) can't reach 6" fails
-// TODO find a way to test that a test "unsigned_int(10) can reach n>10" fails
+// TODO find a way to test that a test "number_u64(3) can't reach 0" fails
+// TODO find a way to test that a test "number_u64(3) can't reach 3" fails
+// TODO find a way to test that a test "number_u64(3,6) can't reach 3" fails
+// TODO find a way to test that a test "number_u64(3,6) can't reach 6" fails
+// TODO find a way to test that a test "number_u64(10) can reach n>10" fails
 
 
 RANDOMIZED_TEST_CASE(map_like)
 RANDOMIZED_TEST_CASE(map_like)
 {
 {
-    GEN(n1, Gen::unsigned_int(10));
+    GEN(n1, Gen::number_u64(10));
     GEN(n2, n1 * 2);
     GEN(n2, n1 * 2);
     EXPECT(n2 % 2 == 0);
     EXPECT(n2 % 2 == 0);
 }
 }
 
 
 RANDOMIZED_TEST_CASE(bind_like)
 RANDOMIZED_TEST_CASE(bind_like)
 {
 {
-    GEN(n1, Gen::unsigned_int(1, 9));
-    GEN(n2, Gen::unsigned_int(n1 * 10, n1 * 100));
+    GEN(n1, Gen::number_u64(1, 9));
+    GEN(n2, Gen::number_u64(n1 * 10, n1 * 100));
     EXPECT(n2 >= 10 && n2 <= 900);
     EXPECT(n2 >= 10 && n2 <= 900);
 }
 }
 
 
@@ -68,7 +69,7 @@ RANDOMIZED_TEST_CASE(bind_like)
 template<typename FN>
 template<typename FN>
 Vector<InvokeResult<FN>> vector_suboptimal(FN item_gen)
 Vector<InvokeResult<FN>> vector_suboptimal(FN item_gen)
 {
 {
-    u32 length = Gen::unsigned_int(5);
+    u32 length = Gen::number_u64(5);
     Vector<InvokeResult<FN>> acc;
     Vector<InvokeResult<FN>> acc;
     for (u32 i = 0; i < length; ++i) {
     for (u32 i = 0; i < length; ++i) {
         acc.append(item_gen());
         acc.append(item_gen());
@@ -79,7 +80,7 @@ Vector<InvokeResult<FN>> vector_suboptimal(FN item_gen)
 RANDOMIZED_TEST_CASE(bind_vector_suboptimal)
 RANDOMIZED_TEST_CASE(bind_vector_suboptimal)
 {
 {
     u32 max_item = 5;
     u32 max_item = 5;
-    GEN(vec, vector_suboptimal([&]() { return Gen::unsigned_int(max_item); }));
+    GEN(vec, vector_suboptimal([&]() { return Gen::number_u64(max_item); }));
     u32 sum = 0;
     u32 sum = 0;
     for (u32 n : vec) {
     for (u32 n : vec) {
         sum += n;
         sum += n;
@@ -90,21 +91,21 @@ RANDOMIZED_TEST_CASE(bind_vector_suboptimal)
 RANDOMIZED_TEST_CASE(vector)
 RANDOMIZED_TEST_CASE(vector)
 {
 {
     u32 max_item = 5;
     u32 max_item = 5;
-    GEN(vec, Gen::vector([&]() { return Gen::unsigned_int(max_item); }));
+    GEN(vec, Gen::vector([&]() { return Gen::number_u64(max_item); }));
     EXPECT(vec.size() <= 32);
     EXPECT(vec.size() <= 32);
 }
 }
 
 
 RANDOMIZED_TEST_CASE(vector_length)
 RANDOMIZED_TEST_CASE(vector_length)
 {
 {
     u32 max_item = 5;
     u32 max_item = 5;
-    GEN(vec, Gen::vector(3, [&]() { return Gen::unsigned_int(max_item); }));
+    GEN(vec, Gen::vector(3, [&]() { return Gen::number_u64(max_item); }));
     EXPECT(vec.size() == 3);
     EXPECT(vec.size() == 3);
 }
 }
 
 
 RANDOMIZED_TEST_CASE(vector_min_max)
 RANDOMIZED_TEST_CASE(vector_min_max)
 {
 {
     u32 max_item = 5;
     u32 max_item = 5;
-    GEN(vec, Gen::vector(1, 4, [&]() { return Gen::unsigned_int(max_item); }));
+    GEN(vec, Gen::vector(1, 4, [&]() { return Gen::number_u64(max_item); }));
     EXPECT(vec.size() >= 1 && vec.size() <= 4);
     EXPECT(vec.size() >= 1 && vec.size() <= 4);
 }
 }
 
 
@@ -160,9 +161,57 @@ RANDOMIZED_TEST_CASE(boolean_false)
     EXPECT(b == false);
     EXPECT(b == false);
 }
 }
 
 
+RANDOMIZED_TEST_CASE(one_of_int)
+{
+    GEN(x, Gen::one_of(1, 2));
+    EXPECT(x == 1 || x == 2);
+}
+
 RANDOMIZED_TEST_CASE(frequency_int)
 RANDOMIZED_TEST_CASE(frequency_int)
 {
 {
     GEN(x, Gen::frequency(Gen::Choice { 5, 'x' }, Gen::Choice { 1, 'o' }));
     GEN(x, Gen::frequency(Gen::Choice { 5, 'x' }, Gen::Choice { 1, 'o' }));
     ASSUME(x == 'x');
     ASSUME(x == 'x');
     EXPECT(x == 'x');
     EXPECT(x == 'x');
 }
 }
+
+RANDOMIZED_TEST_CASE(percentage)
+{
+    GEN(x, Gen::percentage());
+    EXPECT(x >= 0 && x <= 1);
+}
+
+RANDOMIZED_TEST_CASE(number_f64_max_bounds)
+{
+    GEN(x, Gen::number_f64(10));
+    EXPECT(x <= 10);
+}
+
+RANDOMIZED_TEST_CASE(number_f64_min_max_bounds)
+{
+    GEN(x, Gen::number_f64(-10, 10));
+    EXPECT(x >= -10 && x <= 10);
+}
+
+RANDOMIZED_TEST_CASE(number_f64_never_nan)
+{
+    GEN(x, Gen::number_f64());
+    EXPECT(!isnan(x));
+}
+
+RANDOMIZED_TEST_CASE(number_f64_never_infinite)
+{
+    GEN(x, Gen::number_f64());
+    EXPECT(!isinf(x));
+}
+
+RANDOMIZED_TEST_CASE(number_u32_max_bounds)
+{
+    GEN(n, Gen::number_u32(10));
+    EXPECT(n <= 10);
+}
+
+RANDOMIZED_TEST_CASE(number_u32_min_max_bounds)
+{
+    GEN(n, Gen::number_u32(3, 6));
+    EXPECT(n >= 3 && n <= 6);
+}

+ 168 - 53
Userland/Libraries/LibTest/Randomized/Generator.h

@@ -15,22 +15,24 @@
 #include <AK/StringView.h>
 #include <AK/StringView.h>
 #include <AK/Tuple.h>
 #include <AK/Tuple.h>
 
 
+#include <math.h>
+
 namespace Test {
 namespace Test {
 namespace Randomized {
 namespace Randomized {
 
 
 // Returns a random double value in range 0..1.
 // Returns a random double value in range 0..1.
-inline double get_random_probability()
+// This is not a generator. It is meant to be used inside RandomnessSource::draw_value().
+// Based on: https://dotat.at/@/2023-06-23-random-double.html
+inline f64 get_random_probability()
 {
 {
-    static constexpr u32 max_u32 = NumericLimits<u32>::max();
-    u32 random_u32 = AK::get_random_uniform(max_u32);
-    return static_cast<double>(random_u32) / static_cast<double>(max_u32);
+    return static_cast<f64>(AK::get_random<u64>() >> 11) * 0x1.0p-53;
 }
 }
 
 
 // Generators take random bits from the RandomnessSource and return a value
 // Generators take random bits from the RandomnessSource and return a value
 // back.
 // back.
 //
 //
 // Example:
 // Example:
-// - Gen::u32(5,10) --> 9, 7, 5, 10, 8, ...
+// - Gen::number_u64(5,10) --> 9, 7, 5, 10, 8, ...
 namespace Gen {
 namespace Gen {
 
 
 // An unsigned integer generator.
 // An unsigned integer generator.
@@ -38,41 +40,41 @@ namespace Gen {
 // The minimum value will always be 0.
 // The minimum value will always be 0.
 // The maximum value is given by user in the argument.
 // The maximum value is given by user in the argument.
 //
 //
-// Gen::unsigned_int(10) -> value 5, RandomRun [5]
-//                       -> value 8, RandomRun [8]
-//                       etc.
+// Gen::number_u64(10) -> value 5, RandomRun [5]
+//                     -> value 8, RandomRun [8]
+//                     etc.
 //
 //
 // Shrinks towards 0.
 // Shrinks towards 0.
-inline u32 unsigned_int(u32 max)
+inline u64 number_u64(u64 max)
 {
 {
     if (max == 0)
     if (max == 0)
         return 0;
         return 0;
 
 
-    u32 random = Test::randomness_source().draw_value(max, [&]() {
-        // `clamp` to guard against integer overflow and calling get_random_uniform(0).
-        u32 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u32>::max());
-        return AK::get_random_uniform(exclusive_bound);
+    u64 random = Test::randomness_source().draw_value(max, [&]() {
+        // `clamp` to guard against integer overflow
+        u64 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u64>::max());
+        return AK::get_random_uniform_64(exclusive_bound);
     });
     });
     return random;
     return random;
 }
 }
 
 
 // An unsigned integer generator in a particular range.
 // An unsigned integer generator in a particular range.
 //
 //
-// Gen::unsigned_int(3,10) -> value 3,  RandomRun [0]
-//                         -> value 8,  RandomRun [5]
-//                         -> value 10, RandomRun [7]
-//                         etc.
+// Gen::number_u64(3,10) -> value 3,  RandomRun [0]
+//                       -> value 8,  RandomRun [5]
+//                       -> value 10, RandomRun [7]
+//                       etc.
 //
 //
 // In case `min == max`, the RandomRun footprint will be smaller: no randomness
 // In case `min == max`, the RandomRun footprint will be smaller: no randomness
 // is needed.
 // is needed.
 //
 //
-// Gen::unsigned_int(3,3) -> value 3, RandomRun [] (always)
+// Gen::number_u64(3,3) -> value 3, RandomRun [] (always)
 //
 //
 // Shrinks towards the minimum.
 // Shrinks towards the minimum.
-inline u32 unsigned_int(u32 min, u32 max)
+inline u64 number_u64(u64 min, u64 max)
 {
 {
     VERIFY(max >= min);
     VERIFY(max >= min);
-    return unsigned_int(max - min) + min;
+    return number_u64(max - min) + min;
 }
 }
 
 
 // Randomly (uniformly) selects a value out of the given arguments.
 // Randomly (uniformly) selects a value out of the given arguments.
@@ -89,7 +91,7 @@ CommonType<Ts...> one_of(Ts... choices)
     Vector<CommonType<Ts...>> choices_vec { choices... };
     Vector<CommonType<Ts...>> choices_vec { choices... };
 
 
     constexpr size_t count = sizeof...(choices);
     constexpr size_t count = sizeof...(choices);
-    size_t i = unsigned_int(count - 1);
+    size_t i = number_u64(count - 1);
     return choices_vec[i];
     return choices_vec[i];
 }
 }
 
 
@@ -118,16 +120,16 @@ CommonType<Ts...> frequency(Choice<Ts>... choices)
 {
 {
     Vector<Choice<CommonType<Ts...>>> choices_vec { choices... };
     Vector<Choice<CommonType<Ts...>>> choices_vec { choices... };
 
 
-    u32 sum = 0;
+    u64 sum = 0;
     for (auto const& choice : choices_vec) {
     for (auto const& choice : choices_vec) {
         VERIFY(choice.weight > 0);
         VERIFY(choice.weight > 0);
-        sum += static_cast<u32>(choice.weight);
+        sum += static_cast<u64>(choice.weight);
     }
     }
 
 
-    u32 target = unsigned_int(sum);
+    u64 target = number_u64(sum);
     size_t i = 0;
     size_t i = 0;
     for (auto const& choice : choices_vec) {
     for (auto const& choice : choices_vec) {
-        u32 weight = static_cast<u32>(choice.weight);
+        u64 weight = static_cast<u64>(choice.weight);
         if (weight >= target) {
         if (weight >= target) {
             return choice.value;
             return choice.value;
         }
         }
@@ -137,46 +139,47 @@ CommonType<Ts...> frequency(Choice<Ts>... choices)
     return choices_vec[i - 1].value;
     return choices_vec[i - 1].value;
 }
 }
 
 
-// An unsigned integer generator in the full u32 range.
+// An unsigned integer generator in the full u64 range.
 //
 //
-// 8/17 (47%) of the time it will bias towards 8bit numbers,
-// 4/17 (23%) towards 4bit numbers,
-// 2/17 (12%) towards 16bit numbers,
-// 1/17 (6%) towards 32bit numbers,
-// 2/17 (12%) towards edge cases like 0 and NumericLimits::max() of various unsigned int types.
+// Prefers 8bit numbers, then 4bit, 16bit, 32bit and 64bit ones.
+// Around 11% of the time it tries edge cases like 0 and various NumericLimits::max().
 //
 //
-// Gen::unsigned_int() -> value 3,     RandomRun [0,3]
-//                     -> value 8,     RandomRun [1,8]
-//                     -> value 100,   RandomRun [2,100]
-//                     -> value 5,     RandomRun [3,5]
-//                     -> value 255,   RandomRun [4,1]
-//                     -> value 65535, RandomRun [4,2]
-//                     etc.
+// Gen::number_u64() -> value 3,     RandomRun [0,3]
+//                   -> value 8,     RandomRun [1,8]
+//                   -> value 100,   RandomRun [2,100]
+//                   -> value 5,     RandomRun [3,5]
+//                   -> value 255,   RandomRun [4,1]
+//                   -> value 65535, RandomRun [4,2]
+//                   etc.
 //
 //
 // Shrinks towards 0.
 // Shrinks towards 0.
-inline u32 unsigned_int()
+inline u64 number_u64()
 {
 {
-    u32 bits = frequency(
+    u64 bits = frequency(
         // weight, bits
         // weight, bits
         Choice { 4, 4 },
         Choice { 4, 4 },
         Choice { 8, 8 },
         Choice { 8, 8 },
         Choice { 2, 16 },
         Choice { 2, 16 },
         Choice { 1, 32 },
         Choice { 1, 32 },
+        Choice { 1, 64 },
         Choice { 2, 0 });
         Choice { 2, 0 });
 
 
     // The special cases go last as they can be the most extreme (large) values.
     // The special cases go last as they can be the most extreme (large) values.
 
 
     if (bits == 0) {
     if (bits == 0) {
-        // Special cases, eg. max integers for u8, u16, u32.
+        // Special cases, eg. max integers for u8, u16, u32, u64.
         return one_of(
         return one_of(
             0U,
             0U,
             NumericLimits<u8>::max(),
             NumericLimits<u8>::max(),
             NumericLimits<u16>::max(),
             NumericLimits<u16>::max(),
-            NumericLimits<u32>::max());
+            NumericLimits<u32>::max(),
+            NumericLimits<u64>::max());
     }
     }
 
 
-    u32 max = ((u64)1 << bits) - 1;
-    return unsigned_int(max);
+    u64 max = bits == 64
+        ? NumericLimits<u64>::max()
+        : ((u64)1 << bits) - 1;
+    return number_u64(max);
 }
 }
 
 
 // A generator returning `true` with the given `probability` (0..1).
 // A generator returning `true` with the given `probability` (0..1).
@@ -190,15 +193,15 @@ inline u32 unsigned_int()
 //   -> value true,  RandomRun [1]
 //   -> value true,  RandomRun [1]
 //
 //
 // Shrinks towards false.
 // Shrinks towards false.
-inline bool weighted_boolean(double probability)
+inline bool weighted_boolean(f64 probability)
 {
 {
     if (probability <= 0)
     if (probability <= 0)
         return false;
         return false;
     if (probability >= 1)
     if (probability >= 1)
         return true;
         return true;
 
 
-    u32 random_int = Test::randomness_source().draw_value(1, [&]() {
-        double drawn_probability = get_random_probability();
+    u64 random_int = Test::randomness_source().draw_value(1, [&]() {
+        f64 drawn_probability = get_random_probability();
         return drawn_probability <= probability ? 1 : 0;
         return drawn_probability <= probability ? 1 : 0;
     });
     });
     bool random_bool = random_int == 1;
     bool random_bool = random_int == 1;
@@ -219,7 +222,7 @@ inline bool boolean()
 
 
 // A vector generator of a random length between the given limits.
 // A vector generator of a random length between the given limits.
 //
 //
-// Gen::vector(2,3,[]() { return Gen::unsigned_int(5); })
+// Gen::vector(2,3,[]() { return Gen::number_u64(5); })
 //   -> value [1,5],      RandomRun [1,1,1,5,0]
 //   -> value [1,5],      RandomRun [1,1,1,5,0]
 //   -> value [1,5,0],    RandomRun [1,1,1,5,1,0,0]
 //   -> value [1,5,0],    RandomRun [1,1,1,5,1,0,0]
 //   etc.
 //   etc.
@@ -227,7 +230,7 @@ inline bool boolean()
 // In case `min == max`, the RandomRun footprint will be smaller, as there will
 // In case `min == max`, the RandomRun footprint will be smaller, as there will
 // be no randomness involved in figuring out the length:
 // be no randomness involved in figuring out the length:
 //
 //
-// Gen::vector(3,3,[]() { return Gen::unsigned_int(5); })
+// Gen::vector(3,3,[]() { return Gen::number_u64(5); })
 //   -> value [1,3], RandomRun [1,3]
 //   -> value [1,3], RandomRun [1,3]
 //   -> value [5,2], RandomRun [5,2]
 //   -> value [5,2], RandomRun [5,2]
 //   etc.
 //   etc.
@@ -266,7 +269,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
         ++size;
         ++size;
     }
     }
 
 
-    double average = static_cast<double>(min + max) / 2.0;
+    f64 average = static_cast<f64>(min + max) / 2.0;
     VERIFY(average > 0);
     VERIFY(average > 0);
 
 
     // A geometric distribution: https://en.wikipedia.org/wiki/Geometric_distribution#Moments_and_cumulants
     // A geometric distribution: https://en.wikipedia.org/wiki/Geometric_distribution#Moments_and_cumulants
@@ -279,7 +282,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
     // That gives us `1 - 1/p`. Then, E(X) also contains the final success, so we
     // That gives us `1 - 1/p`. Then, E(X) also contains the final success, so we
     // need to say `1 + average` instead of `average`, as it will mean "our X
     // need to say `1 + average` instead of `average`, as it will mean "our X
     // items + the final failure that stops the process".
     // items + the final failure that stops the process".
-    double probability = 1.0 - 1.0 / (1.0 + average);
+    f64 probability = 1.0 - 1.0 / (1.0 + average);
 
 
     while (size < max) {
     while (size < max) {
         if (weighted_boolean(probability)) {
         if (weighted_boolean(probability)) {
@@ -295,7 +298,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
 
 
 // A vector generator of a given length.
 // A vector generator of a given length.
 //
 //
-// Gen::vector_of_length(3,[]() { return Gen::unsigned_int(5); })
+// Gen::vector_of_length(3,[]() { return Gen::number_u64(5); })
 //   -> value [1,5,0],    RandomRun [1,1,1,5,1,0,0]
 //   -> value [1,5,0],    RandomRun [1,1,1,5,1,0,0]
 //   -> value [2,9,3],    RandomRun [1,2,1,9,1,3,0]
 //   -> value [2,9,3],    RandomRun [1,2,1,9,1,3,0]
 //   etc.
 //   etc.
@@ -312,7 +315,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t length, Fn item_gen)
 // If you need a different length, use vector(max,item_gen) or
 // If you need a different length, use vector(max,item_gen) or
 // vector(min,max,item_gen).
 // vector(min,max,item_gen).
 //
 //
-// Gen::vector([]() { return Gen::unsigned_int(5); })
+// Gen::vector([]() { return Gen::number_u64(5); })
 //   -> value [],         RandomRun [0]
 //   -> value [],         RandomRun [0]
 //   -> value [1],        RandomRun [1,1,0]
 //   -> value [1],        RandomRun [1,1,0]
 //   -> value [1,5],      RandomRun [1,1,1,5,0]
 //   -> value [1,5],      RandomRun [1,1,1,5,0]
@@ -327,6 +330,118 @@ inline Vector<InvokeResult<Fn>> vector(Fn item_gen)
     return vector(0, 32, item_gen);
     return vector(0, 32, item_gen);
 }
 }
 
 
+// A double generator in the [0,1) range.
+//
+// RandomRun footprint: a single number.
+//
+// Shrinks towards 0.
+//
+// Based on: https://dotat.at/@/2023-06-23-random-double.html
+inline f64 percentage()
+{
+    return static_cast<f64>(number_u64() >> 11) * 0x1.0p-53;
+}
+
+// An internal double generator. This one won't make any attempt to shrink nicely.
+// Test writers should use number_f64(f64 min, f64 max) instead.
+inline f64 number_f64_scaled(f64 min, f64 max)
+{
+    VERIFY(max >= min);
+
+    if (min == max)
+        return min;
+
+    f64 p = percentage();
+    return min * (1.0 - p) + max * p;
+}
+
+inline f64 number_f64(f64 min, f64 max)
+{
+    // FIXME: after we figure out how to use frequency() with lambdas,
+    // do edge cases and nicely shrinking float generators here
+
+    return number_f64_scaled(min, max);
+}
+
+inline f64 number_f64()
+{
+    // FIXME: this could be much nicer to the user, at the expense of code complexity
+    // We could follow Hypothesis' lead and remap integers 0..MAXINT to _simple_
+    // floats rather than small floats. Meaning, we would like to prefer integers
+    // over floats with decimal digits, positive numbers over negative numbers etc.
+    // As a result, users would get failures with floats like 0, 1, or 0.5 instead of
+    // ones like 1.175494e-38.
+    // Check the doc comment in Hypothesis: https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/src/hypothesis/internal/conjecture/floats.py
+
+    return number_f64(NumericLimits<f64>::lowest(), NumericLimits<f64>::max());
+}
+
+// A double generator.
+//
+// The minimum value will always be NumericLimits<f64>::lowest().
+// The maximum value is given by user in the argument.
+//
+// Prefers positive numbers, then negative numbers, then edge cases.
+//
+// Shrinks towards 0.
+inline f64 number_f64(f64 max)
+{
+    // FIXME: after we figure out how to use frequency() with lambdas,
+    // do edge cases and nicely shrinking float generators here
+
+    return number_f64_scaled(NumericLimits<f64>::lowest(), max);
+}
+
+// TODO
+inline u32 number_u32(u32 max)
+{
+    if (max == 0)
+        return 0;
+
+    u32 random = Test::randomness_source().draw_value(max, [&]() {
+        // `clamp` to guard against integer overflow
+        u32 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u32>::max());
+        return AK::get_random_uniform(exclusive_bound);
+    });
+    return random;
+}
+
+// TODO
+inline u32 number_u32(u32 min, u32 max)
+{
+    VERIFY(max >= min);
+    return number_u32(max - min) + min;
+}
+
+// TODO
+inline u32 number_u32()
+{
+    u32 bits = frequency(
+        // weight, bits
+        Choice { 4, 4 },
+        Choice { 8, 8 },
+        Choice { 2, 16 },
+        Choice { 1, 32 },
+        Choice { 1, 64 },
+        Choice { 2, 0 });
+
+    // The special cases go last as they can be the most extreme (large) values.
+
+    if (bits == 0) {
+        // Special cases, eg. max integers for u8, u16, u32.
+        return one_of(
+            0U,
+            NumericLimits<u8>::max(),
+            NumericLimits<u16>::max(),
+            NumericLimits<u32>::max());
+    }
+
+    u32 max = bits == 32
+        ? NumericLimits<u32>::max()
+        : ((u32)1 << bits) - 1;
+    return number_u32(max);
+}
+
 } // namespace Gen
 } // namespace Gen
 } // namespace Randomized
 } // namespace Randomized
 } // namespace Test
 } // namespace Test

+ 10 - 10
Userland/Libraries/LibTest/Randomized/RandomRun.h

@@ -29,24 +29,24 @@ public:
     RandomRun() = default;
     RandomRun() = default;
     RandomRun(RandomRun const& rhs) = default;
     RandomRun(RandomRun const& rhs) = default;
     RandomRun& operator=(RandomRun const& rhs) = default;
     RandomRun& operator=(RandomRun const& rhs) = default;
-    explicit RandomRun(Vector<u32> const& data)
+    explicit RandomRun(Vector<u64> const& data)
         : m_data(move(data))
         : m_data(move(data))
     {
     {
     }
     }
     bool is_empty() const { return m_data.is_empty(); }
     bool is_empty() const { return m_data.is_empty(); }
     bool contains_chunk(Chunk const& c) const { return c.index + c.size <= m_data.size(); }
     bool contains_chunk(Chunk const& c) const { return c.index + c.size <= m_data.size(); }
-    void append(u32 n) { m_data.append(n); }
+    void append(u64 n) { m_data.append(n); }
     size_t size() const { return m_data.size(); }
     size_t size() const { return m_data.size(); }
-    Optional<u32> next()
+    Optional<u64> next()
     {
     {
         if (m_current_index < m_data.size()) {
         if (m_current_index < m_data.size()) {
             return m_data[m_current_index++];
             return m_data[m_current_index++];
         }
         }
-        return Optional<u32> {};
+        return Optional<u64> {};
     }
     }
-    u32& operator[](size_t index) { return m_data[index]; }
-    u32 const& operator[](size_t index) const { return m_data[index]; }
-    Vector<u32> data() const { return m_data; }
+    u64& operator[](size_t index) { return m_data[index]; }
+    u64 const& operator[](size_t index) const { return m_data[index]; }
+    Vector<u64> data() const { return m_data; }
 
 
     // Shortlex sorting
     // Shortlex sorting
     //
     //
@@ -85,7 +85,7 @@ public:
 
 
     RandomRun with_sorted(Chunk c) const
     RandomRun with_sorted(Chunk c) const
     {
     {
-        Vector<u32> new_data = m_data;
+        Vector<u64> new_data = m_data;
         AK::dual_pivot_quick_sort(
         AK::dual_pivot_quick_sort(
             new_data,
             new_data,
             c.index,
             c.index,
@@ -95,13 +95,13 @@ public:
     }
     }
     RandomRun with_deleted(Chunk c) const
     RandomRun with_deleted(Chunk c) const
     {
     {
-        Vector<u32> new_data(m_data);
+        Vector<u64> new_data(m_data);
         new_data.remove(c.index, c.size);
         new_data.remove(c.index, c.size);
         return RandomRun(move(new_data));
         return RandomRun(move(new_data));
     }
     }
 
 
 private:
 private:
-    Vector<u32> m_data;
+    Vector<u64> m_data;
     size_t m_current_index = 0;
     size_t m_current_index = 0;
 };
 };
 
 

+ 2 - 2
Userland/Libraries/LibTest/Randomized/RandomnessSource.h

@@ -26,11 +26,11 @@ public:
     static RandomnessSource live() { return RandomnessSource(RandomRun(), true); }
     static RandomnessSource live() { return RandomnessSource(RandomRun(), true); }
     static RandomnessSource recorded(RandomRun const& run) { return RandomnessSource(run, false); }
     static RandomnessSource recorded(RandomRun const& run) { return RandomnessSource(run, false); }
     RandomRun& run() { return m_run; }
     RandomRun& run() { return m_run; }
-    u32 draw_value(u32 max, Function<u32()> random_generator)
+    u64 draw_value(u64 max, Function<u64()> random_generator)
     {
     {
         // Live: use the random generator and remember the value.
         // Live: use the random generator and remember the value.
         if (m_is_live) {
         if (m_is_live) {
-            u32 value = random_generator();
+            u64 value = random_generator();
             m_run.append(value);
             m_run.append(value);
             return value;
             return value;
         }
         }

+ 9 - 9
Userland/Libraries/LibTest/Randomized/Shrink.h

@@ -77,15 +77,15 @@ ShrinkResult keep_if_better(RandomRun const& new_run, RandomRun const& current_b
 }
 }
 
 
 template<typename Fn, typename UpdateRunFn>
 template<typename Fn, typename UpdateRunFn>
-ShrinkResult binary_shrink(u32 orig_low, u32 orig_high, UpdateRunFn update_run, RandomRun const& orig_run, Fn const& test_function)
+ShrinkResult binary_shrink(u64 orig_low, u64 orig_high, UpdateRunFn update_run, RandomRun const& orig_run, Fn const& test_function)
 {
 {
     if (orig_low == orig_high) {
     if (orig_low == orig_high) {
         return no_improvement(orig_run);
         return no_improvement(orig_run);
     }
     }
 
 
     RandomRun current_best = orig_run;
     RandomRun current_best = orig_run;
-    u32 low = orig_low;
-    u32 high = orig_high;
+    u64 low = orig_low;
+    u64 high = orig_high;
 
 
     // Let's try with the best case (low = most shrunk) first
     // Let's try with the best case (low = most shrunk) first
     RandomRun run_with_low = update_run(low, current_best);
     RandomRun run_with_low = update_run(low, current_best);
@@ -111,7 +111,7 @@ ShrinkResult binary_shrink(u32 orig_low, u32 orig_high, UpdateRunFn update_run,
     // pass/reject/overrun.
     // pass/reject/overrun.
     ShrinkResult result = after_low;
     ShrinkResult result = after_low;
     while (low + 1 < high) {
     while (low + 1 < high) {
-        u32 mid = low + (high - low) / 2;
+        u64 mid = low + (high - low) / 2;
         RandomRun run_with_mid = update_run(mid, current_best);
         RandomRun run_with_mid = update_run(mid, current_best);
         ShrinkResult after_mid = keep_if_better(run_with_mid, current_best, test_function);
         ShrinkResult after_mid = keep_if_better(run_with_mid, current_best, test_function);
         switch (after_mid.was_improvement) {
         switch (after_mid.was_improvement) {
@@ -194,7 +194,7 @@ ShrinkResult shrink_delete(DeleteChunkAndMaybeDecPrevious command, RandomRun con
 template<typename Fn>
 template<typename Fn>
 ShrinkResult shrink_minimize(MinimizeChoice command, RandomRun const& run, Fn const& test_function)
 ShrinkResult shrink_minimize(MinimizeChoice command, RandomRun const& run, Fn const& test_function)
 {
 {
-    u32 value = run[command.index];
+    u64 value = run[command.index];
 
 
     // We can't minimize 0! Already the best possible case.
     // We can't minimize 0! Already the best possible case.
     if (value == 0) {
     if (value == 0) {
@@ -204,7 +204,7 @@ ShrinkResult shrink_minimize(MinimizeChoice command, RandomRun const& run, Fn co
     return binary_shrink(
     return binary_shrink(
         0,
         0,
         value,
         value,
-        [&](u32 new_value, RandomRun const& run) {
+        [&](u64 new_value, RandomRun const& run) {
             RandomRun copied_run = run;
             RandomRun copied_run = run;
             copied_run[command.index] = new_value;
             copied_run[command.index] = new_value;
             return copied_run;
             return copied_run;
@@ -236,12 +236,12 @@ ShrinkResult shrink_redistribute(RedistributeChoicesAndMaybeInc command, RandomR
 
 
     ShrinkResult after_swap = keep_if_better(run_after_swap, current_best, test_function);
     ShrinkResult after_swap = keep_if_better(run_after_swap, current_best, test_function);
     current_best = after_swap.run;
     current_best = after_swap.run;
-    u32 constant_sum = current_best[command.right_index] + current_best[command.left_index];
+    u64 constant_sum = current_best[command.right_index] + current_best[command.left_index];
 
 
     ShrinkResult after_redistribute = binary_shrink(
     ShrinkResult after_redistribute = binary_shrink(
         0,
         0,
         current_best[command.left_index],
         current_best[command.left_index],
-        [&](u32 new_value, RandomRun const& run) {
+        [&](u64 new_value, RandomRun const& run) {
             RandomRun copied_run = run;
             RandomRun copied_run = run;
             copied_run[command.left_index] = new_value;
             copied_run[command.left_index] = new_value;
             copied_run[command.right_index] = constant_sum - new_value;
             copied_run[command.right_index] = constant_sum - new_value;
@@ -275,7 +275,7 @@ ShrinkResult shrink_redistribute(RedistributeChoicesAndMaybeInc command, RandomR
     ShrinkResult after_inc_redistribute = binary_shrink(
     ShrinkResult after_inc_redistribute = binary_shrink(
         0,
         0,
         current_best[command.left_index],
         current_best[command.left_index],
-        [&](u32 new_value, RandomRun const& run) {
+        [&](u64 new_value, RandomRun const& run) {
             RandomRun copied_run = run;
             RandomRun copied_run = run;
             copied_run[command.left_index] = new_value;
             copied_run[command.left_index] = new_value;
             copied_run[command.right_index] = constant_sum - new_value;
             copied_run[command.right_index] = constant_sum - new_value;