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