|
6 | 6 | import numbers |
7 | 7 | import operator |
8 | 8 | import fractions |
| 9 | +import sys |
9 | 10 | import unittest |
10 | 11 | from copy import copy, deepcopy |
11 | 12 | from pickle import dumps, loads |
@@ -76,6 +77,9 @@ def __ge__(self, other): |
76 | 77 | def __float__(self): |
77 | 78 | assert False, "__float__ should not be invoked" |
78 | 79 |
|
| 80 | +class DummyFraction(fractions.Fraction): |
| 81 | + """Dummy Fraction subclass for copy and deepcopy testing.""" |
| 82 | + |
79 | 83 | class GcdTest(unittest.TestCase): |
80 | 84 |
|
81 | 85 | def testMisc(self): |
@@ -286,9 +290,14 @@ def testLimitDenominator(self): |
286 | 290 | self.assertEqual(F(201, 200).limit_denominator(100), F(1)) |
287 | 291 | self.assertEqual(F(201, 200).limit_denominator(101), F(102, 101)) |
288 | 292 | self.assertEqual(F(0).limit_denominator(10000), F(0)) |
| 293 | + for i in (0, -1): |
| 294 | + self.assertRaisesMessage( |
| 295 | + ValueError, "max_denominator should be at least 1", |
| 296 | + F(1).limit_denominator, i) |
289 | 297 |
|
290 | 298 | def testConversions(self): |
291 | 299 | self.assertTypedEquals(-1, math.trunc(F(-11, 10))) |
| 300 | + self.assertTypedEquals(1, math.trunc(F(11, 10))) |
292 | 301 | self.assertTypedEquals(-2, math.floor(F(-11, 10))) |
293 | 302 | self.assertTypedEquals(-1, math.ceil(F(-11, 10))) |
294 | 303 | self.assertTypedEquals(-1, math.ceil(F(-10, 10))) |
@@ -329,6 +338,7 @@ def testArithmetic(self): |
329 | 338 | self.assertEqual(F(8, 27), F(2, 3) ** F(3)) |
330 | 339 | self.assertEqual(F(27, 8), F(2, 3) ** F(-3)) |
331 | 340 | self.assertTypedEquals(2.0, F(4) ** F(1, 2)) |
| 341 | + self.assertEqual(F(1, 1), +F(1, 1)) |
332 | 342 | z = pow(F(-1), F(1, 2)) |
333 | 343 | self.assertAlmostEqual(z.real, 0) |
334 | 344 | self.assertEqual(z.imag, 1) |
@@ -395,6 +405,10 @@ def testMixingWithDecimal(self): |
395 | 405 | TypeError, |
396 | 406 | "unsupported operand type(s) for +: 'Fraction' and 'Decimal'", |
397 | 407 | operator.add, F(3,11), Decimal('3.1415926')) |
| 408 | + self.assertRaisesMessage( |
| 409 | + TypeError, |
| 410 | + "unsupported operand type(s) for +: 'Decimal' and 'Fraction'", |
| 411 | + operator.add, Decimal('3.1415926'), F(3,11)) |
398 | 412 |
|
399 | 413 | def testComparisons(self): |
400 | 414 | self.assertTrue(F(1, 2) < F(2, 3)) |
@@ -538,9 +552,12 @@ def testStringification(self): |
538 | 552 | self.assertEqual("7", str(F(7, 1))) |
539 | 553 |
|
540 | 554 | def testHash(self): |
| 555 | + hmod = sys.hash_info.modulus |
| 556 | + hinf = sys.hash_info.inf |
541 | 557 | self.assertEqual(hash(2.5), hash(F(5, 2))) |
542 | 558 | self.assertEqual(hash(10**50), hash(F(10**50))) |
543 | 559 | self.assertNotEqual(hash(float(10**23)), hash(F(10**23))) |
| 560 | + self.assertEqual(hinf, hash(F(1, hmod))) |
544 | 561 | # Check that __hash__ produces the same value as hash(), for |
545 | 562 | # consistency with int and Decimal. (See issue #10356.) |
546 | 563 | self.assertEqual(hash(F(-1)), F(-1).__hash__()) |
@@ -574,9 +591,14 @@ def testApproximateCos1(self): |
574 | 591 |
|
575 | 592 | def test_copy_deepcopy_pickle(self): |
576 | 593 | r = F(13, 7) |
| 594 | + dr = DummyFraction(13, 7) |
577 | 595 | self.assertEqual(r, loads(dumps(r))) |
578 | 596 | self.assertEqual(id(r), id(copy(r))) |
579 | 597 | self.assertEqual(id(r), id(deepcopy(r))) |
| 598 | + self.assertNotEqual(id(dr), id(copy(dr))) |
| 599 | + self.assertNotEqual(id(dr), id(deepcopy(dr))) |
| 600 | + self.assertTypedEquals(dr, copy(dr)) |
| 601 | + self.assertTypedEquals(dr, deepcopy(dr)) |
580 | 602 |
|
581 | 603 | def test_slots(self): |
582 | 604 | # Issue 4998 |
|
0 commit comments