ยปCore Development>Code coverage>Lib/test/test_binop.py

Python code coverage for Lib/test/test_binop.py

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