test_binop.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. """Tests for binary operators on subtypes of built-in types."""
  2. import unittest
  3. from operator import eq, le, ne
  4. from abc import ABCMeta
  5. def gcd(a, b):
  6. """Greatest common divisor using Euclid's algorithm."""
  7. while a:
  8. a, b = b%a, a
  9. return b
  10. def isint(x):
  11. """Test whether an object is an instance of int."""
  12. return isinstance(x, int)
  13. def isnum(x):
  14. """Test whether an object is an instance of a built-in numeric type."""
  15. for T in int, float, complex:
  16. if isinstance(x, T):
  17. return 1
  18. return 0
  19. def isRat(x):
  20. """Test whether an object is an instance of the Rat class."""
  21. return isinstance(x, Rat)
  22. class Rat(object):
  23. """Rational number implemented as a normalized pair of ints."""
  24. __slots__ = ['_Rat__num', '_Rat__den']
  25. def __init__(self, num=0, den=1):
  26. """Constructor: Rat([num[, den]]).
  27. The arguments must be ints, and default to (0, 1)."""
  28. if not isint(num):
  29. raise TypeError("Rat numerator must be int (%r)" % num)
  30. if not isint(den):
  31. raise TypeError("Rat denominator must be int (%r)" % den)
  32. # But the zero is always on
  33. if den == 0:
  34. raise ZeroDivisionError("zero denominator")
  35. g = gcd(den, num)
  36. self.__num = int(num//g)
  37. self.__den = int(den//g)
  38. def _get_num(self):
  39. """Accessor function for read-only 'num' attribute of Rat."""
  40. return self.__num
  41. num = property(_get_num, None)
  42. def _get_den(self):
  43. """Accessor function for read-only 'den' attribute of Rat."""
  44. return self.__den
  45. den = property(_get_den, None)
  46. def __repr__(self):
  47. """Convert a Rat to a string resembling a Rat constructor call."""
  48. return "Rat(%d, %d)" % (self.__num, self.__den)
  49. def __str__(self):
  50. """Convert a Rat to a string resembling a decimal numeric value."""
  51. return str(float(self))
  52. def __float__(self):
  53. """Convert a Rat to a float."""
  54. return self.__num*1.0/self.__den
  55. def __int__(self):
  56. """Convert a Rat to an int; self.den must be 1."""
  57. if self.__den == 1:
  58. try:
  59. return int(self.__num)
  60. except OverflowError:
  61. raise OverflowError("%s too large to convert to int" %
  62. repr(self))
  63. raise ValueError("can't convert %s to int" % repr(self))
  64. def __add__(self, other):
  65. """Add two Rats, or a Rat and a number."""
  66. if isint(other):
  67. other = Rat(other)
  68. if isRat(other):
  69. return Rat(self.__num*other.__den + other.__num*self.__den,
  70. self.__den*other.__den)
  71. if isnum(other):
  72. return float(self) + other
  73. return NotImplemented
  74. __radd__ = __add__
  75. def __sub__(self, other):
  76. """Subtract two Rats, or a Rat and a number."""
  77. if isint(other):
  78. other = Rat(other)
  79. if isRat(other):
  80. return Rat(self.__num*other.__den - other.__num*self.__den,
  81. self.__den*other.__den)
  82. if isnum(other):
  83. return float(self) - other
  84. return NotImplemented
  85. def __rsub__(self, other):
  86. """Subtract two Rats, or a Rat and a number (reversed args)."""
  87. if isint(other):
  88. other = Rat(other)
  89. if isRat(other):
  90. return Rat(other.__num*self.__den - self.__num*other.__den,
  91. self.__den*other.__den)
  92. if isnum(other):
  93. return other - float(self)
  94. return NotImplemented
  95. def __mul__(self, other):
  96. """Multiply two Rats, or a Rat and a number."""
  97. if isRat(other):
  98. return Rat(self.__num*other.__num, self.__den*other.__den)
  99. if isint(other):
  100. return Rat(self.__num*other, self.__den)
  101. if isnum(other):
  102. return float(self)*other
  103. return NotImplemented
  104. __rmul__ = __mul__
  105. def __truediv__(self, other):
  106. """Divide two Rats, or a Rat and a number."""
  107. if isRat(other):
  108. return Rat(self.__num*other.__den, self.__den*other.__num)
  109. if isint(other):
  110. return Rat(self.__num, self.__den*other)
  111. if isnum(other):
  112. return float(self) / other
  113. return NotImplemented
  114. def __rtruediv__(self, other):
  115. """Divide two Rats, or a Rat and a number (reversed args)."""
  116. if isRat(other):
  117. return Rat(other.__num*self.__den, other.__den*self.__num)
  118. if isint(other):
  119. return Rat(other*self.__den, self.__num)
  120. if isnum(other):
  121. return other / float(self)
  122. return NotImplemented
  123. def __floordiv__(self, other):
  124. """Divide two Rats, returning the floored result."""
  125. if isint(other):
  126. other = Rat(other)
  127. elif not isRat(other):
  128. return NotImplemented
  129. x = self/other
  130. return x.__num // x.__den
  131. def __rfloordiv__(self, other):
  132. """Divide two Rats, returning the floored result (reversed args)."""
  133. x = other/self
  134. return x.__num // x.__den
  135. def __divmod__(self, other):
  136. """Divide two Rats, returning quotient and remainder."""
  137. if isint(other):
  138. other = Rat(other)
  139. elif not isRat(other):
  140. return NotImplemented
  141. x = self//other
  142. return (x, self - other * x)
  143. def __rdivmod__(self, other):
  144. """Divide two Rats, returning quotient and remainder (reversed args)."""
  145. if isint(other):
  146. other = Rat(other)
  147. elif not isRat(other):
  148. return NotImplemented
  149. return divmod(other, self)
  150. def __mod__(self, other):
  151. """Take one Rat modulo another."""
  152. return divmod(self, other)[1]
  153. def __rmod__(self, other):
  154. """Take one Rat modulo another (reversed args)."""
  155. return divmod(other, self)[1]
  156. def __eq__(self, other):
  157. """Compare two Rats for equality."""
  158. if isint(other):
  159. return self.__den == 1 and self.__num == other
  160. if isRat(other):
  161. return self.__num == other.__num and self.__den == other.__den
  162. if isnum(other):
  163. return float(self) == other
  164. return NotImplemented
  165. class RatTestCase(unittest.TestCase):
  166. """Unit tests for Rat class and its support utilities."""
  167. def test_gcd(self):
  168. self.assertEqual(gcd(10, 12), 2)
  169. self.assertEqual(gcd(10, 15), 5)
  170. self.assertEqual(gcd(10, 11), 1)
  171. self.assertEqual(gcd(100, 15), 5)
  172. self.assertEqual(gcd(-10, 2), -2)
  173. self.assertEqual(gcd(10, -2), 2)
  174. self.assertEqual(gcd(-10, -2), -2)
  175. for i in range(1, 20):
  176. for j in range(1, 20):
  177. self.assertTrue(gcd(i, j) > 0)
  178. self.assertTrue(gcd(-i, j) < 0)
  179. self.assertTrue(gcd(i, -j) > 0)
  180. self.assertTrue(gcd(-i, -j) < 0)
  181. def test_constructor(self):
  182. a = Rat(10, 15)
  183. self.assertEqual(a.num, 2)
  184. self.assertEqual(a.den, 3)
  185. a = Rat(10, -15)
  186. self.assertEqual(a.num, -2)
  187. self.assertEqual(a.den, 3)
  188. a = Rat(-10, 15)
  189. self.assertEqual(a.num, -2)
  190. self.assertEqual(a.den, 3)
  191. a = Rat(-10, -15)
  192. self.assertEqual(a.num, 2)
  193. self.assertEqual(a.den, 3)
  194. a = Rat(7)
  195. self.assertEqual(a.num, 7)
  196. self.assertEqual(a.den, 1)
  197. try:
  198. a = Rat(1, 0)
  199. except ZeroDivisionError:
  200. pass
  201. else:
  202. self.fail("Rat(1, 0) didn't raise ZeroDivisionError")
  203. for bad in "0", 0.0, 0j, (), [], {}, None, Rat, unittest:
  204. try:
  205. a = Rat(bad)
  206. except TypeError:
  207. pass
  208. else:
  209. self.fail("Rat(%r) didn't raise TypeError" % bad)
  210. try:
  211. a = Rat(1, bad)
  212. except TypeError:
  213. pass
  214. else:
  215. self.fail("Rat(1, %r) didn't raise TypeError" % bad)
  216. def test_add(self):
  217. self.assertEqual(Rat(2, 3) + Rat(1, 3), 1)
  218. self.assertEqual(Rat(2, 3) + 1, Rat(5, 3))
  219. self.assertEqual(1 + Rat(2, 3), Rat(5, 3))
  220. self.assertEqual(1.0 + Rat(1, 2), 1.5)
  221. self.assertEqual(Rat(1, 2) + 1.0, 1.5)
  222. def test_sub(self):
  223. self.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10))
  224. self.assertEqual(Rat(7, 5) - 1, Rat(2, 5))
  225. self.assertEqual(1 - Rat(3, 5), Rat(2, 5))
  226. self.assertEqual(Rat(3, 2) - 1.0, 0.5)
  227. self.assertEqual(1.0 - Rat(1, 2), 0.5)
  228. def test_mul(self):
  229. self.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21))
  230. self.assertEqual(Rat(10, 3) * 3, 10)
  231. self.assertEqual(3 * Rat(10, 3), 10)
  232. self.assertEqual(Rat(10, 5) * 0.5, 1.0)
  233. self.assertEqual(0.5 * Rat(10, 5), 1.0)
  234. def test_div(self):
  235. self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
  236. self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
  237. self.assertEqual(2 / Rat(5), Rat(2, 5))
  238. self.assertEqual(3.0 * Rat(1, 2), 1.5)
  239. self.assertEqual(Rat(1, 2) * 3.0, 1.5)
  240. def test_floordiv(self):
  241. self.assertEqual(Rat(10) // Rat(4), 2)
  242. self.assertEqual(Rat(10, 3) // Rat(4, 3), 2)
  243. self.assertEqual(Rat(10) // 4, 2)
  244. self.assertEqual(10 // Rat(4), 2)
  245. def test_eq(self):
  246. self.assertEqual(Rat(10), Rat(20, 2))
  247. self.assertEqual(Rat(10), 10)
  248. self.assertEqual(10, Rat(10))
  249. self.assertEqual(Rat(10), 10.0)
  250. self.assertEqual(10.0, Rat(10))
  251. def test_true_div(self):
  252. self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
  253. self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
  254. self.assertEqual(2 / Rat(5), Rat(2, 5))
  255. self.assertEqual(3.0 * Rat(1, 2), 1.5)
  256. self.assertEqual(Rat(1, 2) * 3.0, 1.5)
  257. self.assertEqual(eval('1/2'), 0.5)
  258. # XXX Ran out of steam; TO DO: divmod, div, future division
  259. class OperationLogger:
  260. """Base class for classes with operation logging."""
  261. def __init__(self, logger):
  262. self.logger = logger
  263. def log_operation(self, *args):
  264. self.logger(*args)
  265. def op_sequence(op, *classes):
  266. """Return the sequence of operations that results from applying
  267. the operation `op` to instances of the given classes."""
  268. log = []
  269. instances = []
  270. for c in classes:
  271. instances.append(c(log.append))
  272. try:
  273. op(*instances)
  274. except TypeError:
  275. pass
  276. return log
  277. class A(OperationLogger):
  278. def __eq__(self, other):
  279. self.log_operation('A.__eq__')
  280. return NotImplemented
  281. def __le__(self, other):
  282. self.log_operation('A.__le__')
  283. return NotImplemented
  284. def __ge__(self, other):
  285. self.log_operation('A.__ge__')
  286. return NotImplemented
  287. class B(OperationLogger, metaclass=ABCMeta):
  288. def __eq__(self, other):
  289. self.log_operation('B.__eq__')
  290. return NotImplemented
  291. def __le__(self, other):
  292. self.log_operation('B.__le__')
  293. return NotImplemented
  294. def __ge__(self, other):
  295. self.log_operation('B.__ge__')
  296. return NotImplemented
  297. class C(B):
  298. def __eq__(self, other):
  299. self.log_operation('C.__eq__')
  300. return NotImplemented
  301. def __le__(self, other):
  302. self.log_operation('C.__le__')
  303. return NotImplemented
  304. def __ge__(self, other):
  305. self.log_operation('C.__ge__')
  306. return NotImplemented
  307. class V(OperationLogger):
  308. """Virtual subclass of B"""
  309. def __eq__(self, other):
  310. self.log_operation('V.__eq__')
  311. return NotImplemented
  312. def __le__(self, other):
  313. self.log_operation('V.__le__')
  314. return NotImplemented
  315. def __ge__(self, other):
  316. self.log_operation('V.__ge__')
  317. return NotImplemented
  318. B.register(V)
  319. class OperationOrderTests(unittest.TestCase):
  320. def test_comparison_orders(self):
  321. self.assertEqual(op_sequence(eq, A, A), ['A.__eq__', 'A.__eq__'])
  322. self.assertEqual(op_sequence(eq, A, B), ['A.__eq__', 'B.__eq__'])
  323. self.assertEqual(op_sequence(eq, B, A), ['B.__eq__', 'A.__eq__'])
  324. # C is a subclass of B, so C.__eq__ is called first
  325. self.assertEqual(op_sequence(eq, B, C), ['C.__eq__', 'B.__eq__'])
  326. self.assertEqual(op_sequence(eq, C, B), ['C.__eq__', 'B.__eq__'])
  327. self.assertEqual(op_sequence(le, A, A), ['A.__le__', 'A.__ge__'])
  328. self.assertEqual(op_sequence(le, A, B), ['A.__le__', 'B.__ge__'])
  329. self.assertEqual(op_sequence(le, B, A), ['B.__le__', 'A.__ge__'])
  330. self.assertEqual(op_sequence(le, B, C), ['C.__ge__', 'B.__le__'])
  331. self.assertEqual(op_sequence(le, C, B), ['C.__le__', 'B.__ge__'])
  332. self.assertTrue(issubclass(V, B))
  333. self.assertEqual(op_sequence(eq, B, V), ['B.__eq__', 'V.__eq__'])
  334. self.assertEqual(op_sequence(le, B, V), ['B.__le__', 'V.__ge__'])
  335. class SupEq(object):
  336. """Class that can test equality"""
  337. def __eq__(self, other):
  338. return True
  339. class S(SupEq):
  340. """Subclass of SupEq that should fail"""
  341. __eq__ = None
  342. class F(object):
  343. """Independent class that should fall back"""
  344. class X(object):
  345. """Independent class that should fail"""
  346. __eq__ = None
  347. class SN(SupEq):
  348. """Subclass of SupEq that can test equality, but not non-equality"""
  349. __ne__ = None
  350. class XN:
  351. """Independent class that can test equality, but not non-equality"""
  352. def __eq__(self, other):
  353. return True
  354. __ne__ = None
  355. class FallbackBlockingTests(unittest.TestCase):
  356. """Unit tests for None method blocking"""
  357. def test_fallback_rmethod_blocking(self):
  358. e, f, s, x = SupEq(), F(), S(), X()
  359. self.assertEqual(e, e)
  360. self.assertEqual(e, f)
  361. self.assertEqual(f, e)
  362. # left operand is checked first
  363. self.assertEqual(e, x)
  364. self.assertRaises(TypeError, eq, x, e)
  365. # S is a subclass, so it's always checked first
  366. self.assertRaises(TypeError, eq, e, s)
  367. self.assertRaises(TypeError, eq, s, e)
  368. def test_fallback_ne_blocking(self):
  369. e, sn, xn = SupEq(), SN(), XN()
  370. self.assertFalse(e != e)
  371. self.assertRaises(TypeError, ne, e, sn)
  372. self.assertRaises(TypeError, ne, sn, e)
  373. self.assertFalse(e != xn)
  374. self.assertRaises(TypeError, ne, xn, e)
  375. if __name__ == "__main__":
  376. unittest.main()