1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices;
18 
19 import java.util.Random;
20 
21 /**
22  * <p> A mock implementation of java.util.Random that returns preset values.
23  * Useful for making deterministic tests for classes that rely on a random
24  * number sequence. </p>
25  *
26  * <p> The provided array of long or double values is used (in a circular
27  * fashion) instead of a random number generator. The arrays are used to
28  * implement the Random API through appropriate conversions, as follows: </p>
29  *
30  * <ul>
31  *
32  * <li> <code>long[]</code> values are used for <code>next(int)</code>,
33  * <code>nextInt()</code>, <code>nextInt(int)</code>,
34  * <code>nextBoolean()</code>, <code>nextByte()</code>, and
35  * <code>nextLong()</code>. </li>
36  *
37  * <li> <code>double[]</code> values are used for <code>nextFloat()</code>,
38  * <code>nextGaussian()</code>, and <code>nextDouble()</code>. </li>
39  *
40  * </ul>
41  */
42 
43 // Copied from google3/java/com/google/testing/util/MockRandom.java
44 public class MockRandom extends Random {
45 
46     private int mNextLongIndex = 0;
47     private int mNextDoubleIndex = 0;
48     private long[] mLongValues;
49     private double[] mDoubleValues;
50 
MockRandom(long[] longValues, double[] doubleValues)51     public MockRandom(long[] longValues, double[] doubleValues) {
52         this.mLongValues = longValues;
53         this.mDoubleValues = doubleValues;
54     }
55 
MockRandom(long[] longValues)56     public MockRandom(long[] longValues) {
57         this(longValues, null);
58     }
59 
MockRandom(double[] doubleValues)60     public MockRandom(double[] doubleValues) {
61         this(null, doubleValues);
62     }
63 
64     @Override
next(int bits)65     protected synchronized int next(int bits) {
66         return (int) (nextLong() & ((1L << bits) - 1));
67     }
68 
69     @Override
nextBoolean()70     public synchronized boolean nextBoolean() {
71         return nextLong() % 2 == 1;
72     }
73 
74     @Override
nextBytes(byte[] bytes)75     public synchronized void nextBytes(byte[] bytes) {
76         for (int i = 0; i < bytes.length; i++) {
77             bytes[i] = (byte) nextLong();
78         }
79     }
80 
81     @Override
nextDouble()82     public synchronized double nextDouble() {
83         if (mDoubleValues == null) {
84             throw new IllegalStateException("No double values were provided");
85         }
86         double next = mDoubleValues[mNextDoubleIndex];
87         mNextDoubleIndex = (mNextDoubleIndex + 1) % mDoubleValues.length;
88         return next;
89     }
90 
91     @Override
nextFloat()92     public synchronized float nextFloat() {
93         return (float) nextDouble();
94     }
95 
96     @Override
nextGaussian()97     public synchronized double nextGaussian() {
98         return nextDouble();
99     }
100 
101     @Override
nextInt()102     public synchronized int nextInt() {
103         return (int) nextLong();
104     }
105 
106     @Override
nextInt(int n)107     public synchronized int nextInt(int n) {
108         // nextInt() might return a negative number, but this method must not.
109         return (nextInt() & 0x7fffffff) % n;
110     }
111 
112     @Override
nextLong()113     public synchronized long nextLong() {
114         if (mLongValues == null) {
115             throw new IllegalStateException("No long values were provided");
116         }
117         long next = mLongValues[mNextLongIndex];
118         mNextLongIndex = (mNextLongIndex + 1) % mLongValues.length;
119         return next;
120     }
121 
122     @Override
setSeed(long seed)123     public synchronized void setSeed(long seed) {}
124 }
125