1# Python test set -- built-in functions 2 3import unittest 4import sys 5import pickle 6import itertools 7 8# pure Python implementations (3 args only), for comparison 9def pyrange(start, stop, step): 10 if (start - stop) // step < 0: 11 # replace stop with next element in the sequence of integers 12 # that are congruent to start modulo step. 13 stop += (start - stop) % step 14 while start != stop: 15 yield start 16 start += step 17 18def pyrange_reversed(start, stop, step): 19 stop += (start - stop) % step 20 return pyrange(stop - step, start - step, -step) 21 22 23class RangeTest(unittest.TestCase): 24 def assert_iterators_equal(self, xs, ys, test_id, limit=None): 25 # check that an iterator xs matches the expected results ys, 26 # up to a given limit. 27 if limit is not None: 28 xs = itertools.islice(xs, limit) 29 ys = itertools.islice(ys, limit) 30 sentinel = object() 31 pairs = itertools.zip_longest(xs, ys, fillvalue=sentinel) 32 for i, (x, y) in enumerate(pairs): 33 if x == y: 34 continue 35 elif x == sentinel: 36 self.fail('{}: iterator ended unexpectedly ' 37 'at position {}; expected {}'.format(test_id, i, y)) 38 elif y == sentinel: 39 self.fail('{}: unexpected excess element {} at ' 40 'position {}'.format(test_id, x, i)) 41 else: 42 self.fail('{}: wrong element at position {}; ' 43 'expected {}, got {}'.format(test_id, i, y, x)) 44 45 def test_range(self): 46 self.assertEqual(list(range(3)), [0, 1, 2]) 47 self.assertEqual(list(range(1, 5)), [1, 2, 3, 4]) 48 self.assertEqual(list(range(0)), []) 49 self.assertEqual(list(range(-3)), []) 50 self.assertEqual(list(range(1, 10, 3)), [1, 4, 7]) 51 self.assertEqual(list(range(5, -5, -3)), [5, 2, -1, -4]) 52 53 a = 10 54 b = 100 55 c = 50 56 57 self.assertEqual(list(range(a, a+2)), [a, a+1]) 58 self.assertEqual(list(range(a+2, a, -1)), [a+2, a+1]) 59 self.assertEqual(list(range(a+4, a, -2)), [a+4, a+2]) 60 61 seq = list(range(a, b, c)) 62 self.assertIn(a, seq) 63 self.assertNotIn(b, seq) 64 self.assertEqual(len(seq), 2) 65 66 seq = list(range(b, a, -c)) 67 self.assertIn(b, seq) 68 self.assertNotIn(a, seq) 69 self.assertEqual(len(seq), 2) 70 71 seq = list(range(-a, -b, -c)) 72 self.assertIn(-a, seq) 73 self.assertNotIn(-b, seq) 74 self.assertEqual(len(seq), 2) 75 76 self.assertRaises(TypeError, range) 77 self.assertRaises(TypeError, range, 1, 2, 3, 4) 78 self.assertRaises(ValueError, range, 1, 2, 0) 79 80 self.assertRaises(TypeError, range, 0.0, 2, 1) 81 self.assertRaises(TypeError, range, 1, 2.0, 1) 82 self.assertRaises(TypeError, range, 1, 2, 1.0) 83 self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) 84 85 self.assertRaises(TypeError, range, 0, "spam") 86 self.assertRaises(TypeError, range, 0, 42, "spam") 87 88 self.assertEqual(len(range(0, sys.maxsize, sys.maxsize-1)), 2) 89 90 r = range(-sys.maxsize, sys.maxsize, 2) 91 self.assertEqual(len(r), sys.maxsize) 92 93 def test_large_operands(self): 94 x = range(10**20, 10**20+10, 3) 95 self.assertEqual(len(x), 4) 96 self.assertEqual(len(list(x)), 4) 97 98 x = range(10**20+10, 10**20, 3) 99 self.assertEqual(len(x), 0) 100 self.assertEqual(len(list(x)), 0) 101 self.assertFalse(x) 102 103 x = range(10**20, 10**20+10, -3) 104 self.assertEqual(len(x), 0) 105 self.assertEqual(len(list(x)), 0) 106 self.assertFalse(x) 107 108 x = range(10**20+10, 10**20, -3) 109 self.assertEqual(len(x), 4) 110 self.assertEqual(len(list(x)), 4) 111 self.assertTrue(x) 112 113 # Now test range() with longs 114 for x in [range(-2**100), 115 range(0, -2**100), 116 range(0, 2**100, -1)]: 117 self.assertEqual(list(x), []) 118 self.assertFalse(x) 119 120 a = int(10 * sys.maxsize) 121 b = int(100 * sys.maxsize) 122 c = int(50 * sys.maxsize) 123 124 self.assertEqual(list(range(a, a+2)), [a, a+1]) 125 self.assertEqual(list(range(a+2, a, -1)), [a+2, a+1]) 126 self.assertEqual(list(range(a+4, a, -2)), [a+4, a+2]) 127 128 seq = list(range(a, b, c)) 129 self.assertIn(a, seq) 130 self.assertNotIn(b, seq) 131 self.assertEqual(len(seq), 2) 132 self.assertEqual(seq[0], a) 133 self.assertEqual(seq[-1], a+c) 134 135 seq = list(range(b, a, -c)) 136 self.assertIn(b, seq) 137 self.assertNotIn(a, seq) 138 self.assertEqual(len(seq), 2) 139 self.assertEqual(seq[0], b) 140 self.assertEqual(seq[-1], b-c) 141 142 seq = list(range(-a, -b, -c)) 143 self.assertIn(-a, seq) 144 self.assertNotIn(-b, seq) 145 self.assertEqual(len(seq), 2) 146 self.assertEqual(seq[0], -a) 147 self.assertEqual(seq[-1], -a-c) 148 149 def test_large_range(self): 150 # Check long ranges (len > sys.maxsize) 151 # len() is expected to fail due to limitations of the __len__ protocol 152 def _range_len(x): 153 try: 154 length = len(x) 155 except OverflowError: 156 step = x[1] - x[0] 157 length = 1 + ((x[-1] - x[0]) // step) 158 return length 159 160 a = -sys.maxsize 161 b = sys.maxsize 162 expected_len = b - a 163 x = range(a, b) 164 self.assertIn(a, x) 165 self.assertNotIn(b, x) 166 self.assertRaises(OverflowError, len, x) 167 self.assertTrue(x) 168 self.assertEqual(_range_len(x), expected_len) 169 self.assertEqual(x[0], a) 170 idx = sys.maxsize+1 171 self.assertEqual(x[idx], a+idx) 172 self.assertEqual(x[idx:idx+1][0], a+idx) 173 with self.assertRaises(IndexError): 174 x[-expected_len-1] 175 with self.assertRaises(IndexError): 176 x[expected_len] 177 178 a = 0 179 b = 2 * sys.maxsize 180 expected_len = b - a 181 x = range(a, b) 182 self.assertIn(a, x) 183 self.assertNotIn(b, x) 184 self.assertRaises(OverflowError, len, x) 185 self.assertTrue(x) 186 self.assertEqual(_range_len(x), expected_len) 187 self.assertEqual(x[0], a) 188 idx = sys.maxsize+1 189 self.assertEqual(x[idx], a+idx) 190 self.assertEqual(x[idx:idx+1][0], a+idx) 191 with self.assertRaises(IndexError): 192 x[-expected_len-1] 193 with self.assertRaises(IndexError): 194 x[expected_len] 195 196 a = 0 197 b = sys.maxsize**10 198 c = 2*sys.maxsize 199 expected_len = 1 + (b - a) // c 200 x = range(a, b, c) 201 self.assertIn(a, x) 202 self.assertNotIn(b, x) 203 self.assertRaises(OverflowError, len, x) 204 self.assertTrue(x) 205 self.assertEqual(_range_len(x), expected_len) 206 self.assertEqual(x[0], a) 207 idx = sys.maxsize+1 208 self.assertEqual(x[idx], a+(idx*c)) 209 self.assertEqual(x[idx:idx+1][0], a+(idx*c)) 210 with self.assertRaises(IndexError): 211 x[-expected_len-1] 212 with self.assertRaises(IndexError): 213 x[expected_len] 214 215 a = sys.maxsize**10 216 b = 0 217 c = -2*sys.maxsize 218 expected_len = 1 + (b - a) // c 219 x = range(a, b, c) 220 self.assertIn(a, x) 221 self.assertNotIn(b, x) 222 self.assertRaises(OverflowError, len, x) 223 self.assertTrue(x) 224 self.assertEqual(_range_len(x), expected_len) 225 self.assertEqual(x[0], a) 226 idx = sys.maxsize+1 227 self.assertEqual(x[idx], a+(idx*c)) 228 self.assertEqual(x[idx:idx+1][0], a+(idx*c)) 229 with self.assertRaises(IndexError): 230 x[-expected_len-1] 231 with self.assertRaises(IndexError): 232 x[expected_len] 233 234 def test_invalid_invocation(self): 235 self.assertRaises(TypeError, range) 236 self.assertRaises(TypeError, range, 1, 2, 3, 4) 237 self.assertRaises(ValueError, range, 1, 2, 0) 238 a = int(10 * sys.maxsize) 239 self.assertRaises(ValueError, range, a, a + 1, int(0)) 240 self.assertRaises(TypeError, range, 1., 1., 1.) 241 self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) 242 self.assertRaises(TypeError, range, 0, "spam") 243 self.assertRaises(TypeError, range, 0, 42, "spam") 244 # Exercise various combinations of bad arguments, to check 245 # refcounting logic 246 self.assertRaises(TypeError, range, 0.0) 247 self.assertRaises(TypeError, range, 0, 0.0) 248 self.assertRaises(TypeError, range, 0.0, 0) 249 self.assertRaises(TypeError, range, 0.0, 0.0) 250 self.assertRaises(TypeError, range, 0, 0, 1.0) 251 self.assertRaises(TypeError, range, 0, 0.0, 1) 252 self.assertRaises(TypeError, range, 0, 0.0, 1.0) 253 self.assertRaises(TypeError, range, 0.0, 0, 1) 254 self.assertRaises(TypeError, range, 0.0, 0, 1.0) 255 self.assertRaises(TypeError, range, 0.0, 0.0, 1) 256 self.assertRaises(TypeError, range, 0.0, 0.0, 1.0) 257 258 def test_index(self): 259 u = range(2) 260 self.assertEqual(u.index(0), 0) 261 self.assertEqual(u.index(1), 1) 262 self.assertRaises(ValueError, u.index, 2) 263 264 u = range(-2, 3) 265 self.assertEqual(u.count(0), 1) 266 self.assertEqual(u.index(0), 2) 267 self.assertRaises(TypeError, u.index) 268 269 class BadExc(Exception): 270 pass 271 272 class BadCmp: 273 def __eq__(self, other): 274 if other == 2: 275 raise BadExc() 276 return False 277 278 a = range(4) 279 self.assertRaises(BadExc, a.index, BadCmp()) 280 281 a = range(-2, 3) 282 self.assertEqual(a.index(0), 2) 283 self.assertEqual(range(1, 10, 3).index(4), 1) 284 self.assertEqual(range(1, -10, -3).index(-5), 2) 285 286 self.assertEqual(range(10**20).index(1), 1) 287 self.assertEqual(range(10**20).index(10**20 - 1), 10**20 - 1) 288 289 self.assertRaises(ValueError, range(1, 2**100, 2).index, 2**87) 290 self.assertEqual(range(1, 2**100, 2).index(2**87+1), 2**86) 291 292 class AlwaysEqual(object): 293 def __eq__(self, other): 294 return True 295 always_equal = AlwaysEqual() 296 self.assertEqual(range(10).index(always_equal), 0) 297 298 def test_user_index_method(self): 299 bignum = 2*sys.maxsize 300 smallnum = 42 301 302 # User-defined class with an __index__ method 303 class I: 304 def __init__(self, n): 305 self.n = int(n) 306 def __index__(self): 307 return self.n 308 self.assertEqual(list(range(I(bignum), I(bignum + 1))), [bignum]) 309 self.assertEqual(list(range(I(smallnum), I(smallnum + 1))), [smallnum]) 310 311 # User-defined class with a failing __index__ method 312 class IX: 313 def __index__(self): 314 raise RuntimeError 315 self.assertRaises(RuntimeError, range, IX()) 316 317 # User-defined class with an invalid __index__ method 318 class IN: 319 def __index__(self): 320 return "not a number" 321 322 self.assertRaises(TypeError, range, IN()) 323 324 # Test use of user-defined classes in slice indices. 325 self.assertEqual(range(10)[:I(5)], range(5)) 326 327 with self.assertRaises(RuntimeError): 328 range(0, 10)[:IX()] 329 330 with self.assertRaises(TypeError): 331 range(0, 10)[:IN()] 332 333 def test_count(self): 334 self.assertEqual(range(3).count(-1), 0) 335 self.assertEqual(range(3).count(0), 1) 336 self.assertEqual(range(3).count(1), 1) 337 self.assertEqual(range(3).count(2), 1) 338 self.assertEqual(range(3).count(3), 0) 339 self.assertIs(type(range(3).count(-1)), int) 340 self.assertIs(type(range(3).count(1)), int) 341 self.assertEqual(range(10**20).count(1), 1) 342 self.assertEqual(range(10**20).count(10**20), 0) 343 self.assertEqual(range(3).index(1), 1) 344 self.assertEqual(range(1, 2**100, 2).count(2**87), 0) 345 self.assertEqual(range(1, 2**100, 2).count(2**87+1), 1) 346 347 class AlwaysEqual(object): 348 def __eq__(self, other): 349 return True 350 always_equal = AlwaysEqual() 351 self.assertEqual(range(10).count(always_equal), 10) 352 353 self.assertEqual(len(range(sys.maxsize, sys.maxsize+10)), 10) 354 355 def test_repr(self): 356 self.assertEqual(repr(range(1)), 'range(0, 1)') 357 self.assertEqual(repr(range(1, 2)), 'range(1, 2)') 358 self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)') 359 360 def test_pickling(self): 361 testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1), 362 (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)] 363 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 364 for t in testcases: 365 with self.subTest(proto=proto, test=t): 366 r = range(*t) 367 self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))), 368 list(r)) 369 370 def test_iterator_pickling(self): 371 testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1), 372 (13, 21, 3), (-2, 2, 2), (2**65, 2**65+2)] 373 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 374 for t in testcases: 375 it = itorg = iter(range(*t)) 376 data = list(range(*t)) 377 378 d = pickle.dumps(it, proto) 379 it = pickle.loads(d) 380 self.assertEqual(type(itorg), type(it)) 381 self.assertEqual(list(it), data) 382 383 it = pickle.loads(d) 384 try: 385 next(it) 386 except StopIteration: 387 continue 388 d = pickle.dumps(it, proto) 389 it = pickle.loads(d) 390 self.assertEqual(list(it), data[1:]) 391 392 def test_exhausted_iterator_pickling(self): 393 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 394 r = range(2**65, 2**65+2) 395 i = iter(r) 396 while True: 397 r = next(i) 398 if r == 2**65+1: 399 break 400 d = pickle.dumps(i, proto) 401 i2 = pickle.loads(d) 402 self.assertEqual(list(i), []) 403 self.assertEqual(list(i2), []) 404 405 def test_large_exhausted_iterator_pickling(self): 406 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 407 r = range(20) 408 i = iter(r) 409 while True: 410 r = next(i) 411 if r == 19: 412 break 413 d = pickle.dumps(i, proto) 414 i2 = pickle.loads(d) 415 self.assertEqual(list(i), []) 416 self.assertEqual(list(i2), []) 417 418 def test_odd_bug(self): 419 # This used to raise a "SystemError: NULL result without error" 420 # because the range validation step was eating the exception 421 # before NULL was returned. 422 with self.assertRaises(TypeError): 423 range([], 1, -1) 424 425 def test_types(self): 426 # Non-integer objects *equal* to any of the range's items are supposed 427 # to be contained in the range. 428 self.assertIn(1.0, range(3)) 429 self.assertIn(True, range(3)) 430 self.assertIn(1+0j, range(3)) 431 432 class C1: 433 def __eq__(self, other): return True 434 self.assertIn(C1(), range(3)) 435 436 # Objects are never coerced into other types for comparison. 437 class C2: 438 def __int__(self): return 1 439 def __index__(self): return 1 440 self.assertNotIn(C2(), range(3)) 441 # ..except if explicitly told so. 442 self.assertIn(int(C2()), range(3)) 443 444 # Check that the range.__contains__ optimization is only 445 # used for ints, not for instances of subclasses of int. 446 class C3(int): 447 def __eq__(self, other): return True 448 self.assertIn(C3(11), range(10)) 449 self.assertIn(C3(11), list(range(10))) 450 451 def test_strided_limits(self): 452 r = range(0, 101, 2) 453 self.assertIn(0, r) 454 self.assertNotIn(1, r) 455 self.assertIn(2, r) 456 self.assertNotIn(99, r) 457 self.assertIn(100, r) 458 self.assertNotIn(101, r) 459 460 r = range(0, -20, -1) 461 self.assertIn(0, r) 462 self.assertIn(-1, r) 463 self.assertIn(-19, r) 464 self.assertNotIn(-20, r) 465 466 r = range(0, -20, -2) 467 self.assertIn(-18, r) 468 self.assertNotIn(-19, r) 469 self.assertNotIn(-20, r) 470 471 def test_empty(self): 472 r = range(0) 473 self.assertNotIn(0, r) 474 self.assertNotIn(1, r) 475 476 r = range(0, -10) 477 self.assertNotIn(0, r) 478 self.assertNotIn(-1, r) 479 self.assertNotIn(1, r) 480 481 def test_range_iterators(self): 482 # exercise 'fast' iterators, that use a rangeiterobject internally. 483 # see issue 7298 484 limits = [base + jiggle 485 for M in (2**32, 2**64) 486 for base in (-M, -M//2, 0, M//2, M) 487 for jiggle in (-2, -1, 0, 1, 2)] 488 test_ranges = [(start, end, step) 489 for start in limits 490 for end in limits 491 for step in (-2**63, -2**31, -2, -1, 1, 2)] 492 493 for start, end, step in test_ranges: 494 iter1 = range(start, end, step) 495 iter2 = pyrange(start, end, step) 496 test_id = "range({}, {}, {})".format(start, end, step) 497 # check first 100 entries 498 self.assert_iterators_equal(iter1, iter2, test_id, limit=100) 499 500 iter1 = reversed(range(start, end, step)) 501 iter2 = pyrange_reversed(start, end, step) 502 test_id = "reversed(range({}, {}, {}))".format(start, end, step) 503 self.assert_iterators_equal(iter1, iter2, test_id, limit=100) 504 505 def test_range_iterators_invocation(self): 506 # verify range iterators instances cannot be created by 507 # calling their type 508 rangeiter_type = type(iter(range(0))) 509 self.assertRaises(TypeError, rangeiter_type, 1, 3, 1) 510 long_rangeiter_type = type(iter(range(1 << 1000))) 511 self.assertRaises(TypeError, long_rangeiter_type, 1, 3, 1) 512 513 def test_slice(self): 514 def check(start, stop, step=None): 515 i = slice(start, stop, step) 516 self.assertEqual(list(r[i]), list(r)[i]) 517 self.assertEqual(len(r[i]), len(list(r)[i])) 518 for r in [range(10), 519 range(0), 520 range(1, 9, 3), 521 range(8, 0, -3), 522 range(sys.maxsize+1, sys.maxsize+10), 523 ]: 524 check(0, 2) 525 check(0, 20) 526 check(1, 2) 527 check(20, 30) 528 check(-30, -20) 529 check(-1, 100, 2) 530 check(0, -1) 531 check(-1, -3, -1) 532 533 def test_contains(self): 534 r = range(10) 535 self.assertIn(0, r) 536 self.assertIn(1, r) 537 self.assertIn(5.0, r) 538 self.assertNotIn(5.1, r) 539 self.assertNotIn(-1, r) 540 self.assertNotIn(10, r) 541 self.assertNotIn("", r) 542 r = range(9, -1, -1) 543 self.assertIn(0, r) 544 self.assertIn(1, r) 545 self.assertIn(5.0, r) 546 self.assertNotIn(5.1, r) 547 self.assertNotIn(-1, r) 548 self.assertNotIn(10, r) 549 self.assertNotIn("", r) 550 r = range(0, 10, 2) 551 self.assertIn(0, r) 552 self.assertNotIn(1, r) 553 self.assertNotIn(5.0, r) 554 self.assertNotIn(5.1, r) 555 self.assertNotIn(-1, r) 556 self.assertNotIn(10, r) 557 self.assertNotIn("", r) 558 r = range(9, -1, -2) 559 self.assertNotIn(0, r) 560 self.assertIn(1, r) 561 self.assertIn(5.0, r) 562 self.assertNotIn(5.1, r) 563 self.assertNotIn(-1, r) 564 self.assertNotIn(10, r) 565 self.assertNotIn("", r) 566 567 def test_reverse_iteration(self): 568 for r in [range(10), 569 range(0), 570 range(1, 9, 3), 571 range(8, 0, -3), 572 range(sys.maxsize+1, sys.maxsize+10), 573 ]: 574 self.assertEqual(list(reversed(r)), list(r)[::-1]) 575 576 def test_issue11845(self): 577 r = range(*slice(1, 18, 2).indices(20)) 578 values = {None, 0, 1, -1, 2, -2, 5, -5, 19, -19, 579 20, -20, 21, -21, 30, -30, 99, -99} 580 for i in values: 581 for j in values: 582 for k in values - {0}: 583 r[i:j:k] 584 585 def test_comparison(self): 586 test_ranges = [range(0), range(0, -1), range(1, 1, 3), 587 range(1), range(5, 6), range(5, 6, 2), 588 range(5, 7, 2), range(2), range(0, 4, 2), 589 range(0, 5, 2), range(0, 6, 2)] 590 test_tuples = list(map(tuple, test_ranges)) 591 592 # Check that equality of ranges matches equality of the corresponding 593 # tuples for each pair from the test lists above. 594 ranges_eq = [a == b for a in test_ranges for b in test_ranges] 595 tuples_eq = [a == b for a in test_tuples for b in test_tuples] 596 self.assertEqual(ranges_eq, tuples_eq) 597 598 # Check that != correctly gives the logical negation of == 599 ranges_ne = [a != b for a in test_ranges for b in test_ranges] 600 self.assertEqual(ranges_ne, [not x for x in ranges_eq]) 601 602 # Equal ranges should have equal hashes. 603 for a in test_ranges: 604 for b in test_ranges: 605 if a == b: 606 self.assertEqual(hash(a), hash(b)) 607 608 # Ranges are unequal to other types (even sequence types) 609 self.assertIs(range(0) == (), False) 610 self.assertIs(() == range(0), False) 611 self.assertIs(range(2) == [0, 1], False) 612 613 # Huge integers aren't a problem. 614 self.assertEqual(range(0, 2**100 - 1, 2), 615 range(0, 2**100, 2)) 616 self.assertEqual(hash(range(0, 2**100 - 1, 2)), 617 hash(range(0, 2**100, 2))) 618 self.assertNotEqual(range(0, 2**100, 2), 619 range(0, 2**100 + 1, 2)) 620 self.assertEqual(range(2**200, 2**201 - 2**99, 2**100), 621 range(2**200, 2**201, 2**100)) 622 self.assertEqual(hash(range(2**200, 2**201 - 2**99, 2**100)), 623 hash(range(2**200, 2**201, 2**100))) 624 self.assertNotEqual(range(2**200, 2**201, 2**100), 625 range(2**200, 2**201 + 1, 2**100)) 626 627 # Order comparisons are not implemented for ranges. 628 with self.assertRaises(TypeError): 629 range(0) < range(0) 630 with self.assertRaises(TypeError): 631 range(0) > range(0) 632 with self.assertRaises(TypeError): 633 range(0) <= range(0) 634 with self.assertRaises(TypeError): 635 range(0) >= range(0) 636 637 638 def test_attributes(self): 639 # test the start, stop and step attributes of range objects 640 self.assert_attrs(range(0), 0, 0, 1) 641 self.assert_attrs(range(10), 0, 10, 1) 642 self.assert_attrs(range(-10), 0, -10, 1) 643 self.assert_attrs(range(0, 10, 1), 0, 10, 1) 644 self.assert_attrs(range(0, 10, 3), 0, 10, 3) 645 self.assert_attrs(range(10, 0, -1), 10, 0, -1) 646 self.assert_attrs(range(10, 0, -3), 10, 0, -3) 647 648 def assert_attrs(self, rangeobj, start, stop, step): 649 self.assertEqual(rangeobj.start, start) 650 self.assertEqual(rangeobj.stop, stop) 651 self.assertEqual(rangeobj.step, step) 652 653 with self.assertRaises(AttributeError): 654 rangeobj.start = 0 655 with self.assertRaises(AttributeError): 656 rangeobj.stop = 10 657 with self.assertRaises(AttributeError): 658 rangeobj.step = 1 659 660 with self.assertRaises(AttributeError): 661 del rangeobj.start 662 with self.assertRaises(AttributeError): 663 del rangeobj.stop 664 with self.assertRaises(AttributeError): 665 del rangeobj.step 666 667if __name__ == "__main__": 668 unittest.main() 669