Skip to content

gh-77465: Increase test coverage for numbers #111738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jan 25, 2024
158 changes: 157 additions & 1 deletion Lib/test/test_abstract_numbers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
"""Unit tests for numbers.py."""

import abc
import math
import operator
import unittest
from numbers import Complex, Real, Rational, Integral
from numbers import Complex, Real, Rational, Integral, Number


def concretize(cls):
def not_implemented(*args, **kwargs):
raise NotImplementedError()

for name in dir(cls):
try:
value = getattr(cls, name)
if value.__isabstractmethod__:
setattr(cls, name, not_implemented)
except AttributeError:
pass
abc.update_abstractmethods(cls)
return cls


class TestNumbers(unittest.TestCase):
def test_int(self):
self.assertTrue(issubclass(int, Integral))
self.assertTrue(issubclass(int, Rational))
self.assertTrue(issubclass(int, Real))
self.assertTrue(issubclass(int, Complex))
self.assertTrue(issubclass(int, Number))

self.assertEqual(7, int(7).real)
self.assertEqual(0, int(7).imag)
Expand All @@ -18,17 +38,23 @@ def test_int(self):
self.assertEqual(1, int(7).denominator)

def test_float(self):
self.assertFalse(issubclass(float, Integral))
self.assertFalse(issubclass(float, Rational))
self.assertTrue(issubclass(float, Real))
self.assertTrue(issubclass(float, Complex))
self.assertTrue(issubclass(float, Number))

self.assertEqual(7.3, float(7.3).real)
self.assertEqual(0, float(7.3).imag)
self.assertEqual(7.3, float(7.3).conjugate())
self.assertEqual(-7.3, float(-7.3).conjugate())

def test_complex(self):
self.assertFalse(issubclass(complex, Integral))
self.assertFalse(issubclass(complex, Rational))
self.assertFalse(issubclass(complex, Real))
self.assertTrue(issubclass(complex, Complex))
self.assertTrue(issubclass(complex, Number))

c1, c2 = complex(3, 2), complex(4,1)
# XXX: This is not ideal, but see the comment in math_trunc().
Expand All @@ -40,5 +66,135 @@ def test_complex(self):
self.assertRaises(TypeError, int, c1)


class TestNumbersDefaultMethods(unittest.TestCase):
def test_complex(self):
@concretize
class MyComplex(Complex):
def __init__(self, real, imag):
self.r = real
self.i = imag

@property
def real(self):
return self.r

@property
def imag(self):
return self.i

def __add__(self, other):
if isinstance(other, Complex):
return MyComplex(self.imag + other.imag,
self.real + other.real)
raise NotImplementedError

def __neg__(self):
return MyComplex(-self.real, -self.imag)

def __eq__(self, other):
if isinstance(other, Complex):
return self.imag == other.imag and self.real == other.real
if isinstance(other, Number):
return self.imag == 0 and self.real == other.real

# test __bool__
self.assertTrue(bool(MyComplex(1, 1)))
self.assertTrue(bool(MyComplex(0, 1)))
self.assertTrue(bool(MyComplex(1, 0)))
self.assertFalse(bool(MyComplex(0, 0)))

# test __sub__
self.assertEqual(MyComplex(2, 3) - complex(1, 2), MyComplex(1, 1))

# test __rsub__
self.assertEqual(complex(2, 3) - MyComplex(1, 2), MyComplex(1, 1))

def test_real(self):
@concretize
class MyReal(Real):
def __init__(self, n):
self.n = n

def __pos__(self):
return self.n

def __float__(self):
return float(self.n)

def __floordiv__(self, other):
return self.n // other

def __rfloordiv__(self, other):
return other // self.n

def __mod__(self, other):
return self.n % other

def __rmod__(self, other):
return other % self.n

# test __divmod__
self.assertEqual(divmod(MyReal(3), 2), (1, 1))

# test __rdivmod__
self.assertEqual(divmod(3, MyReal(2)), (1, 1))

# test __complex__
self.assertEqual(complex(MyReal(1)), 1+0j)

# test real
self.assertEqual(MyReal(3).real, 3)

# test imag
self.assertEqual(MyReal(3).imag, 0)

# test conjugate
self.assertEqual(MyReal(123).conjugate(), 123)


def test_rational(self):
@concretize
class MyRational(Rational):
def __init__(self, numerator, denominator):
self.n = numerator
self.d = denominator

@property
def numerator(self):
return self.n

@property
def denominator(self):
return self.d

# test__float__
self.assertEqual(float(MyRational(5, 2)), 2.5)


def test_integral(self):
@concretize
class MyIntegral(Integral):
def __init__(self, n):
self.n = n

def __pos__(self):
return self.n

def __int__(self):
return self.n

# test __index__
self.assertEqual(operator.index(MyIntegral(123)), 123)

# test __float__
self.assertEqual(float(MyIntegral(123)), 123.0)

# test numerator
self.assertEqual(MyIntegral(123).numerator, 123)

# test denominator
self.assertEqual(MyIntegral(123).denominator, 1)


if __name__ == "__main__":
unittest.main()