1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7package jsr166;
8
9import java.util.concurrent.ThreadLocalRandom;
10import java.util.concurrent.atomic.AtomicLong;
11import java.util.concurrent.atomic.AtomicReference;
12
13import junit.framework.Test;
14import junit.framework.TestSuite;
15
16public class ThreadLocalRandomTest extends JSR166TestCase {
17
18    // android-note: Removed because the CTS runner does a bad job of
19    // retrying tests that have suite() declarations.
20    //
21    // public static void main(String[] args) {
22    //     main(suite(), args);
23    // }
24    // public static Test suite() {
25    //     return new TestSuite(...);
26    // }
27
28    /*
29     * Testing coverage notes:
30     *
31     * We don't test randomness properties, but only that repeated
32     * calls, up to NCALLS tries, produce at least one different
33     * result.  For bounded versions, we sample various intervals
34     * across multiples of primes.
35     */
36
37    // max numbers of calls to detect getting stuck on one value
38    static final int NCALLS = 10000;
39
40    // max sampled int bound
41    static final int MAX_INT_BOUND = (1 << 28);
42
43    // max sampled long bound
44    static final long MAX_LONG_BOUND = (1L << 42);
45
46    // Number of replications for other checks
47    static final int REPS = 20;
48
49    /**
50     * setSeed throws UnsupportedOperationException
51     */
52    public void testSetSeed() {
53        try {
54            ThreadLocalRandom.current().setSeed(17);
55            shouldThrow();
56        } catch (UnsupportedOperationException success) {}
57    }
58
59    /**
60     * Repeated calls to nextInt produce at least two distinct results
61     */
62    public void testNextInt() {
63        int f = ThreadLocalRandom.current().nextInt();
64        int i = 0;
65        while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
66            ++i;
67        assertTrue(i < NCALLS);
68    }
69
70    /**
71     * Repeated calls to nextLong produce at least two distinct results
72     */
73    public void testNextLong() {
74        long f = ThreadLocalRandom.current().nextLong();
75        int i = 0;
76        while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
77            ++i;
78        assertTrue(i < NCALLS);
79    }
80
81    /**
82     * Repeated calls to nextBoolean produce at least two distinct results
83     */
84    public void testNextBoolean() {
85        boolean f = ThreadLocalRandom.current().nextBoolean();
86        int i = 0;
87        while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
88            ++i;
89        assertTrue(i < NCALLS);
90    }
91
92    /**
93     * Repeated calls to nextFloat produce at least two distinct results
94     */
95    public void testNextFloat() {
96        float f = ThreadLocalRandom.current().nextFloat();
97        int i = 0;
98        while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
99            ++i;
100        assertTrue(i < NCALLS);
101    }
102
103    /**
104     * Repeated calls to nextDouble produce at least two distinct results
105     */
106    public void testNextDouble() {
107        double f = ThreadLocalRandom.current().nextDouble();
108        int i = 0;
109        while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
110            ++i;
111        assertTrue(i < NCALLS);
112    }
113
114    /**
115     * Repeated calls to nextGaussian produce at least two distinct results
116     */
117    public void testNextGaussian() {
118        double f = ThreadLocalRandom.current().nextGaussian();
119        int i = 0;
120        while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
121            ++i;
122        assertTrue(i < NCALLS);
123    }
124
125    /**
126     * nextInt(non-positive) throws IllegalArgumentException
127     */
128    public void testNextIntBoundNonPositive() {
129        ThreadLocalRandom rnd = ThreadLocalRandom.current();
130        for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
131            try {
132                rnd.nextInt(bound);
133                shouldThrow();
134            } catch (IllegalArgumentException success) {}
135        }
136    }
137
138    /**
139     * nextInt(least >= bound) throws IllegalArgumentException
140     */
141    public void testNextIntBadBounds() {
142        int[][] badBoundss = {
143            { 17, 2 },
144            { -42, -42 },
145            { Integer.MAX_VALUE, Integer.MIN_VALUE },
146        };
147        ThreadLocalRandom rnd = ThreadLocalRandom.current();
148        for (int[] badBounds : badBoundss) {
149            try {
150                rnd.nextInt(badBounds[0], badBounds[1]);
151                shouldThrow();
152            } catch (IllegalArgumentException success) {}
153        }
154    }
155
156    /**
157     * nextInt(bound) returns 0 <= value < bound;
158     * repeated calls produce at least two distinct results
159     */
160    public void testNextIntBounded() {
161        // sample bound space across prime number increments
162        for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
163            int f = ThreadLocalRandom.current().nextInt(bound);
164            assertTrue(0 <= f && f < bound);
165            int i = 0;
166            int j;
167            while (i < NCALLS &&
168                   (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
169                assertTrue(0 <= j && j < bound);
170                ++i;
171            }
172            assertTrue(i < NCALLS);
173        }
174    }
175
176    /**
177     * nextInt(least, bound) returns least <= value < bound;
178     * repeated calls produce at least two distinct results
179     */
180    public void testNextIntBounded2() {
181        for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
182            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
183                int f = ThreadLocalRandom.current().nextInt(least, bound);
184                assertTrue(least <= f && f < bound);
185                int i = 0;
186                int j;
187                while (i < NCALLS &&
188                       (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
189                    assertTrue(least <= j && j < bound);
190                    ++i;
191                }
192                assertTrue(i < NCALLS);
193            }
194        }
195    }
196
197    /**
198     * nextLong(non-positive) throws IllegalArgumentException
199     */
200    public void testNextLongBoundNonPositive() {
201        ThreadLocalRandom rnd = ThreadLocalRandom.current();
202        for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
203            try {
204                rnd.nextLong(bound);
205                shouldThrow();
206            } catch (IllegalArgumentException success) {}
207        }
208    }
209
210    /**
211     * nextLong(least >= bound) throws IllegalArgumentException
212     */
213    public void testNextLongBadBounds() {
214        long[][] badBoundss = {
215            { 17L, 2L },
216            { -42L, -42L },
217            { Long.MAX_VALUE, Long.MIN_VALUE },
218        };
219        ThreadLocalRandom rnd = ThreadLocalRandom.current();
220        for (long[] badBounds : badBoundss) {
221            try {
222                rnd.nextLong(badBounds[0], badBounds[1]);
223                shouldThrow();
224            } catch (IllegalArgumentException success) {}
225        }
226    }
227
228    /**
229     * nextLong(bound) returns 0 <= value < bound;
230     * repeated calls produce at least two distinct results
231     */
232    public void testNextLongBounded() {
233        for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
234            long f = ThreadLocalRandom.current().nextLong(bound);
235            assertTrue(0 <= f && f < bound);
236            int i = 0;
237            long j;
238            while (i < NCALLS &&
239                   (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
240                assertTrue(0 <= j && j < bound);
241                ++i;
242            }
243            assertTrue(i < NCALLS);
244        }
245    }
246
247    /**
248     * nextLong(least, bound) returns least <= value < bound;
249     * repeated calls produce at least two distinct results
250     */
251    public void testNextLongBounded2() {
252        for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
253            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
254                long f = ThreadLocalRandom.current().nextLong(least, bound);
255                assertTrue(least <= f && f < bound);
256                int i = 0;
257                long j;
258                while (i < NCALLS &&
259                       (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
260                    assertTrue(least <= j && j < bound);
261                    ++i;
262                }
263                assertTrue(i < NCALLS);
264            }
265        }
266    }
267
268    /**
269     * nextDouble(non-positive) throws IllegalArgumentException
270     */
271    public void testNextDoubleBoundNonPositive() {
272        ThreadLocalRandom rnd = ThreadLocalRandom.current();
273        double[] badBounds = {
274            0.0d,
275            -17.0d,
276            -Double.MIN_VALUE,
277            Double.NEGATIVE_INFINITY,
278            Double.NaN,
279        };
280        for (double bound : badBounds) {
281            try {
282                rnd.nextDouble(bound);
283                shouldThrow();
284            } catch (IllegalArgumentException success) {}
285        }
286    }
287
288    /**
289     * nextDouble(least, bound) returns least <= value < bound;
290     * repeated calls produce at least two distinct results
291     */
292    public void testNextDoubleBounded2() {
293        for (double least = 0.0001; least < 1.0e20; least *= 8) {
294            for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
295                double f = ThreadLocalRandom.current().nextDouble(least, bound);
296                assertTrue(least <= f && f < bound);
297                int i = 0;
298                double j;
299                while (i < NCALLS &&
300                       (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
301                    assertTrue(least <= j && j < bound);
302                    ++i;
303                }
304                assertTrue(i < NCALLS);
305            }
306        }
307    }
308
309    /**
310     * Different threads produce different pseudo-random sequences
311     */
312    public void testDifferentSequences() {
313        // Don't use main thread's ThreadLocalRandom - it is likely to
314        // be polluted by previous tests.
315        final AtomicReference<ThreadLocalRandom> threadLocalRandom =
316            new AtomicReference<ThreadLocalRandom>();
317        final AtomicLong rand = new AtomicLong();
318
319        long firstRand = 0;
320        ThreadLocalRandom firstThreadLocalRandom = null;
321
322        Runnable getRandomState = new CheckedRunnable() {
323            public void realRun() {
324                ThreadLocalRandom current = ThreadLocalRandom.current();
325                assertSame(current, ThreadLocalRandom.current());
326                // test bug: the following is not guaranteed and not true in JDK8
327                //                assertNotSame(current, threadLocalRandom.get());
328                rand.set(current.nextLong());
329                threadLocalRandom.set(current);
330            }};
331
332        Thread first = newStartedThread(getRandomState);
333        awaitTermination(first);
334        firstRand = rand.get();
335        firstThreadLocalRandom = threadLocalRandom.get();
336
337        for (int i = 0; i < NCALLS; i++) {
338            Thread t = newStartedThread(getRandomState);
339            awaitTermination(t);
340            if (firstRand != rand.get())
341                return;
342        }
343        fail("all threads generate the same pseudo-random sequence");
344    }
345
346}
347