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