home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / test_binop.py < prev    next >
Text File  |  2003-12-30  |  11KB  |  329 lines

  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()
  329.