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