RandomTest.java revision 7972:b1f41565b806
1/*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import org.testng.Assert;
25import org.testng.annotations.Test;
26
27import java.util.Random;
28import java.util.concurrent.atomic.AtomicInteger;
29import java.util.concurrent.atomic.LongAdder;
30import java.util.function.BiConsumer;
31
32import static org.testng.Assert.*;
33
34/**
35 * @test
36 * @run testng RandomTest
37 * @summary test methods on Random
38 */
39@Test
40public class RandomTest {
41
42    // Note: this test was adapted from the 166 TCK ThreadLocalRandomTest test
43    // and modified to be a TestNG test
44
45    /*
46     * Testing coverage notes:
47     *
48     * We don't test randomness properties, but only that repeated
49     * calls, up to NCALLS tries, produce at least one different
50     * result.  For bounded versions, we sample various intervals
51     * across multiples of primes.
52     */
53
54    // max numbers of calls to detect getting stuck on one value
55    static final int NCALLS = 10000;
56
57    // max sampled int bound
58    static final int MAX_INT_BOUND = (1 << 28);
59
60    // max sampled long bound
61    static final long MAX_LONG_BOUND = (1L << 42);
62
63    // Number of replications for other checks
64    static final int REPS = 20;
65
66    /**
67     * Repeated calls to nextInt produce at least two distinct results
68     */
69    public void testNextInt() {
70        Random r = new Random();
71        int f = r.nextInt();
72        int i = 0;
73        while (i < NCALLS && r.nextInt() == f)
74            ++i;
75        assertTrue(i < NCALLS);
76    }
77
78    /**
79     * Repeated calls to nextLong produce at least two distinct results
80     */
81    public void testNextLong() {
82        Random r = new Random();
83        long f = r.nextLong();
84        int i = 0;
85        while (i < NCALLS && r.nextLong() == f)
86            ++i;
87        assertTrue(i < NCALLS);
88    }
89
90    /**
91     * Repeated calls to nextBoolean produce at least two distinct results
92     */
93    public void testNextBoolean() {
94        Random r = new Random();
95        boolean f = r.nextBoolean();
96        int i = 0;
97        while (i < NCALLS && r.nextBoolean() == f)
98            ++i;
99        assertTrue(i < NCALLS);
100    }
101
102    /**
103     * Repeated calls to nextFloat produce at least two distinct results
104     */
105    public void testNextFloat() {
106        Random r = new Random();
107        float f = r.nextFloat();
108        int i = 0;
109        while (i < NCALLS && r.nextFloat() == f)
110            ++i;
111        assertTrue(i < NCALLS);
112    }
113
114    /**
115     * Repeated calls to nextDouble produce at least two distinct results
116     */
117    public void testNextDouble() {
118        Random r = new Random();
119        double f = r.nextDouble();
120        int i = 0;
121        while (i < NCALLS && r.nextDouble() == f)
122            ++i;
123        assertTrue(i < NCALLS);
124    }
125
126    /**
127     * Repeated calls to nextGaussian produce at least two distinct results
128     */
129    public void testNextGaussian() {
130        Random r = new Random();
131        double f = r.nextGaussian();
132        int i = 0;
133        while (i < NCALLS && r.nextGaussian() == f)
134            ++i;
135        assertTrue(i < NCALLS);
136    }
137
138    /**
139     * nextInt(negative) throws IllegalArgumentException
140     */
141    @Test(expectedExceptions = IllegalArgumentException.class)
142    public void testNextIntBoundedNeg() {
143        Random r = new Random();
144        int f = r.nextInt(-17);
145    }
146
147    /**
148     * nextInt(bound) returns 0 <= value < bound; repeated calls produce at
149     * least two distinct results
150     */
151    public void testNextIntBounded() {
152        Random r = new Random();
153        // sample bound space across prime number increments
154        for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
155            int f = r.nextInt(bound);
156            assertTrue(0 <= f && f < bound);
157            int i = 0;
158            int j;
159            while (i < NCALLS &&
160                   (j = r.nextInt(bound)) == f) {
161                assertTrue(0 <= j && j < bound);
162                ++i;
163            }
164            assertTrue(i < NCALLS);
165        }
166    }
167
168    /**
169     * Invoking sized ints, long, doubles, with negative sizes throws
170     * IllegalArgumentException
171     */
172    public void testBadStreamSize() {
173        Random r = new Random();
174        executeAndCatchIAE(() -> r.ints(-1L));
175        executeAndCatchIAE(() -> r.ints(-1L, 2, 3));
176        executeAndCatchIAE(() -> r.longs(-1L));
177        executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L));
178        executeAndCatchIAE(() -> r.doubles(-1L));
179        executeAndCatchIAE(() -> r.doubles(-1L, .5, .6));
180    }
181
182    /**
183     * Invoking bounded ints, long, doubles, with illegal bounds throws
184     * IllegalArgumentException
185     */
186    public void testBadStreamBounds() {
187        Random r = new Random();
188        executeAndCatchIAE(() -> r.ints(2, 1));
189        executeAndCatchIAE(() -> r.ints(10, 42, 42));
190        executeAndCatchIAE(() -> r.longs(-1L, -1L));
191        executeAndCatchIAE(() -> r.longs(10, 1L, -2L));
192
193        testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b));
194    }
195
196    // An arbitrary finite double value
197    static final double FINITE = Math.PI;
198
199    void testDoubleBadOriginBound(BiConsumer<Double, Double> bi) {
200        executeAndCatchIAE(() -> bi.accept(17.0, 2.0));
201        executeAndCatchIAE(() -> bi.accept(0.0, 0.0));
202        executeAndCatchIAE(() -> bi.accept(Double.NaN, FINITE));
203        executeAndCatchIAE(() -> bi.accept(FINITE, Double.NaN));
204        executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
205
206        // Returns NaN
207//        executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE));
208//        executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
209
210        executeAndCatchIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY));
211
212        // Returns Double.MAX_VALUE
213//        executeAndCatchIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY));
214
215        executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
216        executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE));
217        executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
218    }
219
220    private void executeAndCatchIAE(Runnable r) {
221        executeAndCatch(IllegalArgumentException.class, r);
222    }
223
224    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
225        Exception caught = null;
226        try {
227            r.run();
228        }
229        catch (Exception e) {
230            caught = e;
231        }
232
233        assertNotNull(caught,
234                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
235                                    expected.getName()));
236        Assert.assertTrue(expected.isInstance(caught),
237                          String.format("Exception thrown %s not an instance of %s",
238                                        caught.getClass().getName(), expected.getName()));
239    }
240
241    /**
242     * A sequential sized stream of ints generates the given number of values
243     */
244    public void testIntsCount() {
245        LongAdder counter = new LongAdder();
246        Random r = new Random();
247        long size = 0;
248        for (int reps = 0; reps < REPS; ++reps) {
249            counter.reset();
250            r.ints(size).forEach(x -> {
251                counter.increment();
252            });
253            assertEquals(counter.sum(), size);
254            size += 524959;
255        }
256    }
257
258    /**
259     * A sequential sized stream of longs generates the given number of values
260     */
261    public void testLongsCount() {
262        LongAdder counter = new LongAdder();
263        Random r = new Random();
264        long size = 0;
265        for (int reps = 0; reps < REPS; ++reps) {
266            counter.reset();
267            r.longs(size).forEach(x -> {
268                counter.increment();
269            });
270            assertEquals(counter.sum(), size);
271            size += 524959;
272        }
273    }
274
275    /**
276     * A sequential sized stream of doubles generates the given number of values
277     */
278    public void testDoublesCount() {
279        LongAdder counter = new LongAdder();
280        Random r = new Random();
281        long size = 0;
282        for (int reps = 0; reps < REPS; ++reps) {
283            counter.reset();
284            r.doubles(size).forEach(x -> {
285                counter.increment();
286            });
287            assertEquals(counter.sum(), size);
288            size += 524959;
289        }
290    }
291
292    /**
293     * Each of a sequential sized stream of bounded ints is within bounds
294     */
295    public void testBoundedInts() {
296        AtomicInteger fails = new AtomicInteger(0);
297        Random r = new Random();
298        long size = 12345L;
299        for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
300            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
301                final int lo = least, hi = bound;
302                r.ints(size, lo, hi).
303                        forEach(x -> {
304                            if (x < lo || x >= hi)
305                                fails.getAndIncrement();
306                        });
307            }
308        }
309        assertEquals(fails.get(), 0);
310    }
311
312    /**
313     * Each of a sequential sized stream of bounded longs is within bounds
314     */
315    public void testBoundedLongs() {
316        AtomicInteger fails = new AtomicInteger(0);
317        Random r = new Random();
318        long size = 123L;
319        for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
320            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
321                final long lo = least, hi = bound;
322                r.longs(size, lo, hi).
323                        forEach(x -> {
324                            if (x < lo || x >= hi)
325                                fails.getAndIncrement();
326                        });
327            }
328        }
329        assertEquals(fails.get(), 0);
330    }
331
332    /**
333     * Each of a sequential sized stream of bounded doubles is within bounds
334     */
335    public void testBoundedDoubles() {
336        AtomicInteger fails = new AtomicInteger(0);
337        Random r = new Random();
338        long size = 456;
339        for (double least = 0.00011; least < 1.0e20; least *= 9) {
340            for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
341                final double lo = least, hi = bound;
342                r.doubles(size, lo, hi).
343                        forEach(x -> {
344                            if (x < lo || x >= hi)
345                                fails.getAndIncrement();
346                        });
347            }
348        }
349        assertEquals(fails.get(), 0);
350    }
351
352    /**
353     * A parallel unsized stream of ints generates at least 100 values
354     */
355    public void testUnsizedIntsCount() {
356        LongAdder counter = new LongAdder();
357        Random r = new Random();
358        long size = 100;
359        r.ints().limit(size).parallel().forEach(x -> {
360            counter.increment();
361        });
362        assertEquals(counter.sum(), size);
363    }
364
365    /**
366     * A parallel unsized stream of longs generates at least 100 values
367     */
368    public void testUnsizedLongsCount() {
369        LongAdder counter = new LongAdder();
370        Random r = new Random();
371        long size = 100;
372        r.longs().limit(size).parallel().forEach(x -> {
373            counter.increment();
374        });
375        assertEquals(counter.sum(), size);
376    }
377
378    /**
379     * A parallel unsized stream of doubles generates at least 100 values
380     */
381    public void testUnsizedDoublesCount() {
382        LongAdder counter = new LongAdder();
383        Random r = new Random();
384        long size = 100;
385        r.doubles().limit(size).parallel().forEach(x -> {
386            counter.increment();
387        });
388        assertEquals(counter.sum(), size);
389    }
390
391    /**
392     * A sequential unsized stream of ints generates at least 100 values
393     */
394    public void testUnsizedIntsCountSeq() {
395        LongAdder counter = new LongAdder();
396        Random r = new Random();
397        long size = 100;
398        r.ints().limit(size).forEach(x -> {
399            counter.increment();
400        });
401        assertEquals(counter.sum(), size);
402    }
403
404    /**
405     * A sequential unsized stream of longs generates at least 100 values
406     */
407    public void testUnsizedLongsCountSeq() {
408        LongAdder counter = new LongAdder();
409        Random r = new Random();
410        long size = 100;
411        r.longs().limit(size).forEach(x -> {
412            counter.increment();
413        });
414        assertEquals(counter.sum(), size);
415    }
416
417    /**
418     * A sequential unsized stream of doubles generates at least 100 values
419     */
420    public void testUnsizedDoublesCountSeq() {
421        LongAdder counter = new LongAdder();
422        Random r = new Random();
423        long size = 100;
424        r.doubles().limit(size).forEach(x -> {
425            counter.increment();
426        });
427        assertEquals(counter.sum(), size);
428    }
429
430}
431