1import unittest
2import unittest.mock
3import random
4import os
5import time
6import pickle
7import warnings
8import test.support
9
10from functools import partial
11from math import log, exp, pi, fsum, sin, factorial
12from test import support
13from fractions import Fraction
14from collections import abc, Counter
15
16class TestBasicOps:
17    # Superclass with tests common to all generators.
18    # Subclasses must arrange for self.gen to retrieve the Random instance
19    # to be tested.
20
21    def randomlist(self, n):
22        """Helper function to make a list of random numbers"""
23        return [self.gen.random() for i in range(n)]
24
25    def test_autoseed(self):
26        self.gen.seed()
27        state1 = self.gen.getstate()
28        time.sleep(0.1)
29        self.gen.seed()      # different seeds at different times
30        state2 = self.gen.getstate()
31        self.assertNotEqual(state1, state2)
32
33    def test_saverestore(self):
34        N = 1000
35        self.gen.seed()
36        state = self.gen.getstate()
37        randseq = self.randomlist(N)
38        self.gen.setstate(state)    # should regenerate the same sequence
39        self.assertEqual(randseq, self.randomlist(N))
40
41    def test_seedargs(self):
42        # Seed value with a negative hash.
43        class MySeed(object):
44            def __hash__(self):
45                return -1729
46        for arg in [None, 0, 1, -1, 10**20, -(10**20),
47                    False, True, 3.14, 'a']:
48            self.gen.seed(arg)
49
50        for arg in [1+2j, tuple('abc'), MySeed()]:
51            with self.assertRaises(TypeError):
52                self.gen.seed(arg)
53
54        for arg in [list(range(3)), dict(one=1)]:
55            self.assertRaises(TypeError, self.gen.seed, arg)
56        self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4)
57        self.assertRaises(TypeError, type(self.gen), [])
58
59    def test_seed_no_mutate_bug_44018(self):
60        a = bytearray(b'1234')
61        self.gen.seed(a)
62        self.assertEqual(a, bytearray(b'1234'))
63
64    @unittest.mock.patch('random._urandom') # os.urandom
65    def test_seed_when_randomness_source_not_found(self, urandom_mock):
66        # Random.seed() uses time.time() when an operating system specific
67        # randomness source is not found. To test this on machines where it
68        # exists, run the above test, test_seedargs(), again after mocking
69        # os.urandom() so that it raises the exception expected when the
70        # randomness source is not available.
71        urandom_mock.side_effect = NotImplementedError
72        self.test_seedargs()
73
74    def test_shuffle(self):
75        shuffle = self.gen.shuffle
76        lst = []
77        shuffle(lst)
78        self.assertEqual(lst, [])
79        lst = [37]
80        shuffle(lst)
81        self.assertEqual(lst, [37])
82        seqs = [list(range(n)) for n in range(10)]
83        shuffled_seqs = [list(range(n)) for n in range(10)]
84        for shuffled_seq in shuffled_seqs:
85            shuffle(shuffled_seq)
86        for (seq, shuffled_seq) in zip(seqs, shuffled_seqs):
87            self.assertEqual(len(seq), len(shuffled_seq))
88            self.assertEqual(set(seq), set(shuffled_seq))
89        # The above tests all would pass if the shuffle was a
90        # no-op. The following non-deterministic test covers that.  It
91        # asserts that the shuffled sequence of 1000 distinct elements
92        # must be different from the original one. Although there is
93        # mathematically a non-zero probability that this could
94        # actually happen in a genuinely random shuffle, it is
95        # completely negligible, given that the number of possible
96        # permutations of 1000 objects is 1000! (factorial of 1000),
97        # which is considerably larger than the number of atoms in the
98        # universe...
99        lst = list(range(1000))
100        shuffled_lst = list(range(1000))
101        shuffle(shuffled_lst)
102        self.assertTrue(lst != shuffled_lst)
103        shuffle(lst)
104        self.assertTrue(lst != shuffled_lst)
105        self.assertRaises(TypeError, shuffle, (1, 2, 3))
106
107    def test_choice(self):
108        choice = self.gen.choice
109        with self.assertRaises(IndexError):
110            choice([])
111        self.assertEqual(choice([50]), 50)
112        self.assertIn(choice([25, 75]), [25, 75])
113
114    def test_choice_with_numpy(self):
115        # Accommodation for NumPy arrays which have disabled __bool__().
116        # See: https://github.com/python/cpython/issues/100805
117        choice = self.gen.choice
118
119        class NA(list):
120            "Simulate numpy.array() behavior"
121            def __bool__(self):
122                raise RuntimeError
123
124        with self.assertRaises(IndexError):
125            choice(NA([]))
126        self.assertEqual(choice(NA([50])), 50)
127        self.assertIn(choice(NA([25, 75])), [25, 75])
128
129    def test_sample(self):
130        # For the entire allowable range of 0 <= k <= N, validate that
131        # the sample is of the correct length and contains only unique items
132        N = 100
133        population = range(N)
134        for k in range(N+1):
135            s = self.gen.sample(population, k)
136            self.assertEqual(len(s), k)
137            uniq = set(s)
138            self.assertEqual(len(uniq), k)
139            self.assertTrue(uniq <= set(population))
140        self.assertEqual(self.gen.sample([], 0), [])  # test edge case N==k==0
141        # Exception raised if size of sample exceeds that of population
142        self.assertRaises(ValueError, self.gen.sample, population, N+1)
143        self.assertRaises(ValueError, self.gen.sample, [], -1)
144
145    def test_sample_distribution(self):
146        # For the entire allowable range of 0 <= k <= N, validate that
147        # sample generates all possible permutations
148        n = 5
149        pop = range(n)
150        trials = 10000  # large num prevents false negatives without slowing normal case
151        for k in range(n):
152            expected = factorial(n) // factorial(n-k)
153            perms = {}
154            for i in range(trials):
155                perms[tuple(self.gen.sample(pop, k))] = None
156                if len(perms) == expected:
157                    break
158            else:
159                self.fail()
160
161    def test_sample_inputs(self):
162        # SF bug #801342 -- population can be any iterable defining __len__()
163        self.gen.sample(range(20), 2)
164        self.gen.sample(range(20), 2)
165        self.gen.sample(str('abcdefghijklmnopqrst'), 2)
166        self.gen.sample(tuple('abcdefghijklmnopqrst'), 2)
167
168    def test_sample_on_dicts(self):
169        self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2)
170
171    def test_sample_on_sets(self):
172        with self.assertRaises(TypeError):
173            population = {10, 20, 30, 40, 50, 60, 70}
174            self.gen.sample(population, k=5)
175
176    def test_sample_on_seqsets(self):
177        class SeqSet(abc.Sequence, abc.Set):
178            def __init__(self, items):
179                self._items = items
180
181            def __len__(self):
182                return len(self._items)
183
184            def __getitem__(self, index):
185                return self._items[index]
186
187        population = SeqSet([2, 4, 1, 3])
188        with warnings.catch_warnings():
189            warnings.simplefilter("error", DeprecationWarning)
190            self.gen.sample(population, k=2)
191
192    def test_sample_with_counts(self):
193        sample = self.gen.sample
194
195        # General case
196        colors = ['red', 'green', 'blue', 'orange', 'black', 'brown', 'amber']
197        counts = [500,      200,     20,       10,       5,       0,       1 ]
198        k = 700
199        summary = Counter(sample(colors, counts=counts, k=k))
200        self.assertEqual(sum(summary.values()), k)
201        for color, weight in zip(colors, counts):
202            self.assertLessEqual(summary[color], weight)
203        self.assertNotIn('brown', summary)
204
205        # Case that exhausts the population
206        k = sum(counts)
207        summary = Counter(sample(colors, counts=counts, k=k))
208        self.assertEqual(sum(summary.values()), k)
209        for color, weight in zip(colors, counts):
210            self.assertLessEqual(summary[color], weight)
211        self.assertNotIn('brown', summary)
212
213        # Case with population size of 1
214        summary = Counter(sample(['x'], counts=[10], k=8))
215        self.assertEqual(summary, Counter(x=8))
216
217        # Case with all counts equal.
218        nc = len(colors)
219        summary = Counter(sample(colors, counts=[10]*nc, k=10*nc))
220        self.assertEqual(summary, Counter(10*colors))
221
222        # Test error handling
223        with self.assertRaises(TypeError):
224            sample(['red', 'green', 'blue'], counts=10, k=10)               # counts not iterable
225        with self.assertRaises(ValueError):
226            sample(['red', 'green', 'blue'], counts=[-3, -7, -8], k=2)      # counts are negative
227        with self.assertRaises(ValueError):
228            sample(['red', 'green', 'blue'], counts=[0, 0, 0], k=2)         # counts are zero
229        with self.assertRaises(ValueError):
230            sample(['red', 'green'], counts=[10, 10], k=21)                 # population too small
231        with self.assertRaises(ValueError):
232            sample(['red', 'green', 'blue'], counts=[1, 2], k=2)            # too few counts
233        with self.assertRaises(ValueError):
234            sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2)      # too many counts
235
236    def test_choices(self):
237        choices = self.gen.choices
238        data = ['red', 'green', 'blue', 'yellow']
239        str_data = 'abcd'
240        range_data = range(4)
241        set_data = set(range(4))
242
243        # basic functionality
244        for sample in [
245            choices(data, k=5),
246            choices(data, range(4), k=5),
247            choices(k=5, population=data, weights=range(4)),
248            choices(k=5, population=data, cum_weights=range(4)),
249        ]:
250            self.assertEqual(len(sample), 5)
251            self.assertEqual(type(sample), list)
252            self.assertTrue(set(sample) <= set(data))
253
254        # test argument handling
255        with self.assertRaises(TypeError):                               # missing arguments
256            choices(2)
257
258        self.assertEqual(choices(data, k=0), [])                         # k == 0
259        self.assertEqual(choices(data, k=-1), [])                        # negative k behaves like ``[0] * -1``
260        with self.assertRaises(TypeError):
261            choices(data, k=2.5)                                         # k is a float
262
263        self.assertTrue(set(choices(str_data, k=5)) <= set(str_data))    # population is a string sequence
264        self.assertTrue(set(choices(range_data, k=5)) <= set(range_data))  # population is a range
265        with self.assertRaises(TypeError):
266            choices(set_data, k=2)                                       # population is not a sequence
267
268        self.assertTrue(set(choices(data, None, k=5)) <= set(data))      # weights is None
269        self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data))
270        with self.assertRaises(ValueError):
271            choices(data, [1,2], k=5)                                    # len(weights) != len(population)
272        with self.assertRaises(TypeError):
273            choices(data, 10, k=5)                                       # non-iterable weights
274        with self.assertRaises(TypeError):
275            choices(data, [None]*4, k=5)                                 # non-numeric weights
276        for weights in [
277                [15, 10, 25, 30],                                                 # integer weights
278                [15.1, 10.2, 25.2, 30.3],                                         # float weights
279                [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional weights
280                [True, False, True, False]                                        # booleans (include / exclude)
281        ]:
282            self.assertTrue(set(choices(data, weights, k=5)) <= set(data))
283
284        with self.assertRaises(ValueError):
285            choices(data, cum_weights=[1,2], k=5)                        # len(weights) != len(population)
286        with self.assertRaises(TypeError):
287            choices(data, cum_weights=10, k=5)                           # non-iterable cum_weights
288        with self.assertRaises(TypeError):
289            choices(data, cum_weights=[None]*4, k=5)                     # non-numeric cum_weights
290        with self.assertRaises(TypeError):
291            choices(data, range(4), cum_weights=range(4), k=5)           # both weights and cum_weights
292        for weights in [
293                [15, 10, 25, 30],                                                 # integer cum_weights
294                [15.1, 10.2, 25.2, 30.3],                                         # float cum_weights
295                [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional cum_weights
296        ]:
297            self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data))
298
299        # Test weight focused on a single element of the population
300        self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a'])
301        self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b'])
302        self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c'])
303        self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d'])
304
305        # Test consistency with random.choice() for empty population
306        with self.assertRaises(IndexError):
307            choices([], k=1)
308        with self.assertRaises(IndexError):
309            choices([], weights=[], k=1)
310        with self.assertRaises(IndexError):
311            choices([], cum_weights=[], k=5)
312
313    def test_choices_subnormal(self):
314        # Subnormal weights would occasionally trigger an IndexError
315        # in choices() when the value returned by random() was large
316        # enough to make `random() * total` round up to the total.
317        # See https://bugs.python.org/msg275594 for more detail.
318        choices = self.gen.choices
319        choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000)
320
321    def test_choices_with_all_zero_weights(self):
322        # See issue #38881
323        with self.assertRaises(ValueError):
324            self.gen.choices('AB', [0.0, 0.0])
325
326    def test_choices_negative_total(self):
327        with self.assertRaises(ValueError):
328            self.gen.choices('ABC', [3, -5, 1])
329
330    def test_choices_infinite_total(self):
331        with self.assertRaises(ValueError):
332            self.gen.choices('A', [float('inf')])
333        with self.assertRaises(ValueError):
334            self.gen.choices('AB', [0.0, float('inf')])
335        with self.assertRaises(ValueError):
336            self.gen.choices('AB', [-float('inf'), 123])
337        with self.assertRaises(ValueError):
338            self.gen.choices('AB', [0.0, float('nan')])
339        with self.assertRaises(ValueError):
340            self.gen.choices('AB', [float('-inf'), float('inf')])
341
342    def test_gauss(self):
343        # Ensure that the seed() method initializes all the hidden state.  In
344        # particular, through 2.2.1 it failed to reset a piece of state used
345        # by (and only by) the .gauss() method.
346
347        for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
348            self.gen.seed(seed)
349            x1 = self.gen.random()
350            y1 = self.gen.gauss(0, 1)
351
352            self.gen.seed(seed)
353            x2 = self.gen.random()
354            y2 = self.gen.gauss(0, 1)
355
356            self.assertEqual(x1, x2)
357            self.assertEqual(y1, y2)
358
359    def test_getrandbits(self):
360        # Verify ranges
361        for k in range(1, 1000):
362            self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
363        self.assertEqual(self.gen.getrandbits(0), 0)
364
365        # Verify all bits active
366        getbits = self.gen.getrandbits
367        for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
368            all_bits = 2**span-1
369            cum = 0
370            cpl_cum = 0
371            for i in range(100):
372                v = getbits(span)
373                cum |= v
374                cpl_cum |= all_bits ^ v
375            self.assertEqual(cum, all_bits)
376            self.assertEqual(cpl_cum, all_bits)
377
378        # Verify argument checking
379        self.assertRaises(TypeError, self.gen.getrandbits)
380        self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
381        self.assertRaises(ValueError, self.gen.getrandbits, -1)
382        self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
383
384    def test_pickling(self):
385        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
386            state = pickle.dumps(self.gen, proto)
387            origseq = [self.gen.random() for i in range(10)]
388            newgen = pickle.loads(state)
389            restoredseq = [newgen.random() for i in range(10)]
390            self.assertEqual(origseq, restoredseq)
391
392    def test_bug_1727780(self):
393        # verify that version-2-pickles can be loaded
394        # fine, whether they are created on 32-bit or 64-bit
395        # platforms, and that version-3-pickles load fine.
396        files = [("randv2_32.pck", 780),
397                 ("randv2_64.pck", 866),
398                 ("randv3.pck", 343)]
399        for file, value in files:
400            with open(support.findfile(file),"rb") as f:
401                r = pickle.load(f)
402            self.assertEqual(int(r.random()*1000), value)
403
404    def test_bug_9025(self):
405        # Had problem with an uneven distribution in int(n*random())
406        # Verify the fix by checking that distributions fall within expectations.
407        n = 100000
408        randrange = self.gen.randrange
409        k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
410        self.assertTrue(0.30 < k/n < .37, (k/n))
411
412    def test_randbytes(self):
413        # Verify ranges
414        for n in range(1, 10):
415            data = self.gen.randbytes(n)
416            self.assertEqual(type(data), bytes)
417            self.assertEqual(len(data), n)
418
419        self.assertEqual(self.gen.randbytes(0), b'')
420
421        # Verify argument checking
422        self.assertRaises(TypeError, self.gen.randbytes)
423        self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
424        self.assertRaises(ValueError, self.gen.randbytes, -1)
425        self.assertRaises(TypeError, self.gen.randbytes, 1.0)
426
427    def test_mu_sigma_default_args(self):
428        self.assertIsInstance(self.gen.normalvariate(), float)
429        self.assertIsInstance(self.gen.gauss(), float)
430
431
432try:
433    random.SystemRandom().random()
434except NotImplementedError:
435    SystemRandom_available = False
436else:
437    SystemRandom_available = True
438
439@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
440class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
441    gen = random.SystemRandom()
442
443    def test_autoseed(self):
444        # Doesn't need to do anything except not fail
445        self.gen.seed()
446
447    def test_saverestore(self):
448        self.assertRaises(NotImplementedError, self.gen.getstate)
449        self.assertRaises(NotImplementedError, self.gen.setstate, None)
450
451    def test_seedargs(self):
452        # Doesn't need to do anything except not fail
453        self.gen.seed(100)
454
455    def test_gauss(self):
456        self.gen.gauss_next = None
457        self.gen.seed(100)
458        self.assertEqual(self.gen.gauss_next, None)
459
460    def test_pickling(self):
461        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
462            self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
463
464    def test_53_bits_per_float(self):
465        # This should pass whenever a C double has 53 bit precision.
466        span = 2 ** 53
467        cum = 0
468        for i in range(100):
469            cum |= int(self.gen.random() * span)
470        self.assertEqual(cum, span-1)
471
472    def test_bigrand(self):
473        # The randrange routine should build-up the required number of bits
474        # in stages so that all bit positions are active.
475        span = 2 ** 500
476        cum = 0
477        for i in range(100):
478            r = self.gen.randrange(span)
479            self.assertTrue(0 <= r < span)
480            cum |= r
481        self.assertEqual(cum, span-1)
482
483    def test_bigrand_ranges(self):
484        for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
485            start = self.gen.randrange(2 ** (i-2))
486            stop = self.gen.randrange(2 ** i)
487            if stop <= start:
488                continue
489            self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
490
491    def test_rangelimits(self):
492        for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
493            self.assertEqual(set(range(start,stop)),
494                set([self.gen.randrange(start,stop) for i in range(100)]))
495
496    def test_randrange_nonunit_step(self):
497        rint = self.gen.randrange(0, 10, 2)
498        self.assertIn(rint, (0, 2, 4, 6, 8))
499        rint = self.gen.randrange(0, 2, 2)
500        self.assertEqual(rint, 0)
501
502    def test_randrange_errors(self):
503        raises = partial(self.assertRaises, ValueError, self.gen.randrange)
504        # Empty range
505        raises(3, 3)
506        raises(-721)
507        raises(0, 100, -12)
508        # Non-integer start/stop
509        self.assertWarns(DeprecationWarning, raises, 3.14159)
510        self.assertWarns(DeprecationWarning, self.gen.randrange, 3.0)
511        self.assertWarns(DeprecationWarning, self.gen.randrange, Fraction(3, 1))
512        self.assertWarns(DeprecationWarning, raises, '3')
513        self.assertWarns(DeprecationWarning, raises, 0, 2.71828)
514        self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 2.0)
515        self.assertWarns(DeprecationWarning, self.gen.randrange, 0, Fraction(2, 1))
516        self.assertWarns(DeprecationWarning, raises, 0, '2')
517        # Zero and non-integer step
518        raises(0, 42, 0)
519        self.assertWarns(DeprecationWarning, raises, 0, 42, 0.0)
520        self.assertWarns(DeprecationWarning, raises, 0, 0, 0.0)
521        self.assertWarns(DeprecationWarning, raises, 0, 42, 3.14159)
522        self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, 3.0)
523        self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, Fraction(3, 1))
524        self.assertWarns(DeprecationWarning, raises, 0, 42, '3')
525        self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, 1.0)
526        self.assertWarns(DeprecationWarning, raises, 0, 0, 1.0)
527
528    def test_randrange_argument_handling(self):
529        randrange = self.gen.randrange
530        with self.assertWarns(DeprecationWarning):
531            randrange(10.0, 20, 2)
532        with self.assertWarns(DeprecationWarning):
533            randrange(10, 20.0, 2)
534        with self.assertWarns(DeprecationWarning):
535            randrange(10, 20, 1.0)
536        with self.assertWarns(DeprecationWarning):
537            randrange(10, 20, 2.0)
538        with self.assertWarns(DeprecationWarning):
539            with self.assertRaises(ValueError):
540                randrange(10.5)
541        with self.assertWarns(DeprecationWarning):
542            with self.assertRaises(ValueError):
543                randrange(10, 20.5)
544        with self.assertWarns(DeprecationWarning):
545            with self.assertRaises(ValueError):
546                randrange(10, 20, 1.5)
547
548    def test_randrange_step(self):
549        # bpo-42772: When stop is None, the step argument was being ignored.
550        randrange = self.gen.randrange
551        with self.assertRaises(TypeError):
552            randrange(1000, step=100)
553        with self.assertRaises(TypeError):
554            randrange(1000, None, step=100)
555
556    def test_randbelow_logic(self, _log=log, int=int):
557        # check bitcount transition points:  2**i and 2**(i+1)-1
558        # show that: k = int(1.001 + _log(n, 2))
559        # is equal to or one greater than the number of bits in n
560        for i in range(1, 1000):
561            n = 1 << i # check an exact power of two
562            numbits = i+1
563            k = int(1.00001 + _log(n, 2))
564            self.assertEqual(k, numbits)
565            self.assertEqual(n, 2**(k-1))
566
567            n += n - 1      # check 1 below the next power of two
568            k = int(1.00001 + _log(n, 2))
569            self.assertIn(k, [numbits, numbits+1])
570            self.assertTrue(2**k > n > 2**(k-2))
571
572            n -= n >> 15     # check a little farther below the next power of two
573            k = int(1.00001 + _log(n, 2))
574            self.assertEqual(k, numbits)        # note the stronger assertion
575            self.assertTrue(2**k > n > 2**(k-1))   # note the stronger assertion
576
577
578class TestRawMersenneTwister(unittest.TestCase):
579    @test.support.cpython_only
580    def test_bug_41052(self):
581        # _random.Random should not be allowed to serialization
582        import _random
583        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
584            r = _random.Random()
585            self.assertRaises(TypeError, pickle.dumps, r, proto)
586
587    @test.support.cpython_only
588    def test_bug_42008(self):
589        # _random.Random should call seed with first element of arg tuple
590        import _random
591        r1 = _random.Random()
592        r1.seed(8675309)
593        r2 = _random.Random(8675309)
594        self.assertEqual(r1.random(), r2.random())
595
596
597class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
598    gen = random.Random()
599
600    def test_guaranteed_stable(self):
601        # These sequences are guaranteed to stay the same across versions of python
602        self.gen.seed(3456147, version=1)
603        self.assertEqual([self.gen.random().hex() for i in range(4)],
604            ['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1',
605             '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1'])
606        self.gen.seed("the quick brown fox", version=2)
607        self.assertEqual([self.gen.random().hex() for i in range(4)],
608            ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4',
609             '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1'])
610
611    def test_bug_27706(self):
612        # Verify that version 1 seeds are unaffected by hash randomization
613
614        self.gen.seed('nofar', version=1)   # hash('nofar') == 5990528763808513177
615        self.assertEqual([self.gen.random().hex() for i in range(4)],
616            ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
617             '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
618
619        self.gen.seed('rachel', version=1)  # hash('rachel') == -9091735575445484789
620        self.assertEqual([self.gen.random().hex() for i in range(4)],
621            ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
622             '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
623
624        self.gen.seed('', version=1)        # hash('') == 0
625        self.assertEqual([self.gen.random().hex() for i in range(4)],
626            ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
627             '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
628
629    def test_bug_31478(self):
630        # There shouldn't be an assertion failure in _random.Random.seed() in
631        # case the argument has a bad __abs__() method.
632        class BadInt(int):
633            def __abs__(self):
634                return None
635        try:
636            self.gen.seed(BadInt())
637        except TypeError:
638            pass
639
640    def test_bug_31482(self):
641        # Verify that version 1 seeds are unaffected by hash randomization
642        # when the seeds are expressed as bytes rather than strings.
643        # The hash(b) values listed are the Python2.7 hash() values
644        # which were used for seeding.
645
646        self.gen.seed(b'nofar', version=1)   # hash('nofar') == 5990528763808513177
647        self.assertEqual([self.gen.random().hex() for i in range(4)],
648            ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
649             '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
650
651        self.gen.seed(b'rachel', version=1)  # hash('rachel') == -9091735575445484789
652        self.assertEqual([self.gen.random().hex() for i in range(4)],
653            ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
654             '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
655
656        self.gen.seed(b'', version=1)        # hash('') == 0
657        self.assertEqual([self.gen.random().hex() for i in range(4)],
658            ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
659             '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
660
661        b = b'\x00\x20\x40\x60\x80\xA0\xC0\xE0\xF0'
662        self.gen.seed(b, version=1)         # hash(b) == 5015594239749365497
663        self.assertEqual([self.gen.random().hex() for i in range(4)],
664            ['0x1.52c2fde444d23p-1', '0x1.875174f0daea4p-2',
665             '0x1.9e9b2c50e5cd2p-1', '0x1.fa57768bd321cp-2'])
666
667    def test_setstate_first_arg(self):
668        self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
669
670    def test_setstate_middle_arg(self):
671        start_state = self.gen.getstate()
672        # Wrong type, s/b tuple
673        self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
674        # Wrong length, s/b 625
675        self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None))
676        # Wrong type, s/b tuple of 625 ints
677        self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None))
678        # Last element s/b an int also
679        self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None))
680        # Last element s/b between 0 and 624
681        with self.assertRaises((ValueError, OverflowError)):
682            self.gen.setstate((2, (1,)*624+(625,), None))
683        with self.assertRaises((ValueError, OverflowError)):
684            self.gen.setstate((2, (1,)*624+(-1,), None))
685        # Failed calls to setstate() should not have changed the state.
686        bits100 = self.gen.getrandbits(100)
687        self.gen.setstate(start_state)
688        self.assertEqual(self.gen.getrandbits(100), bits100)
689
690        # Little trick to make "tuple(x % (2**32) for x in internalstate)"
691        # raise ValueError. I cannot think of a simple way to achieve this, so
692        # I am opting for using a generator as the middle argument of setstate
693        # which attempts to cast a NaN to integer.
694        state_values = self.gen.getstate()[1]
695        state_values = list(state_values)
696        state_values[-1] = float('nan')
697        state = (int(x) for x in state_values)
698        self.assertRaises(TypeError, self.gen.setstate, (2, state, None))
699
700    def test_referenceImplementation(self):
701        # Compare the python implementation with results from the original
702        # code.  Create 2000 53-bit precision random floats.  Compare only
703        # the last ten entries to show that the independent implementations
704        # are tracking.  Here is the main() function needed to create the
705        # list of expected random numbers:
706        #    void main(void){
707        #         int i;
708        #         unsigned long init[4]={61731, 24903, 614, 42143}, length=4;
709        #         init_by_array(init, length);
710        #         for (i=0; i<2000; i++) {
711        #           printf("%.15f ", genrand_res53());
712        #           if (i%5==4) printf("\n");
713        #         }
714        #     }
715        expected = [0.45839803073713259,
716                    0.86057815201978782,
717                    0.92848331726782152,
718                    0.35932681119782461,
719                    0.081823493762449573,
720                    0.14332226470169329,
721                    0.084297823823520024,
722                    0.53814864671831453,
723                    0.089215024911993401,
724                    0.78486196105372907]
725
726        self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
727        actual = self.randomlist(2000)[-10:]
728        for a, e in zip(actual, expected):
729            self.assertAlmostEqual(a,e,places=14)
730
731    def test_strong_reference_implementation(self):
732        # Like test_referenceImplementation, but checks for exact bit-level
733        # equality.  This should pass on any box where C double contains
734        # at least 53 bits of precision (the underlying algorithm suffers
735        # no rounding errors -- all results are exact).
736        from math import ldexp
737
738        expected = [0x0eab3258d2231f,
739                    0x1b89db315277a5,
740                    0x1db622a5518016,
741                    0x0b7f9af0d575bf,
742                    0x029e4c4db82240,
743                    0x04961892f5d673,
744                    0x02b291598e4589,
745                    0x11388382c15694,
746                    0x02dad977c9e1fe,
747                    0x191d96d4d334c6]
748        self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
749        actual = self.randomlist(2000)[-10:]
750        for a, e in zip(actual, expected):
751            self.assertEqual(int(ldexp(a, 53)), e)
752
753    def test_long_seed(self):
754        # This is most interesting to run in debug mode, just to make sure
755        # nothing blows up.  Under the covers, a dynamically resized array
756        # is allocated, consuming space proportional to the number of bits
757        # in the seed.  Unfortunately, that's a quadratic-time algorithm,
758        # so don't make this horribly big.
759        seed = (1 << (10000 * 8)) - 1  # about 10K bytes
760        self.gen.seed(seed)
761
762    def test_53_bits_per_float(self):
763        # This should pass whenever a C double has 53 bit precision.
764        span = 2 ** 53
765        cum = 0
766        for i in range(100):
767            cum |= int(self.gen.random() * span)
768        self.assertEqual(cum, span-1)
769
770    def test_bigrand(self):
771        # The randrange routine should build-up the required number of bits
772        # in stages so that all bit positions are active.
773        span = 2 ** 500
774        cum = 0
775        for i in range(100):
776            r = self.gen.randrange(span)
777            self.assertTrue(0 <= r < span)
778            cum |= r
779        self.assertEqual(cum, span-1)
780
781    def test_bigrand_ranges(self):
782        for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
783            start = self.gen.randrange(2 ** (i-2))
784            stop = self.gen.randrange(2 ** i)
785            if stop <= start:
786                continue
787            self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
788
789    def test_rangelimits(self):
790        for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
791            self.assertEqual(set(range(start,stop)),
792                set([self.gen.randrange(start,stop) for i in range(100)]))
793
794    def test_getrandbits(self):
795        super().test_getrandbits()
796
797        # Verify cross-platform repeatability
798        self.gen.seed(1234567)
799        self.assertEqual(self.gen.getrandbits(100),
800                         97904845777343510404718956115)
801
802    def test_randrange_uses_getrandbits(self):
803        # Verify use of getrandbits by randrange
804        # Use same seed as in the cross-platform repeatability test
805        # in test_getrandbits above.
806        self.gen.seed(1234567)
807        # If randrange uses getrandbits, it should pick getrandbits(100)
808        # when called with a 100-bits stop argument.
809        self.assertEqual(self.gen.randrange(2**99),
810                         97904845777343510404718956115)
811
812    def test_randbelow_logic(self, _log=log, int=int):
813        # check bitcount transition points:  2**i and 2**(i+1)-1
814        # show that: k = int(1.001 + _log(n, 2))
815        # is equal to or one greater than the number of bits in n
816        for i in range(1, 1000):
817            n = 1 << i # check an exact power of two
818            numbits = i+1
819            k = int(1.00001 + _log(n, 2))
820            self.assertEqual(k, numbits)
821            self.assertEqual(n, 2**(k-1))
822
823            n += n - 1      # check 1 below the next power of two
824            k = int(1.00001 + _log(n, 2))
825            self.assertIn(k, [numbits, numbits+1])
826            self.assertTrue(2**k > n > 2**(k-2))
827
828            n -= n >> 15     # check a little farther below the next power of two
829            k = int(1.00001 + _log(n, 2))
830            self.assertEqual(k, numbits)        # note the stronger assertion
831            self.assertTrue(2**k > n > 2**(k-1))   # note the stronger assertion
832
833    def test_randbelow_without_getrandbits(self):
834        # Random._randbelow() can only use random() when the built-in one
835        # has been overridden but no new getrandbits() method was supplied.
836        maxsize = 1<<random.BPF
837        with warnings.catch_warnings():
838            warnings.simplefilter("ignore", UserWarning)
839            # Population range too large (n >= maxsize)
840            self.gen._randbelow_without_getrandbits(
841                maxsize+1, maxsize=maxsize
842            )
843        self.gen._randbelow_without_getrandbits(5640, maxsize=maxsize)
844
845        # This might be going too far to test a single line, but because of our
846        # noble aim of achieving 100% test coverage we need to write a case in
847        # which the following line in Random._randbelow() gets executed:
848        #
849        # rem = maxsize % n
850        # limit = (maxsize - rem) / maxsize
851        # r = random()
852        # while r >= limit:
853        #     r = random() # <== *This line* <==<
854        #
855        # Therefore, to guarantee that the while loop is executed at least
856        # once, we need to mock random() so that it returns a number greater
857        # than 'limit' the first time it gets called.
858
859        n = 42
860        epsilon = 0.01
861        limit = (maxsize - (maxsize % n)) / maxsize
862        with unittest.mock.patch.object(random.Random, 'random') as random_mock:
863            random_mock.side_effect = [limit + epsilon, limit - epsilon]
864            self.gen._randbelow_without_getrandbits(n, maxsize=maxsize)
865            self.assertEqual(random_mock.call_count, 2)
866
867    def test_randrange_bug_1590891(self):
868        start = 1000000000000
869        stop = -100000000000000000000
870        step = -200
871        x = self.gen.randrange(start, stop, step)
872        self.assertTrue(stop < x <= start)
873        self.assertEqual((x+stop)%step, 0)
874
875    def test_choices_algorithms(self):
876        # The various ways of specifying weights should produce the same results
877        choices = self.gen.choices
878        n = 104729
879
880        self.gen.seed(8675309)
881        a = self.gen.choices(range(n), k=10000)
882
883        self.gen.seed(8675309)
884        b = self.gen.choices(range(n), [1]*n, k=10000)
885        self.assertEqual(a, b)
886
887        self.gen.seed(8675309)
888        c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000)
889        self.assertEqual(a, c)
890
891        # American Roulette
892        population = ['Red', 'Black', 'Green']
893        weights = [18, 18, 2]
894        cum_weights = [18, 36, 38]
895        expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2
896
897        self.gen.seed(9035768)
898        a = self.gen.choices(expanded_population, k=10000)
899
900        self.gen.seed(9035768)
901        b = self.gen.choices(population, weights, k=10000)
902        self.assertEqual(a, b)
903
904        self.gen.seed(9035768)
905        c = self.gen.choices(population, cum_weights=cum_weights, k=10000)
906        self.assertEqual(a, c)
907
908    def test_randbytes(self):
909        super().test_randbytes()
910
911        # Mersenne Twister randbytes() is deterministic
912        # and does not depend on the endian and bitness.
913        seed = 8675309
914        expected = b'3\xa8\xf9f\xf4\xa4\xd06\x19\x8f\x9f\x82\x02oe\xf0'
915
916        self.gen.seed(seed)
917        self.assertEqual(self.gen.randbytes(16), expected)
918
919        # randbytes(0) must not consume any entropy
920        self.gen.seed(seed)
921        self.assertEqual(self.gen.randbytes(0), b'')
922        self.assertEqual(self.gen.randbytes(16), expected)
923
924        # Four randbytes(4) calls give the same output than randbytes(16)
925        self.gen.seed(seed)
926        self.assertEqual(b''.join([self.gen.randbytes(4) for _ in range(4)]),
927                         expected)
928
929        # Each randbytes(1), randbytes(2) or randbytes(3) call consumes
930        # 4 bytes of entropy
931        self.gen.seed(seed)
932        expected1 = expected[3::4]
933        self.assertEqual(b''.join(self.gen.randbytes(1) for _ in range(4)),
934                         expected1)
935
936        self.gen.seed(seed)
937        expected2 = b''.join(expected[i + 2: i + 4]
938                             for i in range(0, len(expected), 4))
939        self.assertEqual(b''.join(self.gen.randbytes(2) for _ in range(4)),
940                         expected2)
941
942        self.gen.seed(seed)
943        expected3 = b''.join(expected[i + 1: i + 4]
944                             for i in range(0, len(expected), 4))
945        self.assertEqual(b''.join(self.gen.randbytes(3) for _ in range(4)),
946                         expected3)
947
948    def test_randbytes_getrandbits(self):
949        # There is a simple relation between randbytes() and getrandbits()
950        seed = 2849427419
951        gen2 = random.Random()
952        self.gen.seed(seed)
953        gen2.seed(seed)
954        for n in range(9):
955            self.assertEqual(self.gen.randbytes(n),
956                             gen2.getrandbits(n * 8).to_bytes(n, 'little'))
957
958    def test_sample_counts_equivalence(self):
959        # Test the documented strong equivalence to a sample with repeated elements.
960        # We run this test on random.Random() which makes deterministic selections
961        # for a given seed value.
962        sample = self.gen.sample
963        seed = self.gen.seed
964
965        colors =  ['red', 'green', 'blue', 'orange', 'black', 'amber']
966        counts = [500,      200,     20,       10,       5,       1 ]
967        k = 700
968        seed(8675309)
969        s1 = sample(colors, counts=counts, k=k)
970        seed(8675309)
971        expanded = [color for (color, count) in zip(colors, counts) for i in range(count)]
972        self.assertEqual(len(expanded), sum(counts))
973        s2 = sample(expanded, k=k)
974        self.assertEqual(s1, s2)
975
976        pop = 'abcdefghi'
977        counts = [10, 9, 8, 7, 6, 5, 4, 3, 2]
978        seed(8675309)
979        s1 = ''.join(sample(pop, counts=counts, k=30))
980        expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)])
981        seed(8675309)
982        s2 = ''.join(sample(expanded, k=30))
983        self.assertEqual(s1, s2)
984
985
986def gamma(z, sqrt2pi=(2.0*pi)**0.5):
987    # Reflection to right half of complex plane
988    if z < 0.5:
989        return pi / sin(pi*z) / gamma(1.0-z)
990    # Lanczos approximation with g=7
991    az = z + (7.0 - 0.5)
992    return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([
993        0.9999999999995183,
994        676.5203681218835 / z,
995        -1259.139216722289 / (z+1.0),
996        771.3234287757674 / (z+2.0),
997        -176.6150291498386 / (z+3.0),
998        12.50734324009056 / (z+4.0),
999        -0.1385710331296526 / (z+5.0),
1000        0.9934937113930748e-05 / (z+6.0),
1001        0.1659470187408462e-06 / (z+7.0),
1002    ])
1003
1004class TestDistributions(unittest.TestCase):
1005    def test_zeroinputs(self):
1006        # Verify that distributions can handle a series of zero inputs'
1007        g = random.Random()
1008        x = [g.random() for i in range(50)] + [0.0]*5
1009        g.random = x[:].pop; g.uniform(1,10)
1010        g.random = x[:].pop; g.paretovariate(1.0)
1011        g.random = x[:].pop; g.expovariate(1.0)
1012        g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
1013        g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0)
1014        g.random = x[:].pop; g.normalvariate(0.0, 1.0)
1015        g.random = x[:].pop; g.gauss(0.0, 1.0)
1016        g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
1017        g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0)
1018        g.random = x[:].pop; g.gammavariate(0.01, 1.0)
1019        g.random = x[:].pop; g.gammavariate(1.0, 1.0)
1020        g.random = x[:].pop; g.gammavariate(200.0, 1.0)
1021        g.random = x[:].pop; g.betavariate(3.0, 3.0)
1022        g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0)
1023
1024    def test_avg_std(self):
1025        # Use integration to test distribution average and standard deviation.
1026        # Only works for distributions which do not consume variates in pairs
1027        g = random.Random()
1028        N = 5000
1029        x = [i/float(N) for i in range(1,N)]
1030        for variate, args, mu, sigmasqrd in [
1031                (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
1032                (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
1033                (g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
1034                (g.vonmisesvariate, (1.23, 0), pi, pi**2/3),
1035                (g.paretovariate, (5.0,), 5.0/(5.0-1),
1036                                  5.0/((5.0-1)**2*(5.0-2))),
1037                (g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0),
1038                                  gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]:
1039            g.random = x[:].pop
1040            y = []
1041            for i in range(len(x)):
1042                try:
1043                    y.append(variate(*args))
1044                except IndexError:
1045                    pass
1046            s1 = s2 = 0
1047            for e in y:
1048                s1 += e
1049                s2 += (e - mu) ** 2
1050            N = len(y)
1051            self.assertAlmostEqual(s1/N, mu, places=2,
1052                                   msg='%s%r' % (variate.__name__, args))
1053            self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2,
1054                                   msg='%s%r' % (variate.__name__, args))
1055
1056    def test_constant(self):
1057        g = random.Random()
1058        N = 100
1059        for variate, args, expected in [
1060                (g.uniform, (10.0, 10.0), 10.0),
1061                (g.triangular, (10.0, 10.0), 10.0),
1062                (g.triangular, (10.0, 10.0, 10.0), 10.0),
1063                (g.expovariate, (float('inf'),), 0.0),
1064                (g.vonmisesvariate, (3.0, float('inf')), 3.0),
1065                (g.gauss, (10.0, 0.0), 10.0),
1066                (g.lognormvariate, (0.0, 0.0), 1.0),
1067                (g.lognormvariate, (-float('inf'), 0.0), 0.0),
1068                (g.normalvariate, (10.0, 0.0), 10.0),
1069                (g.paretovariate, (float('inf'),), 1.0),
1070                (g.weibullvariate, (10.0, float('inf')), 10.0),
1071                (g.weibullvariate, (0.0, 10.0), 0.0),
1072            ]:
1073            for i in range(N):
1074                self.assertEqual(variate(*args), expected)
1075
1076    def test_von_mises_range(self):
1077        # Issue 17149: von mises variates were not consistently in the
1078        # range [0, 2*PI].
1079        g = random.Random()
1080        N = 100
1081        for mu in 0.0, 0.1, 3.1, 6.2:
1082            for kappa in 0.0, 2.3, 500.0:
1083                for _ in range(N):
1084                    sample = g.vonmisesvariate(mu, kappa)
1085                    self.assertTrue(
1086                        0 <= sample <= random.TWOPI,
1087                        msg=("vonmisesvariate({}, {}) produced a result {} out"
1088                             " of range [0, 2*pi]").format(mu, kappa, sample))
1089
1090    def test_von_mises_large_kappa(self):
1091        # Issue #17141: vonmisesvariate() was hang for large kappas
1092        random.vonmisesvariate(0, 1e15)
1093        random.vonmisesvariate(0, 1e100)
1094
1095    def test_gammavariate_errors(self):
1096        # Both alpha and beta must be > 0.0
1097        self.assertRaises(ValueError, random.gammavariate, -1, 3)
1098        self.assertRaises(ValueError, random.gammavariate, 0, 2)
1099        self.assertRaises(ValueError, random.gammavariate, 2, 0)
1100        self.assertRaises(ValueError, random.gammavariate, 1, -3)
1101
1102    # There are three different possibilities in the current implementation
1103    # of random.gammavariate(), depending on the value of 'alpha'. What we
1104    # are going to do here is to fix the values returned by random() to
1105    # generate test cases that provide 100% line coverage of the method.
1106    @unittest.mock.patch('random.Random.random')
1107    def test_gammavariate_alpha_greater_one(self, random_mock):
1108
1109        # #1: alpha > 1.0.
1110        # We want the first random number to be outside the
1111        # [1e-7, .9999999] range, so that the continue statement executes
1112        # once. The values of u1 and u2 will be 0.5 and 0.3, respectively.
1113        random_mock.side_effect = [1e-8, 0.5, 0.3]
1114        returned_value = random.gammavariate(1.1, 2.3)
1115        self.assertAlmostEqual(returned_value, 2.53)
1116
1117    @unittest.mock.patch('random.Random.random')
1118    def test_gammavariate_alpha_equal_one(self, random_mock):
1119
1120        # #2.a: alpha == 1.
1121        # The execution body of the while loop executes once.
1122        # Then random.random() returns 0.45,
1123        # which causes while to stop looping and the algorithm to terminate.
1124        random_mock.side_effect = [0.45]
1125        returned_value = random.gammavariate(1.0, 3.14)
1126        self.assertAlmostEqual(returned_value, 1.877208182372648)
1127
1128    @unittest.mock.patch('random.Random.random')
1129    def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock):
1130
1131        # #2.b: alpha == 1.
1132        # It must be equivalent of calling expovariate(1.0 / beta).
1133        beta = 3.14
1134        random_mock.side_effect = [1e-8, 1e-8]
1135        gammavariate_returned_value = random.gammavariate(1.0, beta)
1136        expovariate_returned_value = random.expovariate(1.0 / beta)
1137        self.assertAlmostEqual(gammavariate_returned_value, expovariate_returned_value)
1138
1139    @unittest.mock.patch('random.Random.random')
1140    def test_gammavariate_alpha_between_zero_and_one(self, random_mock):
1141
1142        # #3: 0 < alpha < 1.
1143        # This is the most complex region of code to cover,
1144        # as there are multiple if-else statements. Let's take a look at the
1145        # source code, and determine the values that we need accordingly:
1146        #
1147        # while 1:
1148        #     u = random()
1149        #     b = (_e + alpha)/_e
1150        #     p = b*u
1151        #     if p <= 1.0: # <=== (A)
1152        #         x = p ** (1.0/alpha)
1153        #     else: # <=== (B)
1154        #         x = -_log((b-p)/alpha)
1155        #     u1 = random()
1156        #     if p > 1.0: # <=== (C)
1157        #         if u1 <= x ** (alpha - 1.0): # <=== (D)
1158        #             break
1159        #     elif u1 <= _exp(-x): # <=== (E)
1160        #         break
1161        # return x * beta
1162        #
1163        # First, we want (A) to be True. For that we need that:
1164        # b*random() <= 1.0
1165        # r1 = random() <= 1.0 / b
1166        #
1167        # We now get to the second if-else branch, and here, since p <= 1.0,
1168        # (C) is False and we take the elif branch, (E). For it to be True,
1169        # so that the break is executed, we need that:
1170        # r2 = random() <= _exp(-x)
1171        # r2 <= _exp(-(p ** (1.0/alpha)))
1172        # r2 <= _exp(-((b*r1) ** (1.0/alpha)))
1173
1174        _e = random._e
1175        _exp = random._exp
1176        _log = random._log
1177        alpha = 0.35
1178        beta = 1.45
1179        b = (_e + alpha)/_e
1180        epsilon = 0.01
1181
1182        r1 = 0.8859296441566 # 1.0 / b
1183        r2 = 0.3678794411714 # _exp(-((b*r1) ** (1.0/alpha)))
1184
1185        # These four "random" values result in the following trace:
1186        # (A) True, (E) False --> [next iteration of while]
1187        # (A) True, (E) True --> [while loop breaks]
1188        random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
1189        returned_value = random.gammavariate(alpha, beta)
1190        self.assertAlmostEqual(returned_value, 1.4499999999997544)
1191
1192        # Let's now make (A) be False. If this is the case, when we get to the
1193        # second if-else 'p' is greater than 1, so (C) evaluates to True. We
1194        # now encounter a second if statement, (D), which in order to execute
1195        # must satisfy the following condition:
1196        # r2 <= x ** (alpha - 1.0)
1197        # r2 <= (-_log((b-p)/alpha)) ** (alpha - 1.0)
1198        # r2 <= (-_log((b-(b*r1))/alpha)) ** (alpha - 1.0)
1199        r1 = 0.8959296441566 # (1.0 / b) + epsilon -- so that (A) is False
1200        r2 = 0.9445400408898141
1201
1202        # And these four values result in the following trace:
1203        # (B) and (C) True, (D) False --> [next iteration of while]
1204        # (B) and (C) True, (D) True [while loop breaks]
1205        random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
1206        returned_value = random.gammavariate(alpha, beta)
1207        self.assertAlmostEqual(returned_value, 1.5830349561760781)
1208
1209    @unittest.mock.patch('random.Random.gammavariate')
1210    def test_betavariate_return_zero(self, gammavariate_mock):
1211        # betavariate() returns zero when the Gamma distribution
1212        # that it uses internally returns this same value.
1213        gammavariate_mock.return_value = 0.0
1214        self.assertEqual(0.0, random.betavariate(2.71828, 3.14159))
1215
1216
1217class TestRandomSubclassing(unittest.TestCase):
1218    def test_random_subclass_with_kwargs(self):
1219        # SF bug #1486663 -- this used to erroneously raise a TypeError
1220        class Subclass(random.Random):
1221            def __init__(self, newarg=None):
1222                random.Random.__init__(self)
1223        Subclass(newarg=1)
1224
1225    def test_subclasses_overriding_methods(self):
1226        # Subclasses with an overridden random, but only the original
1227        # getrandbits method should not rely on getrandbits in for randrange,
1228        # but should use a getrandbits-independent implementation instead.
1229
1230        # subclass providing its own random **and** getrandbits methods
1231        # like random.SystemRandom does => keep relying on getrandbits for
1232        # randrange
1233        class SubClass1(random.Random):
1234            def random(self):
1235                called.add('SubClass1.random')
1236                return random.Random.random(self)
1237
1238            def getrandbits(self, n):
1239                called.add('SubClass1.getrandbits')
1240                return random.Random.getrandbits(self, n)
1241        called = set()
1242        SubClass1().randrange(42)
1243        self.assertEqual(called, {'SubClass1.getrandbits'})
1244
1245        # subclass providing only random => can only use random for randrange
1246        class SubClass2(random.Random):
1247            def random(self):
1248                called.add('SubClass2.random')
1249                return random.Random.random(self)
1250        called = set()
1251        SubClass2().randrange(42)
1252        self.assertEqual(called, {'SubClass2.random'})
1253
1254        # subclass defining getrandbits to complement its inherited random
1255        # => can now rely on getrandbits for randrange again
1256        class SubClass3(SubClass2):
1257            def getrandbits(self, n):
1258                called.add('SubClass3.getrandbits')
1259                return random.Random.getrandbits(self, n)
1260        called = set()
1261        SubClass3().randrange(42)
1262        self.assertEqual(called, {'SubClass3.getrandbits'})
1263
1264        # subclass providing only random and inherited getrandbits
1265        # => random takes precedence
1266        class SubClass4(SubClass3):
1267            def random(self):
1268                called.add('SubClass4.random')
1269                return random.Random.random(self)
1270        called = set()
1271        SubClass4().randrange(42)
1272        self.assertEqual(called, {'SubClass4.random'})
1273
1274        # Following subclasses don't define random or getrandbits directly,
1275        # but inherit them from classes which are not subclasses of Random
1276        class Mixin1:
1277            def random(self):
1278                called.add('Mixin1.random')
1279                return random.Random.random(self)
1280        class Mixin2:
1281            def getrandbits(self, n):
1282                called.add('Mixin2.getrandbits')
1283                return random.Random.getrandbits(self, n)
1284
1285        class SubClass5(Mixin1, random.Random):
1286            pass
1287        called = set()
1288        SubClass5().randrange(42)
1289        self.assertEqual(called, {'Mixin1.random'})
1290
1291        class SubClass6(Mixin2, random.Random):
1292            pass
1293        called = set()
1294        SubClass6().randrange(42)
1295        self.assertEqual(called, {'Mixin2.getrandbits'})
1296
1297        class SubClass7(Mixin1, Mixin2, random.Random):
1298            pass
1299        called = set()
1300        SubClass7().randrange(42)
1301        self.assertEqual(called, {'Mixin1.random'})
1302
1303        class SubClass8(Mixin2, Mixin1, random.Random):
1304            pass
1305        called = set()
1306        SubClass8().randrange(42)
1307        self.assertEqual(called, {'Mixin2.getrandbits'})
1308
1309
1310class TestModule(unittest.TestCase):
1311    def testMagicConstants(self):
1312        self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141)
1313        self.assertAlmostEqual(random.TWOPI, 6.28318530718)
1314        self.assertAlmostEqual(random.LOG4, 1.38629436111989)
1315        self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627)
1316
1317    def test__all__(self):
1318        # tests validity but not completeness of the __all__ list
1319        self.assertTrue(set(random.__all__) <= set(dir(random)))
1320
1321    @test.support.requires_fork()
1322    def test_after_fork(self):
1323        # Test the global Random instance gets reseeded in child
1324        r, w = os.pipe()
1325        pid = os.fork()
1326        if pid == 0:
1327            # child process
1328            try:
1329                val = random.getrandbits(128)
1330                with open(w, "w") as f:
1331                    f.write(str(val))
1332            finally:
1333                os._exit(0)
1334        else:
1335            # parent process
1336            os.close(w)
1337            val = random.getrandbits(128)
1338            with open(r, "r") as f:
1339                child_val = eval(f.read())
1340            self.assertNotEqual(val, child_val)
1341
1342            support.wait_process(pid, exitcode=0)
1343
1344
1345if __name__ == "__main__":
1346    unittest.main()
1347