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