Skip to content

Commit c6aea46

Browse files
encukouskirpichev
andauthored
[3.12] gh-102837: more tests for the math module (GH-111930)(GH-102523) (GH-112030)
* gh-102837: improve test coverage for math module (GH-102523) (Only the test changes from GH-102523 are cherry-picked) - input checks for math_1(L989), math_1a(L1023), math_2(L1064,L1071), hypot(L2682), log(L2307), ldexp(L2168), ceil(L1165), floor(L1236,L1239) and dist(L2587,L2588,L2628). - improve fsum coverage for exceptional cases (L1433,L1438,L1451,L1497), ditto fmod(L2378) (all line numbers are wrt the main branch at 5e6661b) * gh-102837: more tests for the math module (GH-111930) Add tests to improve coverage: * fsum: L1369, L1379, L1383, L1412 * trunc: L2081 * log: L2267 * dist: L2577, L2579 * hypot: L2632 * sumprod: L2744, L2754, L2774, L2778, L2781, L2785, L2831, L2835, L2838 * pow: L2982 * prod: L3294, L3308, L3318-3330 // line numbers wrt to 9dc4fb8 (cherry picked from commit c61de45) --------- Co-authored-by: Sergey B Kirpichev <[email protected]>
1 parent 9aa5ff8 commit c6aea46

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

Lib/test/test_math.py

+96
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ def __init__(self, value):
235235
def __index__(self):
236236
return self.value
237237

238+
class BadDescr:
239+
def __get__(self, obj, objtype=None):
240+
raise ValueError
241+
238242
class MathTests(unittest.TestCase):
239243

240244
def ftest(self, name, got, expected, ulp_tol=5, abs_tol=0.0):
@@ -324,6 +328,7 @@ def testAtan2(self):
324328
self.ftest('atan2(0, 1)', math.atan2(0, 1), 0)
325329
self.ftest('atan2(1, 1)', math.atan2(1, 1), math.pi/4)
326330
self.ftest('atan2(1, 0)', math.atan2(1, 0), math.pi/2)
331+
self.ftest('atan2(1, -1)', math.atan2(1, -1), 3*math.pi/4)
327332

328333
# math.atan2(0, x)
329334
self.ftest('atan2(0., -inf)', math.atan2(0., NINF), math.pi)
@@ -417,16 +422,22 @@ def __ceil__(self):
417422
return 42
418423
class TestNoCeil:
419424
pass
425+
class TestBadCeil:
426+
__ceil__ = BadDescr()
420427
self.assertEqual(math.ceil(TestCeil()), 42)
421428
self.assertEqual(math.ceil(FloatCeil()), 42)
422429
self.assertEqual(math.ceil(FloatLike(42.5)), 43)
423430
self.assertRaises(TypeError, math.ceil, TestNoCeil())
431+
self.assertRaises(ValueError, math.ceil, TestBadCeil())
424432

425433
t = TestNoCeil()
426434
t.__ceil__ = lambda *args: args
427435
self.assertRaises(TypeError, math.ceil, t)
428436
self.assertRaises(TypeError, math.ceil, t, 0)
429437

438+
self.assertEqual(math.ceil(FloatLike(+1.0)), +1.0)
439+
self.assertEqual(math.ceil(FloatLike(-1.0)), -1.0)
440+
430441
@requires_IEEE_754
431442
def testCopysign(self):
432443
self.assertEqual(math.copysign(1, 42), 1.0)
@@ -567,16 +578,22 @@ def __floor__(self):
567578
return 42
568579
class TestNoFloor:
569580
pass
581+
class TestBadFloor:
582+
__floor__ = BadDescr()
570583
self.assertEqual(math.floor(TestFloor()), 42)
571584
self.assertEqual(math.floor(FloatFloor()), 42)
572585
self.assertEqual(math.floor(FloatLike(41.9)), 41)
573586
self.assertRaises(TypeError, math.floor, TestNoFloor())
587+
self.assertRaises(ValueError, math.floor, TestBadFloor())
574588

575589
t = TestNoFloor()
576590
t.__floor__ = lambda *args: args
577591
self.assertRaises(TypeError, math.floor, t)
578592
self.assertRaises(TypeError, math.floor, t, 0)
579593

594+
self.assertEqual(math.floor(FloatLike(+1.0)), +1.0)
595+
self.assertEqual(math.floor(FloatLike(-1.0)), -1.0)
596+
580597
def testFmod(self):
581598
self.assertRaises(TypeError, math.fmod)
582599
self.ftest('fmod(10, 1)', math.fmod(10, 1), 0.0)
@@ -598,6 +615,7 @@ def testFmod(self):
598615
self.assertEqual(math.fmod(-3.0, NINF), -3.0)
599616
self.assertEqual(math.fmod(0.0, 3.0), 0.0)
600617
self.assertEqual(math.fmod(0.0, NINF), 0.0)
618+
self.assertRaises(ValueError, math.fmod, INF, INF)
601619

602620
def testFrexp(self):
603621
self.assertRaises(TypeError, math.frexp)
@@ -667,6 +685,7 @@ def msum(iterable):
667685
([], 0.0),
668686
([0.0], 0.0),
669687
([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100),
688+
([1e100, 1.0, -1e100, 1e-100, 1e50, -1, -1e50], 1e-100),
670689
([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0),
671690
([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0),
672691
([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0),
@@ -714,6 +733,22 @@ def msum(iterable):
714733
s = msum(vals)
715734
self.assertEqual(msum(vals), math.fsum(vals))
716735

736+
self.assertEqual(math.fsum([1.0, math.inf]), math.inf)
737+
self.assertTrue(math.isnan(math.fsum([math.nan, 1.0])))
738+
self.assertEqual(math.fsum([1e100, FloatLike(1.0), -1e100, 1e-100,
739+
1e50, FloatLike(-1.0), -1e50]), 1e-100)
740+
self.assertRaises(OverflowError, math.fsum, [1e+308, 1e+308])
741+
self.assertRaises(ValueError, math.fsum, [math.inf, -math.inf])
742+
self.assertRaises(TypeError, math.fsum, ['spam'])
743+
self.assertRaises(TypeError, math.fsum, 1)
744+
self.assertRaises(OverflowError, math.fsum, [10**1000])
745+
746+
def bad_iter():
747+
yield 1.0
748+
raise ZeroDivisionError
749+
750+
self.assertRaises(ZeroDivisionError, math.fsum, bad_iter())
751+
717752
def testGcd(self):
718753
gcd = math.gcd
719754
self.assertEqual(gcd(0, 0), 0)
@@ -774,6 +809,8 @@ def testHypot(self):
774809
# Test allowable types (those with __float__)
775810
self.assertEqual(hypot(12.0, 5.0), 13.0)
776811
self.assertEqual(hypot(12, 5), 13)
812+
self.assertEqual(hypot(1, -1), math.sqrt(2))
813+
self.assertEqual(hypot(1, FloatLike(-1.)), math.sqrt(2))
777814
self.assertEqual(hypot(Decimal(12), Decimal(5)), 13)
778815
self.assertEqual(hypot(Fraction(12, 32), Fraction(5, 32)), Fraction(13, 32))
779816
self.assertEqual(hypot(bool(1), bool(0), bool(1), bool(1)), math.sqrt(3))
@@ -831,6 +868,8 @@ def testHypot(self):
831868
scale = FLOAT_MIN / 2.0 ** exp
832869
self.assertEqual(math.hypot(4*scale, 3*scale), 5*scale)
833870

871+
self.assertRaises(TypeError, math.hypot, *([1.0]*18), 'spam')
872+
834873
@requires_IEEE_754
835874
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
836875
"hypot() loses accuracy on machines with double rounding")
@@ -923,6 +962,10 @@ def testDist(self):
923962
# Test allowable types (those with __float__)
924963
self.assertEqual(dist((14.0, 1.0), (2.0, -4.0)), 13.0)
925964
self.assertEqual(dist((14, 1), (2, -4)), 13)
965+
self.assertEqual(dist((FloatLike(14.), 1), (2, -4)), 13)
966+
self.assertEqual(dist((11, 1), (FloatLike(-1.), -4)), 13)
967+
self.assertEqual(dist((14, FloatLike(-1.)), (2, -6)), 13)
968+
self.assertEqual(dist((14, -1), (2, -6)), 13)
926969
self.assertEqual(dist((D(14), D(1)), (D(2), D(-4))), D(13))
927970
self.assertEqual(dist((F(14, 32), F(1, 32)), (F(2, 32), F(-4, 32))),
928971
F(13, 32))
@@ -966,13 +1009,25 @@ class T(tuple):
9661009
dist((1, 2, 3, 4), (5, 6, 7))
9671010
with self.assertRaises(ValueError): # Check dimension agree
9681011
dist((1, 2, 3), (4, 5, 6, 7))
1012+
with self.assertRaises(TypeError):
1013+
dist((1,)*17 + ("spam",), (1,)*18)
9691014
with self.assertRaises(TypeError): # Rejects invalid types
9701015
dist("abc", "xyz")
9711016
int_too_big_for_float = 10 ** (sys.float_info.max_10_exp + 5)
9721017
with self.assertRaises((ValueError, OverflowError)):
9731018
dist((1, int_too_big_for_float), (2, 3))
9741019
with self.assertRaises((ValueError, OverflowError)):
9751020
dist((2, 3), (1, int_too_big_for_float))
1021+
with self.assertRaises(TypeError):
1022+
dist((1,), 2)
1023+
with self.assertRaises(TypeError):
1024+
dist([1], 2)
1025+
1026+
class BadFloat:
1027+
__float__ = BadDescr()
1028+
1029+
with self.assertRaises(ValueError):
1030+
dist([1], [BadFloat()])
9761031

9771032
# Verify that the one dimensional case is equivalent to abs()
9781033
for i in range(20):
@@ -1111,6 +1166,7 @@ def test_lcm(self):
11111166

11121167
def testLdexp(self):
11131168
self.assertRaises(TypeError, math.ldexp)
1169+
self.assertRaises(TypeError, math.ldexp, 2.0, 1.1)
11141170
self.ftest('ldexp(0,1)', math.ldexp(0,1), 0)
11151171
self.ftest('ldexp(1,1)', math.ldexp(1,1), 2)
11161172
self.ftest('ldexp(1,-1)', math.ldexp(1,-1), 0.5)
@@ -1143,6 +1199,7 @@ def testLdexp(self):
11431199

11441200
def testLog(self):
11451201
self.assertRaises(TypeError, math.log)
1202+
self.assertRaises(TypeError, math.log, 1, 2, 3)
11461203
self.ftest('log(1/e)', math.log(1/math.e), -1)
11471204
self.ftest('log(1)', math.log(1), 0)
11481205
self.ftest('log(e)', math.log(math.e), 1)
@@ -1153,6 +1210,7 @@ def testLog(self):
11531210
2302.5850929940457)
11541211
self.assertRaises(ValueError, math.log, -1.5)
11551212
self.assertRaises(ValueError, math.log, -10**1000)
1213+
self.assertRaises(ValueError, math.log, 10, -10)
11561214
self.assertRaises(ValueError, math.log, NINF)
11571215
self.assertEqual(math.log(INF), INF)
11581216
self.assertTrue(math.isnan(math.log(NAN)))
@@ -1212,6 +1270,8 @@ def testSumProd(self):
12121270
self.assertEqual(sumprod(iter([10, 20, 30]), (1, 2, 3)), 140)
12131271
self.assertEqual(sumprod([1.5, 2.5], [3.5, 4.5]), 16.5)
12141272
self.assertEqual(sumprod([], []), 0)
1273+
self.assertEqual(sumprod([-1], [1.]), -1)
1274+
self.assertEqual(sumprod([1.], [-1]), -1)
12151275

12161276
# Type preservation and coercion
12171277
for v in [
@@ -1237,11 +1297,20 @@ def testSumProd(self):
12371297
self.assertRaises(TypeError, sumprod, [], [], []) # Three args
12381298
self.assertRaises(TypeError, sumprod, None, [10]) # Non-iterable
12391299
self.assertRaises(TypeError, sumprod, [10], None) # Non-iterable
1300+
self.assertRaises(TypeError, sumprod, ['x'], [1.0])
12401301

12411302
# Uneven lengths
12421303
self.assertRaises(ValueError, sumprod, [10, 20], [30])
12431304
self.assertRaises(ValueError, sumprod, [10], [20, 30])
12441305

1306+
# Overflows
1307+
self.assertEqual(sumprod([10**20], [1]), 10**20)
1308+
self.assertEqual(sumprod([1], [10**20]), 10**20)
1309+
self.assertEqual(sumprod([10**10], [10**10]), 10**20)
1310+
self.assertEqual(sumprod([10**7]*10**5, [10**7]*10**5), 10**19)
1311+
self.assertRaises(OverflowError, sumprod, [10**1000], [1.0])
1312+
self.assertRaises(OverflowError, sumprod, [1.0], [10**1000])
1313+
12451314
# Error in iterator
12461315
def raise_after(n):
12471316
for i in range(n):
@@ -1252,6 +1321,11 @@ def raise_after(n):
12521321
with self.assertRaises(RuntimeError):
12531322
sumprod(raise_after(5), range(10))
12541323

1324+
from test.test_iter import BasicIterClass
1325+
1326+
self.assertEqual(sumprod(BasicIterClass(1), [1]), 0)
1327+
self.assertEqual(sumprod([1], BasicIterClass(1)), 0)
1328+
12551329
# Error in multiplication
12561330
class BadMultiply:
12571331
def __mul__(self, other):
@@ -1491,6 +1565,7 @@ def testPow(self):
14911565
self.assertTrue(math.isnan(math.pow(2, NAN)))
14921566
self.assertTrue(math.isnan(math.pow(0, NAN)))
14931567
self.assertEqual(math.pow(1, NAN), 1)
1568+
self.assertRaises(OverflowError, math.pow, 1e+100, 1e+100)
14941569

14951570
# pow(0., x)
14961571
self.assertEqual(math.pow(0., INF), 0.)
@@ -1847,6 +1922,8 @@ def __trunc__(self):
18471922
return 23
18481923
class TestNoTrunc:
18491924
pass
1925+
class TestBadTrunc:
1926+
__trunc__ = BadDescr()
18501927

18511928
self.assertEqual(math.trunc(TestTrunc()), 23)
18521929
self.assertEqual(math.trunc(FloatTrunc()), 23)
@@ -1855,6 +1932,7 @@ class TestNoTrunc:
18551932
self.assertRaises(TypeError, math.trunc, 1, 2)
18561933
self.assertRaises(TypeError, math.trunc, FloatLike(23.5))
18571934
self.assertRaises(TypeError, math.trunc, TestNoTrunc())
1935+
self.assertRaises(ValueError, math.trunc, TestBadTrunc())
18581936

18591937
def testIsfinite(self):
18601938
self.assertTrue(math.isfinite(0.0))
@@ -2055,6 +2133,8 @@ def test_mtestfile(self):
20552133
'\n '.join(failures))
20562134

20572135
def test_prod(self):
2136+
from fractions import Fraction as F
2137+
20582138
prod = math.prod
20592139
self.assertEqual(prod([]), 1)
20602140
self.assertEqual(prod([], start=5), 5)
@@ -2066,6 +2146,14 @@ def test_prod(self):
20662146
self.assertEqual(prod([1.0, 2.0, 3.0, 4.0, 5.0]), 120.0)
20672147
self.assertEqual(prod([1, 2, 3, 4.0, 5.0]), 120.0)
20682148
self.assertEqual(prod([1.0, 2.0, 3.0, 4, 5]), 120.0)
2149+
self.assertEqual(prod([1., F(3, 2)]), 1.5)
2150+
2151+
# Error in multiplication
2152+
class BadMultiply:
2153+
def __rmul__(self, other):
2154+
raise RuntimeError
2155+
with self.assertRaises(RuntimeError):
2156+
prod([10., BadMultiply()])
20692157

20702158
# Test overflow in fast-path for integers
20712159
self.assertEqual(prod([1, 1, 2**32, 1, 1]), 2**32)
@@ -2379,6 +2467,14 @@ def __float__(self):
23792467
# argument to a float.
23802468
self.assertFalse(getattr(y, "converted", False))
23812469

2470+
def test_input_exceptions(self):
2471+
self.assertRaises(TypeError, math.exp, "spam")
2472+
self.assertRaises(TypeError, math.erf, "spam")
2473+
self.assertRaises(TypeError, math.atan2, "spam", 1.0)
2474+
self.assertRaises(TypeError, math.atan2, 1.0, "spam")
2475+
self.assertRaises(TypeError, math.atan2, 1.0)
2476+
self.assertRaises(TypeError, math.atan2, 1.0, 2.0, 3.0)
2477+
23822478
# Custom assertions.
23832479

23842480
def assertIsNaN(self, value):

0 commit comments

Comments
 (0)