python-2.5.2/win32/Lib/test/test_binop.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Tests for binary operators on subtypes of built-in types."""
       
     2 
       
     3 import unittest
       
     4 from test import test_support
       
     5 
       
     6 def gcd(a, b):
       
     7     """Greatest common divisor using Euclid's algorithm."""
       
     8     while a:
       
     9         a, b = b%a, a
       
    10     return b
       
    11 
       
    12 def isint(x):
       
    13     """Test whether an object is an instance of int or long."""
       
    14     return isinstance(x, int) or isinstance(x, long)
       
    15 
       
    16 def isnum(x):
       
    17     """Test whether an object is an instance of a built-in numeric type."""
       
    18     for T in int, long, float, complex:
       
    19         if isinstance(x, T):
       
    20             return 1
       
    21     return 0
       
    22 
       
    23 def isRat(x):
       
    24     """Test wheter an object is an instance of the Rat class."""
       
    25     return isinstance(x, Rat)
       
    26 
       
    27 class Rat(object):
       
    28 
       
    29     """Rational number implemented as a normalized pair of longs."""
       
    30 
       
    31     __slots__ = ['_Rat__num', '_Rat__den']
       
    32 
       
    33     def __init__(self, num=0L, den=1L):
       
    34         """Constructor: Rat([num[, den]]).
       
    35 
       
    36         The arguments must be ints or longs, and default to (0, 1)."""
       
    37         if not isint(num):
       
    38             raise TypeError, "Rat numerator must be int or long (%r)" % num
       
    39         if not isint(den):
       
    40             raise TypeError, "Rat denominator must be int or long (%r)" % den
       
    41         # But the zero is always on
       
    42         if den == 0:
       
    43             raise ZeroDivisionError, "zero denominator"
       
    44         g = gcd(den, num)
       
    45         self.__num = long(num//g)
       
    46         self.__den = long(den//g)
       
    47 
       
    48     def _get_num(self):
       
    49         """Accessor function for read-only 'num' attribute of Rat."""
       
    50         return self.__num
       
    51     num = property(_get_num, None)
       
    52 
       
    53     def _get_den(self):
       
    54         """Accessor function for read-only 'den' attribute of Rat."""
       
    55         return self.__den
       
    56     den = property(_get_den, None)
       
    57 
       
    58     def __repr__(self):
       
    59         """Convert a Rat to an string resembling a Rat constructor call."""
       
    60         return "Rat(%d, %d)" % (self.__num, self.__den)
       
    61 
       
    62     def __str__(self):
       
    63         """Convert a Rat to a string resembling a decimal numeric value."""
       
    64         return str(float(self))
       
    65 
       
    66     def __float__(self):
       
    67         """Convert a Rat to a float."""
       
    68         return self.__num*1.0/self.__den
       
    69 
       
    70     def __int__(self):
       
    71         """Convert a Rat to an int; self.den must be 1."""
       
    72         if self.__den == 1:
       
    73             try:
       
    74                 return int(self.__num)
       
    75             except OverflowError:
       
    76                 raise OverflowError, ("%s too large to convert to int" %
       
    77                                       repr(self))
       
    78         raise ValueError, "can't convert %s to int" % repr(self)
       
    79 
       
    80     def __long__(self):
       
    81         """Convert a Rat to an long; self.den must be 1."""
       
    82         if self.__den == 1:
       
    83             return long(self.__num)
       
    84         raise ValueError, "can't convert %s to long" % repr(self)
       
    85 
       
    86     def __add__(self, other):
       
    87         """Add two Rats, or a Rat and a number."""
       
    88         if isint(other):
       
    89             other = Rat(other)
       
    90         if isRat(other):
       
    91             return Rat(self.__num*other.__den + other.__num*self.__den,
       
    92                        self.__den*other.__den)
       
    93         if isnum(other):
       
    94             return float(self) + other
       
    95         return NotImplemented
       
    96 
       
    97     __radd__ = __add__
       
    98 
       
    99     def __sub__(self, other):
       
   100         """Subtract two Rats, or a Rat and a number."""
       
   101         if isint(other):
       
   102             other = Rat(other)
       
   103         if isRat(other):
       
   104             return Rat(self.__num*other.__den - other.__num*self.__den,
       
   105                        self.__den*other.__den)
       
   106         if isnum(other):
       
   107             return float(self) - other
       
   108         return NotImplemented
       
   109 
       
   110     def __rsub__(self, other):
       
   111         """Subtract two Rats, or a Rat and a number (reversed args)."""
       
   112         if isint(other):
       
   113             other = Rat(other)
       
   114         if isRat(other):
       
   115             return Rat(other.__num*self.__den - self.__num*other.__den,
       
   116                        self.__den*other.__den)
       
   117         if isnum(other):
       
   118             return other - float(self)
       
   119         return NotImplemented
       
   120 
       
   121     def __mul__(self, other):
       
   122         """Multiply two Rats, or a Rat and a number."""
       
   123         if isRat(other):
       
   124             return Rat(self.__num*other.__num, self.__den*other.__den)
       
   125         if isint(other):
       
   126             return Rat(self.__num*other, self.__den)
       
   127         if isnum(other):
       
   128             return float(self)*other
       
   129         return NotImplemented
       
   130 
       
   131     __rmul__ = __mul__
       
   132 
       
   133     def __truediv__(self, other):
       
   134         """Divide two Rats, or a Rat and a number."""
       
   135         if isRat(other):
       
   136             return Rat(self.__num*other.__den, self.__den*other.__num)
       
   137         if isint(other):
       
   138             return Rat(self.__num, self.__den*other)
       
   139         if isnum(other):
       
   140             return float(self) / other
       
   141         return NotImplemented
       
   142 
       
   143     __div__ = __truediv__
       
   144 
       
   145     def __rtruediv__(self, other):
       
   146         """Divide two Rats, or a Rat and a number (reversed args)."""
       
   147         if isRat(other):
       
   148             return Rat(other.__num*self.__den, other.__den*self.__num)
       
   149         if isint(other):
       
   150             return Rat(other*self.__den, self.__num)
       
   151         if isnum(other):
       
   152             return other / float(self)
       
   153         return NotImplemented
       
   154 
       
   155     __rdiv__ = __rtruediv__
       
   156 
       
   157     def __floordiv__(self, other):
       
   158         """Divide two Rats, returning the floored result."""
       
   159         if isint(other):
       
   160             other = Rat(other)
       
   161         elif not isRat(other):
       
   162             return NotImplemented
       
   163         x = self/other
       
   164         return x.__num // x.__den
       
   165 
       
   166     def __rfloordiv__(self, other):
       
   167         """Divide two Rats, returning the floored result (reversed args)."""
       
   168         x = other/self
       
   169         return x.__num // x.__den
       
   170 
       
   171     def __divmod__(self, other):
       
   172         """Divide two Rats, returning quotient and remainder."""
       
   173         if isint(other):
       
   174             other = Rat(other)
       
   175         elif not isRat(other):
       
   176             return NotImplemented
       
   177         x = self//other
       
   178         return (x, self - other * x)
       
   179 
       
   180     def __rdivmod__(self, other):
       
   181         """Divide two Rats, returning quotient and remainder (reversed args)."""
       
   182         if isint(other):
       
   183             other = Rat(other)
       
   184         elif not isRat(other):
       
   185             return NotImplemented
       
   186         return divmod(other, self)
       
   187 
       
   188     def __mod__(self, other):
       
   189         """Take one Rat modulo another."""
       
   190         return divmod(self, other)[1]
       
   191 
       
   192     def __rmod__(self, other):
       
   193         """Take one Rat modulo another (reversed args)."""
       
   194         return divmod(other, self)[1]
       
   195 
       
   196     def __eq__(self, other):
       
   197         """Compare two Rats for equality."""
       
   198         if isint(other):
       
   199             return self.__den == 1 and self.__num == other
       
   200         if isRat(other):
       
   201             return self.__num == other.__num and self.__den == other.__den
       
   202         if isnum(other):
       
   203             return float(self) == other
       
   204         return NotImplemented
       
   205 
       
   206     def __ne__(self, other):
       
   207         """Compare two Rats for inequality."""
       
   208         return not self == other
       
   209 
       
   210 class RatTestCase(unittest.TestCase):
       
   211     """Unit tests for Rat class and its support utilities."""
       
   212 
       
   213     def test_gcd(self):
       
   214         self.assertEqual(gcd(10, 12), 2)
       
   215         self.assertEqual(gcd(10, 15), 5)
       
   216         self.assertEqual(gcd(10, 11), 1)
       
   217         self.assertEqual(gcd(100, 15), 5)
       
   218         self.assertEqual(gcd(-10, 2), -2)
       
   219         self.assertEqual(gcd(10, -2), 2)
       
   220         self.assertEqual(gcd(-10, -2), -2)
       
   221         for i in range(1, 20):
       
   222             for j in range(1, 20):
       
   223                 self.assert_(gcd(i, j) > 0)
       
   224                 self.assert_(gcd(-i, j) < 0)
       
   225                 self.assert_(gcd(i, -j) > 0)
       
   226                 self.assert_(gcd(-i, -j) < 0)
       
   227 
       
   228     def test_constructor(self):
       
   229         a = Rat(10, 15)
       
   230         self.assertEqual(a.num, 2)
       
   231         self.assertEqual(a.den, 3)
       
   232         a = Rat(10L, 15L)
       
   233         self.assertEqual(a.num, 2)
       
   234         self.assertEqual(a.den, 3)
       
   235         a = Rat(10, -15)
       
   236         self.assertEqual(a.num, -2)
       
   237         self.assertEqual(a.den, 3)
       
   238         a = Rat(-10, 15)
       
   239         self.assertEqual(a.num, -2)
       
   240         self.assertEqual(a.den, 3)
       
   241         a = Rat(-10, -15)
       
   242         self.assertEqual(a.num, 2)
       
   243         self.assertEqual(a.den, 3)
       
   244         a = Rat(7)
       
   245         self.assertEqual(a.num, 7)
       
   246         self.assertEqual(a.den, 1)
       
   247         try:
       
   248             a = Rat(1, 0)
       
   249         except ZeroDivisionError:
       
   250             pass
       
   251         else:
       
   252             self.fail("Rat(1, 0) didn't raise ZeroDivisionError")
       
   253         for bad in "0", 0.0, 0j, (), [], {}, None, Rat, unittest:
       
   254             try:
       
   255                 a = Rat(bad)
       
   256             except TypeError:
       
   257                 pass
       
   258             else:
       
   259                 self.fail("Rat(%r) didn't raise TypeError" % bad)
       
   260             try:
       
   261                 a = Rat(1, bad)
       
   262             except TypeError:
       
   263                 pass
       
   264             else:
       
   265                 self.fail("Rat(1, %r) didn't raise TypeError" % bad)
       
   266 
       
   267     def test_add(self):
       
   268         self.assertEqual(Rat(2, 3) + Rat(1, 3), 1)
       
   269         self.assertEqual(Rat(2, 3) + 1, Rat(5, 3))
       
   270         self.assertEqual(1 + Rat(2, 3), Rat(5, 3))
       
   271         self.assertEqual(1.0 + Rat(1, 2), 1.5)
       
   272         self.assertEqual(Rat(1, 2) + 1.0, 1.5)
       
   273 
       
   274     def test_sub(self):
       
   275         self.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10))
       
   276         self.assertEqual(Rat(7, 5) - 1, Rat(2, 5))
       
   277         self.assertEqual(1 - Rat(3, 5), Rat(2, 5))
       
   278         self.assertEqual(Rat(3, 2) - 1.0, 0.5)
       
   279         self.assertEqual(1.0 - Rat(1, 2), 0.5)
       
   280 
       
   281     def test_mul(self):
       
   282         self.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21))
       
   283         self.assertEqual(Rat(10, 3) * 3, 10)
       
   284         self.assertEqual(3 * Rat(10, 3), 10)
       
   285         self.assertEqual(Rat(10, 5) * 0.5, 1.0)
       
   286         self.assertEqual(0.5 * Rat(10, 5), 1.0)
       
   287 
       
   288     def test_div(self):
       
   289         self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
       
   290         self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
       
   291         self.assertEqual(2 / Rat(5), Rat(2, 5))
       
   292         self.assertEqual(3.0 * Rat(1, 2), 1.5)
       
   293         self.assertEqual(Rat(1, 2) * 3.0, 1.5)
       
   294 
       
   295     def test_floordiv(self):
       
   296         self.assertEqual(Rat(10) // Rat(4), 2)
       
   297         self.assertEqual(Rat(10, 3) // Rat(4, 3), 2)
       
   298         self.assertEqual(Rat(10) // 4, 2)
       
   299         self.assertEqual(10 // Rat(4), 2)
       
   300 
       
   301     def test_eq(self):
       
   302         self.assertEqual(Rat(10), Rat(20, 2))
       
   303         self.assertEqual(Rat(10), 10)
       
   304         self.assertEqual(10, Rat(10))
       
   305         self.assertEqual(Rat(10), 10.0)
       
   306         self.assertEqual(10.0, Rat(10))
       
   307 
       
   308     def test_future_div(self):
       
   309         exec future_test
       
   310 
       
   311     # XXX Ran out of steam; TO DO: divmod, div, future division
       
   312 
       
   313 future_test = """
       
   314 from __future__ import division
       
   315 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
       
   316 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
       
   317 self.assertEqual(2 / Rat(5), Rat(2, 5))
       
   318 self.assertEqual(3.0 * Rat(1, 2), 1.5)
       
   319 self.assertEqual(Rat(1, 2) * 3.0, 1.5)
       
   320 self.assertEqual(eval('1/2'), 0.5)
       
   321 """
       
   322 
       
   323 def test_main():
       
   324     test_support.run_unittest(RatTestCase)
       
   325 
       
   326 
       
   327 if __name__ == "__main__":
       
   328     test_main()