diff options
author | Walter Dörwald <walter@livinglogic.de> | 2003-06-18 14:26:18 (GMT) |
---|---|---|
committer | Walter Dörwald <walter@livinglogic.de> | 2003-06-18 14:26:18 (GMT) |
commit | 5edd785bbb1825e8b4e89525b2dad0cec3a9394d (patch) | |
tree | aef1f6d1f199651adac94048dfd1b71b524ab94f /Lib/test/test_complex.py | |
parent | 39c5d666c94f796e4cf0beadb75f5f248f19ee7c (diff) | |
download | cpython-5edd785bbb1825e8b4e89525b2dad0cec3a9394d.zip cpython-5edd785bbb1825e8b4e89525b2dad0cec3a9394d.tar.gz cpython-5edd785bbb1825e8b4e89525b2dad0cec3a9394d.tar.bz2 |
Port test_complex.py to unittest.
Move the constructor tests from test_builtin to test_complex.
Add a bunch of tests (code coverage is a 94%).
From SF patch #736962.
Diffstat (limited to 'Lib/test/test_complex.py')
-rw-r--r-- | Lib/test/test_complex.py | 338 |
1 files changed, 249 insertions, 89 deletions
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 8a02f7f..0963bcc 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -1,91 +1,251 @@ -from test.test_support import TestFailed, vereq +import unittest +from test import test_support + +import warnings +warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message=".*complex divmod.*are deprecated" +) + from random import random -# These tests ensure that complex math does the right thing; tests of -# the complex() function/constructor are in test_b1.py. - -# XXX need many, many more tests here. - -nerrors = 0 - -def check_close_real(x, y, eps=1e-9): - """Return true iff floats x and y "are close\"""" - # put the one with larger magnitude second - if abs(x) > abs(y): - x, y = y, x - if y == 0: - return abs(x) < eps - if x == 0: - return abs(y) < eps - # check that relative difference < eps - return abs((x-y)/y) < eps - -def check_close(x, y, eps=1e-9): - """Return true iff complexes x and y "are close\"""" - return check_close_real(x.real, y.real, eps) and \ - check_close_real(x.imag, y.imag, eps) - -def test_div(x, y): - """Compute complex z=x*y, and check that z/x==y and z/y==x.""" - global nerrors - z = x * y - if x != 0: - q = z / x - if not check_close(q, y): - nerrors += 1 - print "%r / %r == %r but expected %r" % (z, x, q, y) - if y != 0: - q = z / y - if not check_close(q, x): - nerrors += 1 - print "%r / %r == %r but expected %r" % (z, y, q, x) - -simple_real = [float(i) for i in range(-5, 6)] -simple_complex = [complex(x, y) for x in simple_real for y in simple_real] -for x in simple_complex: - for y in simple_complex: - test_div(x, y) - -# A naive complex division algorithm (such as in 2.0) is very prone to -# nonsense errors for these (overflows and underflows). -test_div(complex(1e200, 1e200), 1+0j) -test_div(complex(1e-200, 1e-200), 1+0j) - -# Just for fun. -for i in range(100): - test_div(complex(random(), random()), - complex(random(), random())) - -for i in range(100): - if not complex(random() + 1e-6, random() + 1e-6): - raise TestFailed("complex(random(), random()) should be true") - -if complex(0.0, 0.0): - raise TestFailed("complex(0.0, 0.0) should be false") - -vereq(complex(5.3, 9.8).conjugate(), 5.3-9.8j) - -try: - print int(5+3j) -except TypeError: - pass -else: - raise TestFailed("int(complex()) didn't raise TypeError") - -try: - print float(5+3j) -except TypeError: - pass -else: - raise TestFailed("float(complex()) didn't raise TypeError") - -try: - z = 1.0 / (0+0j) -except ZeroDivisionError: - pass -else: - nerrors += 1 - raise TestFailed("Division by complex 0 didn't raise ZeroDivisionError") - -if nerrors: - raise TestFailed("%d tests failed" % nerrors) +# These tests ensure that complex math does the right thing + +class ComplexTest(unittest.TestCase): + + def assertAlmostEqual(self, a, b): + if isinstance(a, complex): + if isinstance(b, complex): + unittest.TestCase.assertAlmostEqual(self, a.real, b.real) + unittest.TestCase.assertAlmostEqual(self, a.imag, b.imag) + else: + unittest.TestCase.assertAlmostEqual(self, a.real, b) + unittest.TestCase.assertAlmostEqual(self, a.imag, 0.) + else: + if isinstance(b, complex): + unittest.TestCase.assertAlmostEqual(self, a, b.real) + unittest.TestCase.assertAlmostEqual(self, 0., b.imag) + else: + unittest.TestCase.assertAlmostEqual(self, a, b) + + def assertCloseAbs(self, x, y, eps=1e-9): + """Return true iff floats x and y "are close\"""" + # put the one with larger magnitude second + if abs(x) > abs(y): + x, y = y, x + if y == 0: + return abs(x) < eps + if x == 0: + return abs(y) < eps + # check that relative difference < eps + self.assert_(abs((x-y)/y) < eps) + + def assertClose(self, x, y, eps=1e-9): + """Return true iff complexes x and y "are close\"""" + self.assertCloseAbs(x.real, y.real, eps) + self.assertCloseAbs(x.imag, y.imag, eps) + + def assertIs(self, a, b): + self.assert_(a is b) + + def check_div(self, x, y): + """Compute complex z=x*y, and check that z/x==y and z/y==x.""" + z = x * y + if x != 0: + q = z / x + self.assertClose(q, y) + if y != 0: + q = z / y + self.assertClose(q, x) + + def test_div(self): + simple_real = [float(i) for i in xrange(-5, 6)] + simple_complex = [complex(x, y) for x in simple_real for y in simple_real] + for x in simple_complex: + for y in simple_complex: + self.check_div(x, y) + + # A naive complex division algorithm (such as in 2.0) is very prone to + # nonsense errors for these (overflows and underflows). + self.check_div(complex(1e200, 1e200), 1+0j) + self.check_div(complex(1e-200, 1e-200), 1+0j) + + # Just for fun. + for i in xrange(100): + self.check_div(complex(random(), random()), + complex(random(), random())) + + self.assertRaises(ZeroDivisionError, complex.__div__, 1+1j, 0+0j) + # FIXME: The following currently crashes on Alpha + # self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j) + + def test_truediv(self): + self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j) + self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j) + + def test_floordiv(self): + self.assertAlmostEqual(complex.__floordiv__(3+0j, 1.5+0j), 2) + self.assertRaises(ZeroDivisionError, complex.__floordiv__, 3+0j, 0+0j) + + def test_coerce(self): + self.assertRaises(OverflowError, complex.__coerce__, 1+1j, 1L<<10000) + + def test_richcompare(self): + self.assertRaises(OverflowError, complex.__eq__, 1+1j, 1L<<10000) + self.assertEqual(complex.__lt__(1+1j, None), NotImplemented) + self.assertIs(complex.__eq__(1+1j, 1+1j), True) + self.assertIs(complex.__eq__(1+1j, 2+2j), False) + self.assertIs(complex.__ne__(1+1j, 1+1j), False) + self.assertIs(complex.__ne__(1+1j, 2+2j), True) + self.assertRaises(TypeError, complex.__lt__, 1+1j, 2+2j) + self.assertRaises(TypeError, complex.__le__, 1+1j, 2+2j) + self.assertRaises(TypeError, complex.__gt__, 1+1j, 2+2j) + self.assertRaises(TypeError, complex.__ge__, 1+1j, 2+2j) + + def test_mod(self): + self.assertRaises(ZeroDivisionError, (1+1j).__mod__, 0+0j) + + def test_divmod(self): + self.assertRaises(ZeroDivisionError, divmod, 1+1j, 0+0j) + + def test_pow(self): + self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0) + self.assertAlmostEqual(pow(0+0j, 2+0j), 0.0) + self.assertRaises(ZeroDivisionError, pow, 0+0j, 1j) + self.assertAlmostEqual(pow(1j, -1), 1/1j) + self.assertAlmostEqual(pow(1j, 200), 1) + self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j) + + def test_boolcontext(self): + for i in xrange(100): + self.assert_(complex(random() + 1e-6, random() + 1e-6)) + self.assert_(not complex(0.0, 0.0)) + + def test_conjugate(self): + self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j) + + def test_constructor(self): + class OS: + def __init__(self, value): self.value = value + def __complex__(self): return self.value + class NS(object): + def __init__(self, value): self.value = value + def __complex__(self): return self.value + self.assertEqual(complex(OS(1+10j)), 1+10j) + self.assertEqual(complex(NS(1+10j)), 1+10j) + self.assertRaises(TypeError, complex, OS(None)) + self.assertRaises(TypeError, complex, NS(None)) + + self.assertAlmostEqual(complex("1+10j"), 1+10j) + self.assertAlmostEqual(complex(10), 10+0j) + self.assertAlmostEqual(complex(10.0), 10+0j) + self.assertAlmostEqual(complex(10L), 10+0j) + self.assertAlmostEqual(complex(10+0j), 10+0j) + self.assertAlmostEqual(complex(1,10), 1+10j) + self.assertAlmostEqual(complex(1,10L), 1+10j) + self.assertAlmostEqual(complex(1,10.0), 1+10j) + self.assertAlmostEqual(complex(1L,10), 1+10j) + self.assertAlmostEqual(complex(1L,10L), 1+10j) + self.assertAlmostEqual(complex(1L,10.0), 1+10j) + self.assertAlmostEqual(complex(1.0,10), 1+10j) + self.assertAlmostEqual(complex(1.0,10L), 1+10j) + self.assertAlmostEqual(complex(1.0,10.0), 1+10j) + self.assertAlmostEqual(complex(3.14+0j), 3.14+0j) + self.assertAlmostEqual(complex(3.14), 3.14+0j) + self.assertAlmostEqual(complex(314), 314.0+0j) + self.assertAlmostEqual(complex(314L), 314.0+0j) + self.assertAlmostEqual(complex(3.14+0j, 0j), 3.14+0j) + self.assertAlmostEqual(complex(3.14, 0.0), 3.14+0j) + self.assertAlmostEqual(complex(314, 0), 314.0+0j) + self.assertAlmostEqual(complex(314L, 0L), 314.0+0j) + self.assertAlmostEqual(complex(0j, 3.14j), -3.14+0j) + self.assertAlmostEqual(complex(0.0, 3.14j), -3.14+0j) + self.assertAlmostEqual(complex(0j, 3.14), 3.14j) + self.assertAlmostEqual(complex(0.0, 3.14), 3.14j) + self.assertAlmostEqual(complex("1"), 1+0j) + self.assertAlmostEqual(complex("1j"), 1j) + self.assertAlmostEqual(complex(), 0) + self.assertAlmostEqual(complex("-1"), -1) + self.assertAlmostEqual(complex("+1"), +1) + + class complex2(complex): pass + self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j) + self.assertAlmostEqual(complex(real=17, imag=23), 17+23j) + self.assertAlmostEqual(complex(real=17+23j), 17+23j) + self.assertAlmostEqual(complex(real=17+23j, imag=23), 17+46j) + self.assertAlmostEqual(complex(real=1+2j, imag=3+4j), -3+5j) + + c = 3.14 + 1j + self.assert_(complex(c) is c) + del c + + self.assertRaises(TypeError, complex, "1", "1") + self.assertRaises(TypeError, complex, 1, "1") + + self.assertEqual(complex(" 3.14+J "), 3.14+1j) + if test_support.have_unicode: + self.assertEqual(complex(unicode(" 3.14+J ")), 3.14+1j) + + # SF bug 543840: complex(string) accepts strings with \0 + # Fixed in 2.3. + self.assertRaises(ValueError, complex, '1+1j\0j') + + self.assertRaises(TypeError, int, 5+3j) + self.assertRaises(TypeError, long, 5+3j) + self.assertRaises(TypeError, float, 5+3j) + self.assertRaises(ValueError, complex, "") + self.assertRaises(TypeError, complex, None) + self.assertRaises(ValueError, complex, "\0") + self.assertRaises(TypeError, complex, "1", "2") + self.assertRaises(TypeError, complex, "1", 42) + self.assertRaises(TypeError, complex, 1, "2") + self.assertRaises(ValueError, complex, "1+") + self.assertRaises(ValueError, complex, "1+1j+1j") + self.assertRaises(ValueError, complex, "--") + if test_support.have_unicode: + self.assertRaises(ValueError, complex, unicode("1"*500)) + self.assertRaises(ValueError, complex, unicode("x")) + + class EvilExc(Exception): + pass + + class evilcomplex: + def __complex__(self): + raise EvilExc + + self.assertRaises(EvilExc, complex, evilcomplex()) + + class float2: + def __init__(self, value): + self.value = value + def __float__(self): + return self.value + + self.assertAlmostEqual(complex(float2(42.)), 42) + self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j) + self.assertRaises(TypeError, complex, float2(None)) + + def test_hash(self): + for x in xrange(-30, 30): + self.assertEqual(hash(x), hash(complex(x, 0))) + x /= 3.0 # now check against floating point + self.assertEqual(hash(x), hash(complex(x, 0.))) + + def test_abs(self): + nums = [complex(x/3., y/7.) for x in xrange(-9,9) for y in xrange(-9,9)] + for num in nums: + self.assertAlmostEqual((num.real**2 + num.imag**2) ** 0.5, abs(num)) + + def test_repr(self): + self.assertEqual(repr(1+6j), '(1+6j)') + + def test_neg(self): + self.assertEqual(-(1+6j), -1-6j) + + +def test_main(): + test_support.run_unittest(ComplexTest) + +if __name__ == "__main__": + test_main() |