Hoist a function to randomize a value by a percentage.

Existing code did this, but in a naive way that wasn't suitable for
general exposure (too easy to misuse). Make bulletproof, test, and
expose.

Bug: 364987728
Change-Id: I2f145d95b5dc3eed90c44b71a8b3cf181d5804ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6135479
Owners-Override: Daniel Cheng <[email protected]>
Reviewed-by: Ryan Hansberry <[email protected]>
Commit-Queue: Peter Kasting <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Auto-Submit: Peter Kasting <[email protected]>
Code-Coverage: [email protected] <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1407343}
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
index 8b98e31..6aba609 100644
--- a/base/rand_util_unittest.cc
+++ b/base/rand_util_unittest.cc
@@ -59,6 +59,14 @@
   EXPECT_LE(0.f, number);
 }
 
+TEST(RandUtilTest, RandBool) {
+  // This test should finish extremely quickly unless `RandBool()` can only give
+  // one result value.
+  for (bool seen_false = false, seen_true = false; !seen_false || !seen_true;) {
+    (RandBool() ? seen_true : seen_false) = true;
+  }
+}
+
 TEST(RandUtilTest, RandTimeDelta) {
   {
     const auto delta =
@@ -86,6 +94,23 @@
   EXPECT_LT(delta, base::Seconds(2));
 }
 
+TEST(RandUtilTest, RandomizeByPercentage) {
+  EXPECT_EQ(0, RandomizeByPercentage(0, 100));
+  EXPECT_EQ(100, RandomizeByPercentage(100, 0));
+
+  // Check that 10 +/- 200% will eventually produce values in each range
+  // [-10, 0), [0, 10), [10, 20), [20, 30).
+  for (bool a = false, b = false, c = false, d = false; !a || !b || !c || !d;) {
+    const int r = RandomizeByPercentage(10, 200);
+    EXPECT_GE(r, -10);
+    EXPECT_LT(r, 30);
+    a |= (r < 0);
+    b |= (r >= 0 && r < 10);
+    c |= (r >= 10 && r < 20);
+    d |= (r >= 20);
+  }
+}
+
 TEST(RandUtilTest, BitsToOpenEndedUnitInterval) {
   // Force 64-bit precision, making sure we're not in an 80-bit FPU register.
   volatile double all_zeros = BitsToOpenEndedUnitInterval(0x0);