1 import unittest 2 import unittest.mock 3 import random 4 import os 5 import time 6 import pickle 7 import warnings 8 from functools import partial 9 from math import log, exp, pi, fsum, sin, factorial 10 from test import support 11 from fractions import Fraction 12 13 14 class 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 occassionally 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 f = open(support.findfile(file),"rb") 272 r = pickle.load(f) 273 f.close() 274 self.assertEqual(int(r.random()*1000), value) 275 276 def test_bug_9025(self): 277 # Had problem with an uneven distribution in int(n*random()) 278 # Verify the fix by checking that distributions fall within expectations. 279 n = 100000 280 randrange = self.gen.randrange 281 k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n)) 282 self.assertTrue(0.30 < k/n < .37, (k/n)) 283 284 try: 285 random.SystemRandom().random() 286 except NotImplementedError: 287 SystemRandom_available = False 288 else: 289 SystemRandom_available = True 290 291 @unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available") 292 class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase): 293 gen = random.SystemRandom() 294 295 def test_autoseed(self): 296 # Doesn't need to do anything except not fail 297 self.gen.seed() 298 299 def test_saverestore(self): 300 self.assertRaises(NotImplementedError, self.gen.getstate) 301 self.assertRaises(NotImplementedError, self.gen.setstate, None) 302 303 def test_seedargs(self): 304 # Doesn't need to do anything except not fail 305 self.gen.seed(100) 306 307 def test_gauss(self): 308 self.gen.gauss_next = None 309 self.gen.seed(100) 310 self.assertEqual(self.gen.gauss_next, None) 311 312 def test_pickling(self): 313 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 314 self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto) 315 316 def test_53_bits_per_float(self): 317 # This should pass whenever a C double has 53 bit precision. 318 span = 2 ** 53 319 cum = 0 320 for i in range(100): 321 cum |= int(self.gen.random() * span) 322 self.assertEqual(cum, span-1) 323 324 def test_bigrand(self): 325 # The randrange routine should build-up the required number of bits 326 # in stages so that all bit positions are active. 327 span = 2 ** 500 328 cum = 0 329 for i in range(100): 330 r = self.gen.randrange(span) 331 self.assertTrue(0 <= r < span) 332 cum |= r 333 self.assertEqual(cum, span-1) 334 335 def test_bigrand_ranges(self): 336 for i in [40,80, 160, 200, 211, 250, 375, 512, 550]: 337 start = self.gen.randrange(2 ** (i-2)) 338 stop = self.gen.randrange(2 ** i) 339 if stop <= start: 340 continue 341 self.assertTrue(start <= self.gen.randrange(start, stop) < stop) 342 343 def test_rangelimits(self): 344 for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]: 345 self.assertEqual(set(range(start,stop)), 346 set([self.gen.randrange(start,stop) for i in range(100)])) 347 348 def test_randrange_nonunit_step(self): 349 rint = self.gen.randrange(0, 10, 2) 350 self.assertIn(rint, (0, 2, 4, 6, 8)) 351 rint = self.gen.randrange(0, 2, 2) 352 self.assertEqual(rint, 0) 353 354 def test_randrange_errors(self): 355 raises = partial(self.assertRaises, ValueError, self.gen.randrange) 356 # Empty range 357 raises(3, 3) 358 raises(-721) 359 raises(0, 100, -12) 360 # Non-integer start/stop 361 raises(3.14159) 362 raises(0, 2.71828) 363 # Zero and non-integer step 364 raises(0, 42, 0) 365 raises(0, 42, 3.14159) 366 367 def test_genrandbits(self): 368 # Verify ranges 369 for k in range(1, 1000): 370 self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) 371 372 # Verify all bits active 373 getbits = self.gen.getrandbits 374 for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: 375 cum = 0 376 for i in range(100): 377 cum |= getbits(span) 378 self.assertEqual(cum, 2**span-1) 379 380 # Verify argument checking 381 self.assertRaises(TypeError, self.gen.getrandbits) 382 self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) 383 self.assertRaises(ValueError, self.gen.getrandbits, 0) 384 self.assertRaises(ValueError, self.gen.getrandbits, -1) 385 self.assertRaises(TypeError, self.gen.getrandbits, 10.1) 386 387 def test_randbelow_logic(self, _log=log, int=int): 388 # check bitcount transition points: 2**i and 2**(i+1)-1 389 # show that: k = int(1.001 + _log(n, 2)) 390 # is equal to or one greater than the number of bits in n 391 for i in range(1, 1000): 392 n = 1 << i # check an exact power of two 393 numbits = i+1 394 k = int(1.00001 + _log(n, 2)) 395 self.assertEqual(k, numbits) 396 self.assertEqual(n, 2**(k-1)) 397 398 n += n - 1 # check 1 below the next power of two 399 k = int(1.00001 + _log(n, 2)) 400 self.assertIn(k, [numbits, numbits+1]) 401 self.assertTrue(2**k > n > 2**(k-2)) 402 403 n -= n >> 15 # check a little farther below the next power of two 404 k = int(1.00001 + _log(n, 2)) 405 self.assertEqual(k, numbits) # note the stronger assertion 406 self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion 407 408 409 class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): 410 gen = random.Random() 411 412 def test_guaranteed_stable(self): 413 # These sequences are guaranteed to stay the same across versions of python 414 self.gen.seed(3456147, version=1) 415 self.assertEqual([self.gen.random().hex() for i in range(4)], 416 ['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1', 417 '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1']) 418 self.gen.seed("the quick brown fox", version=2) 419 self.assertEqual([self.gen.random().hex() for i in range(4)], 420 ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4', 421 '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1']) 422 423 def test_bug_27706(self): 424 # Verify that version 1 seeds are unaffected by hash randomization 425 426 self.gen.seed('nofar', version=1) # hash('nofar') == 5990528763808513177 427 self.assertEqual([self.gen.random().hex() for i in range(4)], 428 ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5', 429 '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6']) 430 431 self.gen.seed('rachel', version=1) # hash('rachel') == -9091735575445484789 432 self.assertEqual([self.gen.random().hex() for i in range(4)], 433 ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3', 434 '0x1.3052b9c072678p-2', '0x1.578f332106574p-3']) 435 436 self.gen.seed('', version=1) # hash('') == 0 437 self.assertEqual([self.gen.random().hex() for i in range(4)], 438 ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1', 439 '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2']) 440 441 def test_bug_31478(self): 442 # There shouldn't be an assertion failure in _random.Random.seed() in 443 # case the argument has a bad __abs__() method. 444 class BadInt(int): 445 def __abs__(self): 446 return None 447 try: 448 self.gen.seed(BadInt()) 449 except TypeError: 450 pass 451 452 def test_bug_31482(self): 453 # Verify that version 1 seeds are unaffected by hash randomization 454 # when the seeds are expressed as bytes rather than strings. 455 # The hash(b) values listed are the Python2.7 hash() values 456 # which were used for seeding. 457 458 self.gen.seed(b'nofar', version=1) # hash('nofar') == 5990528763808513177 459 self.assertEqual([self.gen.random().hex() for i in range(4)], 460 ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5', 461 '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6']) 462 463 self.gen.seed(b'rachel', version=1) # hash('rachel') == -9091735575445484789 464 self.assertEqual([self.gen.random().hex() for i in range(4)], 465 ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3', 466 '0x1.3052b9c072678p-2', '0x1.578f332106574p-3']) 467 468 self.gen.seed(b'', version=1) # hash('') == 0 469 self.assertEqual([self.gen.random().hex() for i in range(4)], 470 ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1', 471 '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2']) 472 473 b = b'\x00\x20\x40\x60\x80\xA0\xC0\xE0\xF0' 474 self.gen.seed(b, version=1) # hash(b) == 5015594239749365497 475 self.assertEqual([self.gen.random().hex() for i in range(4)], 476 ['0x1.52c2fde444d23p-1', '0x1.875174f0daea4p-2', 477 '0x1.9e9b2c50e5cd2p-1', '0x1.fa57768bd321cp-2']) 478 479 def test_setstate_first_arg(self): 480 self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) 481 482 def test_setstate_middle_arg(self): 483 start_state = self.gen.getstate() 484 # Wrong type, s/b tuple 485 self.assertRaises(TypeError, self.gen.setstate, (2, None, None)) 486 # Wrong length, s/b 625 487 self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None)) 488 # Wrong type, s/b tuple of 625 ints 489 self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None)) 490 # Last element s/b an int also 491 self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None)) 492 # Last element s/b between 0 and 624 493 with self.assertRaises((ValueError, OverflowError)): 494 self.gen.setstate((2, (1,)*624+(625,), None)) 495 with self.assertRaises((ValueError, OverflowError)): 496 self.gen.setstate((2, (1,)*624+(-1,), None)) 497 # Failed calls to setstate() should not have changed the state. 498 bits100 = self.gen.getrandbits(100) 499 self.gen.setstate(start_state) 500 self.assertEqual(self.gen.getrandbits(100), bits100) 501 502 # Little trick to make "tuple(x % (2**32) for x in internalstate)" 503 # raise ValueError. I cannot think of a simple way to achieve this, so 504 # I am opting for using a generator as the middle argument of setstate 505 # which attempts to cast a NaN to integer. 506 state_values = self.gen.getstate()[1] 507 state_values = list(state_values) 508 state_values[-1] = float('nan') 509 state = (int(x) for x in state_values) 510 self.assertRaises(TypeError, self.gen.setstate, (2, state, None)) 511 512 def test_referenceImplementation(self): 513 # Compare the python implementation with results from the original 514 # code. Create 2000 53-bit precision random floats. Compare only 515 # the last ten entries to show that the independent implementations 516 # are tracking. Here is the main() function needed to create the 517 # list of expected random numbers: 518 # void main(void){ 519 # int i; 520 # unsigned long init[4]={61731, 24903, 614, 42143}, length=4; 521 # init_by_array(init, length); 522 # for (i=0; i<2000; i++) { 523 # printf("%.15f ", genrand_res53()); 524 # if (i%5==4) printf("\n"); 525 # } 526 # } 527 expected = [0.45839803073713259, 528 0.86057815201978782, 529 0.92848331726782152, 530 0.35932681119782461, 531 0.081823493762449573, 532 0.14332226470169329, 533 0.084297823823520024, 534 0.53814864671831453, 535 0.089215024911993401, 536 0.78486196105372907] 537 538 self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96)) 539 actual = self.randomlist(2000)[-10:] 540 for a, e in zip(actual, expected): 541 self.assertAlmostEqual(a,e,places=14) 542 543 def test_strong_reference_implementation(self): 544 # Like test_referenceImplementation, but checks for exact bit-level 545 # equality. This should pass on any box where C double contains 546 # at least 53 bits of precision (the underlying algorithm suffers 547 # no rounding errors -- all results are exact). 548 from math import ldexp 549 550 expected = [0x0eab3258d2231f, 551 0x1b89db315277a5, 552 0x1db622a5518016, 553 0x0b7f9af0d575bf, 554 0x029e4c4db82240, 555 0x04961892f5d673, 556 0x02b291598e4589, 557 0x11388382c15694, 558 0x02dad977c9e1fe, 559 0x191d96d4d334c6] 560 self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96)) 561 actual = self.randomlist(2000)[-10:] 562 for a, e in zip(actual, expected): 563 self.assertEqual(int(ldexp(a, 53)), e) 564 565 def test_long_seed(self): 566 # This is most interesting to run in debug mode, just to make sure 567 # nothing blows up. Under the covers, a dynamically resized array 568 # is allocated, consuming space proportional to the number of bits 569 # in the seed. Unfortunately, that's a quadratic-time algorithm, 570 # so don't make this horribly big. 571 seed = (1 << (10000 * 8)) - 1 # about 10K bytes 572 self.gen.seed(seed) 573 574 def test_53_bits_per_float(self): 575 # This should pass whenever a C double has 53 bit precision. 576 span = 2 ** 53 577 cum = 0 578 for i in range(100): 579 cum |= int(self.gen.random() * span) 580 self.assertEqual(cum, span-1) 581 582 def test_bigrand(self): 583 # The randrange routine should build-up the required number of bits 584 # in stages so that all bit positions are active. 585 span = 2 ** 500 586 cum = 0 587 for i in range(100): 588 r = self.gen.randrange(span) 589 self.assertTrue(0 <= r < span) 590 cum |= r 591 self.assertEqual(cum, span-1) 592 593 def test_bigrand_ranges(self): 594 for i in [40,80, 160, 200, 211, 250, 375, 512, 550]: 595 start = self.gen.randrange(2 ** (i-2)) 596 stop = self.gen.randrange(2 ** i) 597 if stop <= start: 598 continue 599 self.assertTrue(start <= self.gen.randrange(start, stop) < stop) 600 601 def test_rangelimits(self): 602 for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]: 603 self.assertEqual(set(range(start,stop)), 604 set([self.gen.randrange(start,stop) for i in range(100)])) 605 606 def test_genrandbits(self): 607 # Verify cross-platform repeatability 608 self.gen.seed(1234567) 609 self.assertEqual(self.gen.getrandbits(100), 610 97904845777343510404718956115) 611 # Verify ranges 612 for k in range(1, 1000): 613 self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) 614 615 # Verify all bits active 616 getbits = self.gen.getrandbits 617 for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: 618 cum = 0 619 for i in range(100): 620 cum |= getbits(span) 621 self.assertEqual(cum, 2**span-1) 622 623 # Verify argument checking 624 self.assertRaises(TypeError, self.gen.getrandbits) 625 self.assertRaises(TypeError, self.gen.getrandbits, 'a') 626 self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) 627 self.assertRaises(ValueError, self.gen.getrandbits, 0) 628 self.assertRaises(ValueError, self.gen.getrandbits, -1) 629 630 def test_randbelow_logic(self, _log=log, int=int): 631 # check bitcount transition points: 2**i and 2**(i+1)-1 632 # show that: k = int(1.001 + _log(n, 2)) 633 # is equal to or one greater than the number of bits in n 634 for i in range(1, 1000): 635 n = 1 << i # check an exact power of two 636 numbits = i+1 637 k = int(1.00001 + _log(n, 2)) 638 self.assertEqual(k, numbits) 639 self.assertEqual(n, 2**(k-1)) 640 641 n += n - 1 # check 1 below the next power of two 642 k = int(1.00001 + _log(n, 2)) 643 self.assertIn(k, [numbits, numbits+1]) 644 self.assertTrue(2**k > n > 2**(k-2)) 645 646 n -= n >> 15 # check a little farther below the next power of two 647 k = int(1.00001 + _log(n, 2)) 648 self.assertEqual(k, numbits) # note the stronger assertion 649 self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion 650 651 @unittest.mock.patch('random.Random.random') 652 def test_randbelow_overridden_random(self, random_mock): 653 # Random._randbelow() can only use random() when the built-in one 654 # has been overridden but no new getrandbits() method was supplied. 655 random_mock.side_effect = random.SystemRandom().random 656 maxsize = 1<<random.BPF 657 with warnings.catch_warnings(): 658 warnings.simplefilter("ignore", UserWarning) 659 # Population range too large (n >= maxsize) 660 self.gen._randbelow(maxsize+1, maxsize = maxsize) 661 self.gen._randbelow(5640, maxsize = maxsize) 662 # issue 33203: test that _randbelow raises ValueError on 663 # n == 0 also in its getrandbits-independent branch. 664 with self.assertRaises(ValueError): 665 self.gen._randbelow(0, maxsize=maxsize) 666 # This might be going too far to test a single line, but because of our 667 # noble aim of achieving 100% test coverage we need to write a case in 668 # which the following line in Random._randbelow() gets executed: 669 # 670 # rem = maxsize % n 671 # limit = (maxsize - rem) / maxsize 672 # r = random() 673 # while r >= limit: 674 # r = random() # <== *This line* <==< 675 # 676 # Therefore, to guarantee that the while loop is executed at least 677 # once, we need to mock random() so that it returns a number greater 678 # than 'limit' the first time it gets called. 679 680 n = 42 681 epsilon = 0.01 682 limit = (maxsize - (maxsize % n)) / maxsize 683 random_mock.side_effect = [limit + epsilon, limit - epsilon] 684 self.gen._randbelow(n, maxsize = maxsize) 685 686 def test_randrange_bug_1590891(self): 687 start = 1000000000000 688 stop = -100000000000000000000 689 step = -200 690 x = self.gen.randrange(start, stop, step) 691 self.assertTrue(stop < x <= start) 692 self.assertEqual((x+stop)%step, 0) 693 694 def test_choices_algorithms(self): 695 # The various ways of specifying weights should produce the same results 696 choices = self.gen.choices 697 n = 104729 698 699 self.gen.seed(8675309) 700 a = self.gen.choices(range(n), k=10000) 701 702 self.gen.seed(8675309) 703 b = self.gen.choices(range(n), [1]*n, k=10000) 704 self.assertEqual(a, b) 705 706 self.gen.seed(8675309) 707 c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000) 708 self.assertEqual(a, c) 709 710 # Amerian Roulette 711 population = ['Red', 'Black', 'Green'] 712 weights = [18, 18, 2] 713 cum_weights = [18, 36, 38] 714 expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2 715 716 self.gen.seed(9035768) 717 a = self.gen.choices(expanded_population, k=10000) 718 719 self.gen.seed(9035768) 720 b = self.gen.choices(population, weights, k=10000) 721 self.assertEqual(a, b) 722 723 self.gen.seed(9035768) 724 c = self.gen.choices(population, cum_weights=cum_weights, k=10000) 725 self.assertEqual(a, c) 726 727 def gamma(z, sqrt2pi=(2.0*pi)**0.5): 728 # Reflection to right half of complex plane 729 if z < 0.5: 730 return pi / sin(pi*z) / gamma(1.0-z) 731 # Lanczos approximation with g=7 732 az = z + (7.0 - 0.5) 733 return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([ 734 0.9999999999995183, 735 676.5203681218835 / z, 736 -1259.139216722289 / (z+1.0), 737 771.3234287757674 / (z+2.0), 738 -176.6150291498386 / (z+3.0), 739 12.50734324009056 / (z+4.0), 740 -0.1385710331296526 / (z+5.0), 741 0.9934937113930748e-05 / (z+6.0), 742 0.1659470187408462e-06 / (z+7.0), 743 ]) 744 745 class TestDistributions(unittest.TestCase): 746 def test_zeroinputs(self): 747 # Verify that distributions can handle a series of zero inputs' 748 g = random.Random() 749 x = [g.random() for i in range(50)] + [0.0]*5 750 g.random = x[:].pop; g.uniform(1,10) 751 g.random = x[:].pop; g.paretovariate(1.0) 752 g.random = x[:].pop; g.expovariate(1.0) 753 g.random = x[:].pop; g.weibullvariate(1.0, 1.0) 754 g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0) 755 g.random = x[:].pop; g.normalvariate(0.0, 1.0) 756 g.random = x[:].pop; g.gauss(0.0, 1.0) 757 g.random = x[:].pop; g.lognormvariate(0.0, 1.0) 758 g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0) 759 g.random = x[:].pop; g.gammavariate(0.01, 1.0) 760 g.random = x[:].pop; g.gammavariate(1.0, 1.0) 761 g.random = x[:].pop; g.gammavariate(200.0, 1.0) 762 g.random = x[:].pop; g.betavariate(3.0, 3.0) 763 g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0) 764 765 def test_avg_std(self): 766 # Use integration to test distribution average and standard deviation. 767 # Only works for distributions which do not consume variates in pairs 768 g = random.Random() 769 N = 5000 770 x = [i/float(N) for i in range(1,N)] 771 for variate, args, mu, sigmasqrd in [ 772 (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12), 773 (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0), 774 (g.expovariate, (1.5,), 1/1.5, 1/1.5**2), 775 (g.vonmisesvariate, (1.23, 0), pi, pi**2/3), 776 (g.paretovariate, (5.0,), 5.0/(5.0-1), 777 5.0/((5.0-1)**2*(5.0-2))), 778 (g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0), 779 gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]: 780 g.random = x[:].pop 781 y = [] 782 for i in range(len(x)): 783 try: 784 y.append(variate(*args)) 785 except IndexError: 786 pass 787 s1 = s2 = 0 788 for e in y: 789 s1 += e 790 s2 += (e - mu) ** 2 791 N = len(y) 792 self.assertAlmostEqual(s1/N, mu, places=2, 793 msg='%s%r' % (variate.__name__, args)) 794 self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2, 795 msg='%s%r' % (variate.__name__, args)) 796 797 def test_constant(self): 798 g = random.Random() 799 N = 100 800 for variate, args, expected in [ 801 (g.uniform, (10.0, 10.0), 10.0), 802 (g.triangular, (10.0, 10.0), 10.0), 803 (g.triangular, (10.0, 10.0, 10.0), 10.0), 804 (g.expovariate, (float('inf'),), 0.0), 805 (g.vonmisesvariate, (3.0, float('inf')), 3.0), 806 (g.gauss, (10.0, 0.0), 10.0), 807 (g.lognormvariate, (0.0, 0.0), 1.0), 808 (g.lognormvariate, (-float('inf'), 0.0), 0.0), 809 (g.normalvariate, (10.0, 0.0), 10.0), 810 (g.paretovariate, (float('inf'),), 1.0), 811 (g.weibullvariate, (10.0, float('inf')), 10.0), 812 (g.weibullvariate, (0.0, 10.0), 0.0), 813 ]: 814 for i in range(N): 815 self.assertEqual(variate(*args), expected) 816 817 def test_von_mises_range(self): 818 # Issue 17149: von mises variates were not consistently in the 819 # range [0, 2*PI]. 820 g = random.Random() 821 N = 100 822 for mu in 0.0, 0.1, 3.1, 6.2: 823 for kappa in 0.0, 2.3, 500.0: 824 for _ in range(N): 825 sample = g.vonmisesvariate(mu, kappa) 826 self.assertTrue( 827 0 <= sample <= random.TWOPI, 828 msg=("vonmisesvariate({}, {}) produced a result {} out" 829 " of range [0, 2*pi]").format(mu, kappa, sample)) 830 831 def test_von_mises_large_kappa(self): 832 # Issue #17141: vonmisesvariate() was hang for large kappas 833 random.vonmisesvariate(0, 1e15) 834 random.vonmisesvariate(0, 1e100) 835 836 def test_gammavariate_errors(self): 837 # Both alpha and beta must be > 0.0 838 self.assertRaises(ValueError, random.gammavariate, -1, 3) 839 self.assertRaises(ValueError, random.gammavariate, 0, 2) 840 self.assertRaises(ValueError, random.gammavariate, 2, 0) 841 self.assertRaises(ValueError, random.gammavariate, 1, -3) 842 843 @unittest.mock.patch('random.Random.random') 844 def test_gammavariate_full_code_coverage(self, random_mock): 845 # There are three different possibilities in the current implementation 846 # of random.gammavariate(), depending on the value of 'alpha'. What we 847 # are going to do here is to fix the values returned by random() to 848 # generate test cases that provide 100% line coverage of the method. 849 850 # #1: alpha > 1.0: we want the first random number to be outside the 851 # [1e-7, .9999999] range, so that the continue statement executes 852 # once. The values of u1 and u2 will be 0.5 and 0.3, respectively. 853 random_mock.side_effect = [1e-8, 0.5, 0.3] 854 returned_value = random.gammavariate(1.1, 2.3) 855 self.assertAlmostEqual(returned_value, 2.53) 856 857 # #2: alpha == 1: first random number less than 1e-7 to that the body 858 # of the while loop executes once. Then random.random() returns 0.45, 859 # which causes while to stop looping and the algorithm to terminate. 860 random_mock.side_effect = [1e-8, 0.45] 861 returned_value = random.gammavariate(1.0, 3.14) 862 self.assertAlmostEqual(returned_value, 2.507314166123803) 863 864 # #3: 0 < alpha < 1. This is the most complex region of code to cover, 865 # as there are multiple if-else statements. Let's take a look at the 866 # source code, and determine the values that we need accordingly: 867 # 868 # while 1: 869 # u = random() 870 # b = (_e + alpha)/_e 871 # p = b*u 872 # if p <= 1.0: # <=== (A) 873 # x = p ** (1.0/alpha) 874 # else: # <=== (B) 875 # x = -_log((b-p)/alpha) 876 # u1 = random() 877 # if p > 1.0: # <=== (C) 878 # if u1 <= x ** (alpha - 1.0): # <=== (D) 879 # break 880 # elif u1 <= _exp(-x): # <=== (E) 881 # break 882 # return x * beta 883 # 884 # First, we want (A) to be True. For that we need that: 885 # b*random() <= 1.0 886 # r1 = random() <= 1.0 / b 887 # 888 # We now get to the second if-else branch, and here, since p <= 1.0, 889 # (C) is False and we take the elif branch, (E). For it to be True, 890 # so that the break is executed, we need that: 891 # r2 = random() <= _exp(-x) 892 # r2 <= _exp(-(p ** (1.0/alpha))) 893 # r2 <= _exp(-((b*r1) ** (1.0/alpha))) 894 895 _e = random._e 896 _exp = random._exp 897 _log = random._log 898 alpha = 0.35 899 beta = 1.45 900 b = (_e + alpha)/_e 901 epsilon = 0.01 902 903 r1 = 0.8859296441566 # 1.0 / b 904 r2 = 0.3678794411714 # _exp(-((b*r1) ** (1.0/alpha))) 905 906 # These four "random" values result in the following trace: 907 # (A) True, (E) False --> [next iteration of while] 908 # (A) True, (E) True --> [while loop breaks] 909 random_mock.side_effect = [r1, r2 + epsilon, r1, r2] 910 returned_value = random.gammavariate(alpha, beta) 911 self.assertAlmostEqual(returned_value, 1.4499999999997544) 912 913 # Let's now make (A) be False. If this is the case, when we get to the 914 # second if-else 'p' is greater than 1, so (C) evaluates to True. We 915 # now encounter a second if statement, (D), which in order to execute 916 # must satisfy the following condition: 917 # r2 <= x ** (alpha - 1.0) 918 # r2 <= (-_log((b-p)/alpha)) ** (alpha - 1.0) 919 # r2 <= (-_log((b-(b*r1))/alpha)) ** (alpha - 1.0) 920 r1 = 0.8959296441566 # (1.0 / b) + epsilon -- so that (A) is False 921 r2 = 0.9445400408898141 922 923 # And these four values result in the following trace: 924 # (B) and (C) True, (D) False --> [next iteration of while] 925 # (B) and (C) True, (D) True [while loop breaks] 926 random_mock.side_effect = [r1, r2 + epsilon, r1, r2] 927 returned_value = random.gammavariate(alpha, beta) 928 self.assertAlmostEqual(returned_value, 1.5830349561760781) 929 930 @unittest.mock.patch('random.Random.gammavariate') 931 def test_betavariate_return_zero(self, gammavariate_mock): 932 # betavariate() returns zero when the Gamma distribution 933 # that it uses internally returns this same value. 934 gammavariate_mock.return_value = 0.0 935 self.assertEqual(0.0, random.betavariate(2.71828, 3.14159)) 936 937 class TestModule(unittest.TestCase): 938 def testMagicConstants(self): 939 self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141) 940 self.assertAlmostEqual(random.TWOPI, 6.28318530718) 941 self.assertAlmostEqual(random.LOG4, 1.38629436111989) 942 self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627) 943 944 def test__all__(self): 945 # tests validity but not completeness of the __all__ list 946 self.assertTrue(set(random.__all__) <= set(dir(random))) 947 948 def test_random_subclass_with_kwargs(self): 949 # SF bug #1486663 -- this used to erroneously raise a TypeError 950 class Subclass(random.Random): 951 def __init__(self, newarg=None): 952 random.Random.__init__(self) 953 Subclass(newarg=1) 954 955 @unittest.skipUnless(hasattr(os, "fork"), "fork() required") 956 def test_after_fork(self): 957 # Test the global Random instance gets reseeded in child 958 r, w = os.pipe() 959 pid = os.fork() 960 if pid == 0: 961 # child process 962 try: 963 val = random.getrandbits(128) 964 with open(w, "w") as f: 965 f.write(str(val)) 966 finally: 967 os._exit(0) 968 else: 969 # parent process 970 os.close(w) 971 val = random.getrandbits(128) 972 with open(r, "r") as f: 973 child_val = eval(f.read()) 974 self.assertNotEqual(val, child_val) 975 976 pid, status = os.waitpid(pid, 0) 977 self.assertEqual(status, 0) 978 979 980 if __name__ == "__main__": 981 unittest.main() 982