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

Python code coverage for Lib/test/test_codeccallbacks.py

#countcontent
1n/aimport codecs
2n/aimport html.entities
3n/aimport sys
4n/aimport test.support
5n/aimport unicodedata
6n/aimport unittest
7n/a
8n/aclass PosReturn:
9n/a # this can be used for configurable callbacks
10n/a
11n/a def __init__(self):
12n/a self.pos = 0
13n/a
14n/a def handle(self, exc):
15n/a oldpos = self.pos
16n/a realpos = oldpos
17n/a if realpos<0:
18n/a realpos = len(exc.object) + realpos
19n/a # if we don't advance this time, terminate on the next call
20n/a # otherwise we'd get an endless loop
21n/a if realpos <= exc.start:
22n/a self.pos = len(exc.object)
23n/a return ("<?>", oldpos)
24n/a
25n/a# A UnicodeEncodeError object with a bad start attribute
26n/aclass BadStartUnicodeEncodeError(UnicodeEncodeError):
27n/a def __init__(self):
28n/a UnicodeEncodeError.__init__(self, "ascii", "", 0, 1, "bad")
29n/a self.start = []
30n/a
31n/a# A UnicodeEncodeError object with a bad object attribute
32n/aclass BadObjectUnicodeEncodeError(UnicodeEncodeError):
33n/a def __init__(self):
34n/a UnicodeEncodeError.__init__(self, "ascii", "", 0, 1, "bad")
35n/a self.object = []
36n/a
37n/a# A UnicodeDecodeError object without an end attribute
38n/aclass NoEndUnicodeDecodeError(UnicodeDecodeError):
39n/a def __init__(self):
40n/a UnicodeDecodeError.__init__(self, "ascii", bytearray(b""), 0, 1, "bad")
41n/a del self.end
42n/a
43n/a# A UnicodeDecodeError object with a bad object attribute
44n/aclass BadObjectUnicodeDecodeError(UnicodeDecodeError):
45n/a def __init__(self):
46n/a UnicodeDecodeError.__init__(self, "ascii", bytearray(b""), 0, 1, "bad")
47n/a self.object = []
48n/a
49n/a# A UnicodeTranslateError object without a start attribute
50n/aclass NoStartUnicodeTranslateError(UnicodeTranslateError):
51n/a def __init__(self):
52n/a UnicodeTranslateError.__init__(self, "", 0, 1, "bad")
53n/a del self.start
54n/a
55n/a# A UnicodeTranslateError object without an end attribute
56n/aclass NoEndUnicodeTranslateError(UnicodeTranslateError):
57n/a def __init__(self):
58n/a UnicodeTranslateError.__init__(self, "", 0, 1, "bad")
59n/a del self.end
60n/a
61n/a# A UnicodeTranslateError object without an object attribute
62n/aclass NoObjectUnicodeTranslateError(UnicodeTranslateError):
63n/a def __init__(self):
64n/a UnicodeTranslateError.__init__(self, "", 0, 1, "bad")
65n/a del self.object
66n/a
67n/aclass CodecCallbackTest(unittest.TestCase):
68n/a
69n/a def test_xmlcharrefreplace(self):
70n/a # replace unencodable characters which numeric character entities.
71n/a # For ascii, latin-1 and charmaps this is completely implemented
72n/a # in C and should be reasonably fast.
73n/a s = "\u30b9\u30d1\u30e2 \xe4nd eggs"
74n/a self.assertEqual(
75n/a s.encode("ascii", "xmlcharrefreplace"),
76n/a b"&#12473;&#12497;&#12514; &#228;nd eggs"
77n/a )
78n/a self.assertEqual(
79n/a s.encode("latin-1", "xmlcharrefreplace"),
80n/a b"&#12473;&#12497;&#12514; \xe4nd eggs"
81n/a )
82n/a
83n/a def test_xmlcharnamereplace(self):
84n/a # This time use a named character entity for unencodable
85n/a # characters, if one is available.
86n/a
87n/a def xmlcharnamereplace(exc):
88n/a if not isinstance(exc, UnicodeEncodeError):
89n/a raise TypeError("don't know how to handle %r" % exc)
90n/a l = []
91n/a for c in exc.object[exc.start:exc.end]:
92n/a try:
93n/a l.append("&%s;" % html.entities.codepoint2name[ord(c)])
94n/a except KeyError:
95n/a l.append("&#%d;" % ord(c))
96n/a return ("".join(l), exc.end)
97n/a
98n/a codecs.register_error(
99n/a "test.xmlcharnamereplace", xmlcharnamereplace)
100n/a
101n/a sin = "\xab\u211c\xbb = \u2329\u1234\u20ac\u232a"
102n/a sout = b"&laquo;&real;&raquo; = &lang;&#4660;&euro;&rang;"
103n/a self.assertEqual(sin.encode("ascii", "test.xmlcharnamereplace"), sout)
104n/a sout = b"\xab&real;\xbb = &lang;&#4660;&euro;&rang;"
105n/a self.assertEqual(sin.encode("latin-1", "test.xmlcharnamereplace"), sout)
106n/a sout = b"\xab&real;\xbb = &lang;&#4660;\xa4&rang;"
107n/a self.assertEqual(sin.encode("iso-8859-15", "test.xmlcharnamereplace"), sout)
108n/a
109n/a def test_uninamereplace(self):
110n/a # We're using the names from the unicode database this time,
111n/a # and we're doing "syntax highlighting" here, i.e. we include
112n/a # the replaced text in ANSI escape sequences. For this it is
113n/a # useful that the error handler is not called for every single
114n/a # unencodable character, but for a complete sequence of
115n/a # unencodable characters, otherwise we would output many
116n/a # unnecessary escape sequences.
117n/a
118n/a def uninamereplace(exc):
119n/a if not isinstance(exc, UnicodeEncodeError):
120n/a raise TypeError("don't know how to handle %r" % exc)
121n/a l = []
122n/a for c in exc.object[exc.start:exc.end]:
123n/a l.append(unicodedata.name(c, "0x%x" % ord(c)))
124n/a return ("\033[1m%s\033[0m" % ", ".join(l), exc.end)
125n/a
126n/a codecs.register_error(
127n/a "test.uninamereplace", uninamereplace)
128n/a
129n/a sin = "\xac\u1234\u20ac\u8000"
130n/a sout = b"\033[1mNOT SIGN, ETHIOPIC SYLLABLE SEE, EURO SIGN, CJK UNIFIED IDEOGRAPH-8000\033[0m"
131n/a self.assertEqual(sin.encode("ascii", "test.uninamereplace"), sout)
132n/a
133n/a sout = b"\xac\033[1mETHIOPIC SYLLABLE SEE, EURO SIGN, CJK UNIFIED IDEOGRAPH-8000\033[0m"
134n/a self.assertEqual(sin.encode("latin-1", "test.uninamereplace"), sout)
135n/a
136n/a sout = b"\xac\033[1mETHIOPIC SYLLABLE SEE\033[0m\xa4\033[1mCJK UNIFIED IDEOGRAPH-8000\033[0m"
137n/a self.assertEqual(sin.encode("iso-8859-15", "test.uninamereplace"), sout)
138n/a
139n/a def test_backslashescape(self):
140n/a # Does the same as the "unicode-escape" encoding, but with different
141n/a # base encodings.
142n/a sin = "a\xac\u1234\u20ac\u8000\U0010ffff"
143n/a sout = b"a\\xac\\u1234\\u20ac\\u8000\\U0010ffff"
144n/a self.assertEqual(sin.encode("ascii", "backslashreplace"), sout)
145n/a
146n/a sout = b"a\xac\\u1234\\u20ac\\u8000\\U0010ffff"
147n/a self.assertEqual(sin.encode("latin-1", "backslashreplace"), sout)
148n/a
149n/a sout = b"a\xac\\u1234\xa4\\u8000\\U0010ffff"
150n/a self.assertEqual(sin.encode("iso-8859-15", "backslashreplace"), sout)
151n/a
152n/a def test_nameescape(self):
153n/a # Does the same as backslashescape, but prefers ``\N{...}`` escape
154n/a # sequences.
155n/a sin = "a\xac\u1234\u20ac\u8000\U0010ffff"
156n/a sout = (b'a\\N{NOT SIGN}\\N{ETHIOPIC SYLLABLE SEE}\\N{EURO SIGN}'
157n/a b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff')
158n/a self.assertEqual(sin.encode("ascii", "namereplace"), sout)
159n/a
160n/a sout = (b'a\xac\\N{ETHIOPIC SYLLABLE SEE}\\N{EURO SIGN}'
161n/a b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff')
162n/a self.assertEqual(sin.encode("latin-1", "namereplace"), sout)
163n/a
164n/a sout = (b'a\xac\\N{ETHIOPIC SYLLABLE SEE}\xa4'
165n/a b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff')
166n/a self.assertEqual(sin.encode("iso-8859-15", "namereplace"), sout)
167n/a
168n/a def test_decoding_callbacks(self):
169n/a # This is a test for a decoding callback handler
170n/a # that allows the decoding of the invalid sequence
171n/a # "\xc0\x80" and returns "\x00" instead of raising an error.
172n/a # All other illegal sequences will be handled strictly.
173n/a def relaxedutf8(exc):
174n/a if not isinstance(exc, UnicodeDecodeError):
175n/a raise TypeError("don't know how to handle %r" % exc)
176n/a if exc.object[exc.start:exc.start+2] == b"\xc0\x80":
177n/a return ("\x00", exc.start+2) # retry after two bytes
178n/a else:
179n/a raise exc
180n/a
181n/a codecs.register_error("test.relaxedutf8", relaxedutf8)
182n/a
183n/a # all the "\xc0\x80" will be decoded to "\x00"
184n/a sin = b"a\x00b\xc0\x80c\xc3\xbc\xc0\x80\xc0\x80"
185n/a sout = "a\x00b\x00c\xfc\x00\x00"
186n/a self.assertEqual(sin.decode("utf-8", "test.relaxedutf8"), sout)
187n/a
188n/a # "\xc0\x81" is not valid and a UnicodeDecodeError will be raised
189n/a sin = b"\xc0\x80\xc0\x81"
190n/a self.assertRaises(UnicodeDecodeError, sin.decode,
191n/a "utf-8", "test.relaxedutf8")
192n/a
193n/a def test_charmapencode(self):
194n/a # For charmap encodings the replacement string will be
195n/a # mapped through the encoding again. This means, that
196n/a # to be able to use e.g. the "replace" handler, the
197n/a # charmap has to have a mapping for "?".
198n/a charmap = dict((ord(c), bytes(2*c.upper(), 'ascii')) for c in "abcdefgh")
199n/a sin = "abc"
200n/a sout = b"AABBCC"
201n/a self.assertEqual(codecs.charmap_encode(sin, "strict", charmap)[0], sout)
202n/a
203n/a sin = "abcA"
204n/a self.assertRaises(UnicodeError, codecs.charmap_encode, sin, "strict", charmap)
205n/a
206n/a charmap[ord("?")] = b"XYZ"
207n/a sin = "abcDEF"
208n/a sout = b"AABBCCXYZXYZXYZ"
209n/a self.assertEqual(codecs.charmap_encode(sin, "replace", charmap)[0], sout)
210n/a
211n/a charmap[ord("?")] = "XYZ" # wrong type in mapping
212n/a self.assertRaises(TypeError, codecs.charmap_encode, sin, "replace", charmap)
213n/a
214n/a def test_decodeunicodeinternal(self):
215n/a with test.support.check_warnings(('unicode_internal codec has been '
216n/a 'deprecated', DeprecationWarning)):
217n/a self.assertRaises(
218n/a UnicodeDecodeError,
219n/a b"\x00\x00\x00\x00\x00".decode,
220n/a "unicode-internal",
221n/a )
222n/a if len('\0'.encode('unicode-internal')) == 4:
223n/a def handler_unicodeinternal(exc):
224n/a if not isinstance(exc, UnicodeDecodeError):
225n/a raise TypeError("don't know how to handle %r" % exc)
226n/a return ("\x01", 1)
227n/a
228n/a self.assertEqual(
229n/a b"\x00\x00\x00\x00\x00".decode("unicode-internal", "ignore"),
230n/a "\u0000"
231n/a )
232n/a
233n/a self.assertEqual(
234n/a b"\x00\x00\x00\x00\x00".decode("unicode-internal", "replace"),
235n/a "\u0000\ufffd"
236n/a )
237n/a
238n/a self.assertEqual(
239n/a b"\x00\x00\x00\x00\x00".decode("unicode-internal", "backslashreplace"),
240n/a "\u0000\\x00"
241n/a )
242n/a
243n/a codecs.register_error("test.hui", handler_unicodeinternal)
244n/a
245n/a self.assertEqual(
246n/a b"\x00\x00\x00\x00\x00".decode("unicode-internal", "test.hui"),
247n/a "\u0000\u0001\u0000"
248n/a )
249n/a
250n/a def test_callbacks(self):
251n/a def handler1(exc):
252n/a r = range(exc.start, exc.end)
253n/a if isinstance(exc, UnicodeEncodeError):
254n/a l = ["<%d>" % ord(exc.object[pos]) for pos in r]
255n/a elif isinstance(exc, UnicodeDecodeError):
256n/a l = ["<%d>" % exc.object[pos] for pos in r]
257n/a else:
258n/a raise TypeError("don't know how to handle %r" % exc)
259n/a return ("[%s]" % "".join(l), exc.end)
260n/a
261n/a codecs.register_error("test.handler1", handler1)
262n/a
263n/a def handler2(exc):
264n/a if not isinstance(exc, UnicodeDecodeError):
265n/a raise TypeError("don't know how to handle %r" % exc)
266n/a l = ["<%d>" % exc.object[pos] for pos in range(exc.start, exc.end)]
267n/a return ("[%s]" % "".join(l), exc.end+1) # skip one character
268n/a
269n/a codecs.register_error("test.handler2", handler2)
270n/a
271n/a s = b"\x00\x81\x7f\x80\xff"
272n/a
273n/a self.assertEqual(
274n/a s.decode("ascii", "test.handler1"),
275n/a "\x00[<129>]\x7f[<128>][<255>]"
276n/a )
277n/a self.assertEqual(
278n/a s.decode("ascii", "test.handler2"),
279n/a "\x00[<129>][<128>]"
280n/a )
281n/a
282n/a self.assertEqual(
283n/a b"\\u3042\\u3xxx".decode("unicode-escape", "test.handler1"),
284n/a "\u3042[<92><117><51>]xxx"
285n/a )
286n/a
287n/a self.assertEqual(
288n/a b"\\u3042\\u3xx".decode("unicode-escape", "test.handler1"),
289n/a "\u3042[<92><117><51>]xx"
290n/a )
291n/a
292n/a self.assertEqual(
293n/a codecs.charmap_decode(b"abc", "test.handler1", {ord("a"): "z"})[0],
294n/a "z[<98>][<99>]"
295n/a )
296n/a
297n/a self.assertEqual(
298n/a "g\xfc\xdfrk".encode("ascii", "test.handler1"),
299n/a b"g[<252><223>]rk"
300n/a )
301n/a
302n/a self.assertEqual(
303n/a "g\xfc\xdf".encode("ascii", "test.handler1"),
304n/a b"g[<252><223>]"
305n/a )
306n/a
307n/a def test_longstrings(self):
308n/a # test long strings to check for memory overflow problems
309n/a errors = [ "strict", "ignore", "replace", "xmlcharrefreplace",
310n/a "backslashreplace", "namereplace"]
311n/a # register the handlers under different names,
312n/a # to prevent the codec from recognizing the name
313n/a for err in errors:
314n/a codecs.register_error("test." + err, codecs.lookup_error(err))
315n/a l = 1000
316n/a errors += [ "test." + err for err in errors ]
317n/a for uni in [ s*l for s in ("x", "\u3042", "a\xe4") ]:
318n/a for enc in ("ascii", "latin-1", "iso-8859-1", "iso-8859-15",
319n/a "utf-8", "utf-7", "utf-16", "utf-32"):
320n/a for err in errors:
321n/a try:
322n/a uni.encode(enc, err)
323n/a except UnicodeError:
324n/a pass
325n/a
326n/a def check_exceptionobjectargs(self, exctype, args, msg):
327n/a # Test UnicodeError subclasses: construction, attribute assignment and __str__ conversion
328n/a # check with one missing argument
329n/a self.assertRaises(TypeError, exctype, *args[:-1])
330n/a # check with one argument too much
331n/a self.assertRaises(TypeError, exctype, *(args + ["too much"]))
332n/a # check with one argument of the wrong type
333n/a wrongargs = [ "spam", b"eggs", b"spam", 42, 1.0, None ]
334n/a for i in range(len(args)):
335n/a for wrongarg in wrongargs:
336n/a if type(wrongarg) is type(args[i]):
337n/a continue
338n/a # build argument array
339n/a callargs = []
340n/a for j in range(len(args)):
341n/a if i==j:
342n/a callargs.append(wrongarg)
343n/a else:
344n/a callargs.append(args[i])
345n/a self.assertRaises(TypeError, exctype, *callargs)
346n/a
347n/a # check with the correct number and type of arguments
348n/a exc = exctype(*args)
349n/a self.assertEqual(str(exc), msg)
350n/a
351n/a def test_unicodeencodeerror(self):
352n/a self.check_exceptionobjectargs(
353n/a UnicodeEncodeError,
354n/a ["ascii", "g\xfcrk", 1, 2, "ouch"],
355n/a "'ascii' codec can't encode character '\\xfc' in position 1: ouch"
356n/a )
357n/a self.check_exceptionobjectargs(
358n/a UnicodeEncodeError,
359n/a ["ascii", "g\xfcrk", 1, 4, "ouch"],
360n/a "'ascii' codec can't encode characters in position 1-3: ouch"
361n/a )
362n/a self.check_exceptionobjectargs(
363n/a UnicodeEncodeError,
364n/a ["ascii", "\xfcx", 0, 1, "ouch"],
365n/a "'ascii' codec can't encode character '\\xfc' in position 0: ouch"
366n/a )
367n/a self.check_exceptionobjectargs(
368n/a UnicodeEncodeError,
369n/a ["ascii", "\u0100x", 0, 1, "ouch"],
370n/a "'ascii' codec can't encode character '\\u0100' in position 0: ouch"
371n/a )
372n/a self.check_exceptionobjectargs(
373n/a UnicodeEncodeError,
374n/a ["ascii", "\uffffx", 0, 1, "ouch"],
375n/a "'ascii' codec can't encode character '\\uffff' in position 0: ouch"
376n/a )
377n/a self.check_exceptionobjectargs(
378n/a UnicodeEncodeError,
379n/a ["ascii", "\U00010000x", 0, 1, "ouch"],
380n/a "'ascii' codec can't encode character '\\U00010000' in position 0: ouch"
381n/a )
382n/a
383n/a def test_unicodedecodeerror(self):
384n/a self.check_exceptionobjectargs(
385n/a UnicodeDecodeError,
386n/a ["ascii", bytearray(b"g\xfcrk"), 1, 2, "ouch"],
387n/a "'ascii' codec can't decode byte 0xfc in position 1: ouch"
388n/a )
389n/a self.check_exceptionobjectargs(
390n/a UnicodeDecodeError,
391n/a ["ascii", bytearray(b"g\xfcrk"), 1, 3, "ouch"],
392n/a "'ascii' codec can't decode bytes in position 1-2: ouch"
393n/a )
394n/a
395n/a def test_unicodetranslateerror(self):
396n/a self.check_exceptionobjectargs(
397n/a UnicodeTranslateError,
398n/a ["g\xfcrk", 1, 2, "ouch"],
399n/a "can't translate character '\\xfc' in position 1: ouch"
400n/a )
401n/a self.check_exceptionobjectargs(
402n/a UnicodeTranslateError,
403n/a ["g\u0100rk", 1, 2, "ouch"],
404n/a "can't translate character '\\u0100' in position 1: ouch"
405n/a )
406n/a self.check_exceptionobjectargs(
407n/a UnicodeTranslateError,
408n/a ["g\uffffrk", 1, 2, "ouch"],
409n/a "can't translate character '\\uffff' in position 1: ouch"
410n/a )
411n/a self.check_exceptionobjectargs(
412n/a UnicodeTranslateError,
413n/a ["g\U00010000rk", 1, 2, "ouch"],
414n/a "can't translate character '\\U00010000' in position 1: ouch"
415n/a )
416n/a self.check_exceptionobjectargs(
417n/a UnicodeTranslateError,
418n/a ["g\xfcrk", 1, 3, "ouch"],
419n/a "can't translate characters in position 1-2: ouch"
420n/a )
421n/a
422n/a def test_badandgoodstrictexceptions(self):
423n/a # "strict" complains about a non-exception passed in
424n/a self.assertRaises(
425n/a TypeError,
426n/a codecs.strict_errors,
427n/a 42
428n/a )
429n/a # "strict" complains about the wrong exception type
430n/a self.assertRaises(
431n/a Exception,
432n/a codecs.strict_errors,
433n/a Exception("ouch")
434n/a )
435n/a
436n/a # If the correct exception is passed in, "strict" raises it
437n/a self.assertRaises(
438n/a UnicodeEncodeError,
439n/a codecs.strict_errors,
440n/a UnicodeEncodeError("ascii", "\u3042", 0, 1, "ouch")
441n/a )
442n/a self.assertRaises(
443n/a UnicodeDecodeError,
444n/a codecs.strict_errors,
445n/a UnicodeDecodeError("ascii", bytearray(b"\xff"), 0, 1, "ouch")
446n/a )
447n/a self.assertRaises(
448n/a UnicodeTranslateError,
449n/a codecs.strict_errors,
450n/a UnicodeTranslateError("\u3042", 0, 1, "ouch")
451n/a )
452n/a
453n/a def test_badandgoodignoreexceptions(self):
454n/a # "ignore" complains about a non-exception passed in
455n/a self.assertRaises(
456n/a TypeError,
457n/a codecs.ignore_errors,
458n/a 42
459n/a )
460n/a # "ignore" complains about the wrong exception type
461n/a self.assertRaises(
462n/a TypeError,
463n/a codecs.ignore_errors,
464n/a UnicodeError("ouch")
465n/a )
466n/a # If the correct exception is passed in, "ignore" returns an empty replacement
467n/a self.assertEqual(
468n/a codecs.ignore_errors(
469n/a UnicodeEncodeError("ascii", "a\u3042b", 1, 2, "ouch")),
470n/a ("", 2)
471n/a )
472n/a self.assertEqual(
473n/a codecs.ignore_errors(
474n/a UnicodeDecodeError("ascii", bytearray(b"a\xffb"), 1, 2, "ouch")),
475n/a ("", 2)
476n/a )
477n/a self.assertEqual(
478n/a codecs.ignore_errors(
479n/a UnicodeTranslateError("a\u3042b", 1, 2, "ouch")),
480n/a ("", 2)
481n/a )
482n/a
483n/a def test_badandgoodreplaceexceptions(self):
484n/a # "replace" complains about a non-exception passed in
485n/a self.assertRaises(
486n/a TypeError,
487n/a codecs.replace_errors,
488n/a 42
489n/a )
490n/a # "replace" complains about the wrong exception type
491n/a self.assertRaises(
492n/a TypeError,
493n/a codecs.replace_errors,
494n/a UnicodeError("ouch")
495n/a )
496n/a self.assertRaises(
497n/a TypeError,
498n/a codecs.replace_errors,
499n/a BadObjectUnicodeEncodeError()
500n/a )
501n/a self.assertRaises(
502n/a TypeError,
503n/a codecs.replace_errors,
504n/a BadObjectUnicodeDecodeError()
505n/a )
506n/a # With the correct exception, "replace" returns an "?" or "\ufffd" replacement
507n/a self.assertEqual(
508n/a codecs.replace_errors(
509n/a UnicodeEncodeError("ascii", "a\u3042b", 1, 2, "ouch")),
510n/a ("?", 2)
511n/a )
512n/a self.assertEqual(
513n/a codecs.replace_errors(
514n/a UnicodeDecodeError("ascii", bytearray(b"a\xffb"), 1, 2, "ouch")),
515n/a ("\ufffd", 2)
516n/a )
517n/a self.assertEqual(
518n/a codecs.replace_errors(
519n/a UnicodeTranslateError("a\u3042b", 1, 2, "ouch")),
520n/a ("\ufffd", 2)
521n/a )
522n/a
523n/a def test_badandgoodxmlcharrefreplaceexceptions(self):
524n/a # "xmlcharrefreplace" complains about a non-exception passed in
525n/a self.assertRaises(
526n/a TypeError,
527n/a codecs.xmlcharrefreplace_errors,
528n/a 42
529n/a )
530n/a # "xmlcharrefreplace" complains about the wrong exception types
531n/a self.assertRaises(
532n/a TypeError,
533n/a codecs.xmlcharrefreplace_errors,
534n/a UnicodeError("ouch")
535n/a )
536n/a # "xmlcharrefreplace" can only be used for encoding
537n/a self.assertRaises(
538n/a TypeError,
539n/a codecs.xmlcharrefreplace_errors,
540n/a UnicodeDecodeError("ascii", bytearray(b"\xff"), 0, 1, "ouch")
541n/a )
542n/a self.assertRaises(
543n/a TypeError,
544n/a codecs.xmlcharrefreplace_errors,
545n/a UnicodeTranslateError("\u3042", 0, 1, "ouch")
546n/a )
547n/a # Use the correct exception
548n/a cs = (0, 1, 9, 10, 99, 100, 999, 1000, 9999, 10000, 99999, 100000,
549n/a 999999, 1000000)
550n/a cs += (0xd800, 0xdfff)
551n/a s = "".join(chr(c) for c in cs)
552n/a self.assertEqual(
553n/a codecs.xmlcharrefreplace_errors(
554n/a UnicodeEncodeError("ascii", "a" + s + "b",
555n/a 1, 1 + len(s), "ouch")
556n/a ),
557n/a ("".join("&#%d;" % c for c in cs), 1 + len(s))
558n/a )
559n/a
560n/a def test_badandgoodbackslashreplaceexceptions(self):
561n/a # "backslashreplace" complains about a non-exception passed in
562n/a self.assertRaises(
563n/a TypeError,
564n/a codecs.backslashreplace_errors,
565n/a 42
566n/a )
567n/a # "backslashreplace" complains about the wrong exception types
568n/a self.assertRaises(
569n/a TypeError,
570n/a codecs.backslashreplace_errors,
571n/a UnicodeError("ouch")
572n/a )
573n/a # Use the correct exception
574n/a tests = [
575n/a ("\u3042", "\\u3042"),
576n/a ("\n", "\\x0a"),
577n/a ("a", "\\x61"),
578n/a ("\x00", "\\x00"),
579n/a ("\xff", "\\xff"),
580n/a ("\u0100", "\\u0100"),
581n/a ("\uffff", "\\uffff"),
582n/a ("\U00010000", "\\U00010000"),
583n/a ("\U0010ffff", "\\U0010ffff"),
584n/a # Lone surrogates
585n/a ("\ud800", "\\ud800"),
586n/a ("\udfff", "\\udfff"),
587n/a ("\ud800\udfff", "\\ud800\\udfff"),
588n/a ]
589n/a for s, r in tests:
590n/a with self.subTest(str=s):
591n/a self.assertEqual(
592n/a codecs.backslashreplace_errors(
593n/a UnicodeEncodeError("ascii", "a" + s + "b",
594n/a 1, 1 + len(s), "ouch")),
595n/a (r, 1 + len(s))
596n/a )
597n/a self.assertEqual(
598n/a codecs.backslashreplace_errors(
599n/a UnicodeTranslateError("a" + s + "b",
600n/a 1, 1 + len(s), "ouch")),
601n/a (r, 1 + len(s))
602n/a )
603n/a tests = [
604n/a (b"a", "\\x61"),
605n/a (b"\n", "\\x0a"),
606n/a (b"\x00", "\\x00"),
607n/a (b"\xff", "\\xff"),
608n/a ]
609n/a for b, r in tests:
610n/a with self.subTest(bytes=b):
611n/a self.assertEqual(
612n/a codecs.backslashreplace_errors(
613n/a UnicodeDecodeError("ascii", bytearray(b"a" + b + b"b"),
614n/a 1, 2, "ouch")),
615n/a (r, 2)
616n/a )
617n/a
618n/a def test_badandgoodnamereplaceexceptions(self):
619n/a # "namereplace" complains about a non-exception passed in
620n/a self.assertRaises(
621n/a TypeError,
622n/a codecs.namereplace_errors,
623n/a 42
624n/a )
625n/a # "namereplace" complains about the wrong exception types
626n/a self.assertRaises(
627n/a TypeError,
628n/a codecs.namereplace_errors,
629n/a UnicodeError("ouch")
630n/a )
631n/a # "namereplace" can only be used for encoding
632n/a self.assertRaises(
633n/a TypeError,
634n/a codecs.namereplace_errors,
635n/a UnicodeDecodeError("ascii", bytearray(b"\xff"), 0, 1, "ouch")
636n/a )
637n/a self.assertRaises(
638n/a TypeError,
639n/a codecs.namereplace_errors,
640n/a UnicodeTranslateError("\u3042", 0, 1, "ouch")
641n/a )
642n/a # Use the correct exception
643n/a tests = [
644n/a ("\u3042", "\\N{HIRAGANA LETTER A}"),
645n/a ("\x00", "\\x00"),
646n/a ("\ufbf9", "\\N{ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH "
647n/a "HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM}"),
648n/a ("\U000e007f", "\\N{CANCEL TAG}"),
649n/a ("\U0010ffff", "\\U0010ffff"),
650n/a # Lone surrogates
651n/a ("\ud800", "\\ud800"),
652n/a ("\udfff", "\\udfff"),
653n/a ("\ud800\udfff", "\\ud800\\udfff"),
654n/a ]
655n/a for s, r in tests:
656n/a with self.subTest(str=s):
657n/a self.assertEqual(
658n/a codecs.namereplace_errors(
659n/a UnicodeEncodeError("ascii", "a" + s + "b",
660n/a 1, 1 + len(s), "ouch")),
661n/a (r, 1 + len(s))
662n/a )
663n/a
664n/a def test_badandgoodsurrogateescapeexceptions(self):
665n/a surrogateescape_errors = codecs.lookup_error('surrogateescape')
666n/a # "surrogateescape" complains about a non-exception passed in
667n/a self.assertRaises(
668n/a TypeError,
669n/a surrogateescape_errors,
670n/a 42
671n/a )
672n/a # "surrogateescape" complains about the wrong exception types
673n/a self.assertRaises(
674n/a TypeError,
675n/a surrogateescape_errors,
676n/a UnicodeError("ouch")
677n/a )
678n/a # "surrogateescape" can not be used for translating
679n/a self.assertRaises(
680n/a TypeError,
681n/a surrogateescape_errors,
682n/a UnicodeTranslateError("\udc80", 0, 1, "ouch")
683n/a )
684n/a # Use the correct exception
685n/a for s in ("a", "\udc7f", "\udd00"):
686n/a with self.subTest(str=s):
687n/a self.assertRaises(
688n/a UnicodeEncodeError,
689n/a surrogateescape_errors,
690n/a UnicodeEncodeError("ascii", s, 0, 1, "ouch")
691n/a )
692n/a self.assertEqual(
693n/a surrogateescape_errors(
694n/a UnicodeEncodeError("ascii", "a\udc80b", 1, 2, "ouch")),
695n/a (b"\x80", 2)
696n/a )
697n/a self.assertRaises(
698n/a UnicodeDecodeError,
699n/a surrogateescape_errors,
700n/a UnicodeDecodeError("ascii", bytearray(b"a"), 0, 1, "ouch")
701n/a )
702n/a self.assertEqual(
703n/a surrogateescape_errors(
704n/a UnicodeDecodeError("ascii", bytearray(b"a\x80b"), 1, 2, "ouch")),
705n/a ("\udc80", 2)
706n/a )
707n/a
708n/a def test_badandgoodsurrogatepassexceptions(self):
709n/a surrogatepass_errors = codecs.lookup_error('surrogatepass')
710n/a # "surrogatepass" complains about a non-exception passed in
711n/a self.assertRaises(
712n/a TypeError,
713n/a surrogatepass_errors,
714n/a 42
715n/a )
716n/a # "surrogatepass" complains about the wrong exception types
717n/a self.assertRaises(
718n/a TypeError,
719n/a surrogatepass_errors,
720n/a UnicodeError("ouch")
721n/a )
722n/a # "surrogatepass" can not be used for translating
723n/a self.assertRaises(
724n/a TypeError,
725n/a surrogatepass_errors,
726n/a UnicodeTranslateError("\ud800", 0, 1, "ouch")
727n/a )
728n/a # Use the correct exception
729n/a for enc in ("utf-8", "utf-16le", "utf-16be", "utf-32le", "utf-32be"):
730n/a with self.subTest(encoding=enc):
731n/a self.assertRaises(
732n/a UnicodeEncodeError,
733n/a surrogatepass_errors,
734n/a UnicodeEncodeError(enc, "a", 0, 1, "ouch")
735n/a )
736n/a self.assertRaises(
737n/a UnicodeDecodeError,
738n/a surrogatepass_errors,
739n/a UnicodeDecodeError(enc, "a".encode(enc), 0, 1, "ouch")
740n/a )
741n/a for s in ("\ud800", "\udfff", "\ud800\udfff"):
742n/a with self.subTest(str=s):
743n/a self.assertRaises(
744n/a UnicodeEncodeError,
745n/a surrogatepass_errors,
746n/a UnicodeEncodeError("ascii", s, 0, len(s), "ouch")
747n/a )
748n/a tests = [
749n/a ("utf-8", "\ud800", b'\xed\xa0\x80', 3),
750n/a ("utf-16le", "\ud800", b'\x00\xd8', 2),
751n/a ("utf-16be", "\ud800", b'\xd8\x00', 2),
752n/a ("utf-32le", "\ud800", b'\x00\xd8\x00\x00', 4),
753n/a ("utf-32be", "\ud800", b'\x00\x00\xd8\x00', 4),
754n/a ("utf-8", "\udfff", b'\xed\xbf\xbf', 3),
755n/a ("utf-16le", "\udfff", b'\xff\xdf', 2),
756n/a ("utf-16be", "\udfff", b'\xdf\xff', 2),
757n/a ("utf-32le", "\udfff", b'\xff\xdf\x00\x00', 4),
758n/a ("utf-32be", "\udfff", b'\x00\x00\xdf\xff', 4),
759n/a ("utf-8", "\ud800\udfff", b'\xed\xa0\x80\xed\xbf\xbf', 3),
760n/a ("utf-16le", "\ud800\udfff", b'\x00\xd8\xff\xdf', 2),
761n/a ("utf-16be", "\ud800\udfff", b'\xd8\x00\xdf\xff', 2),
762n/a ("utf-32le", "\ud800\udfff", b'\x00\xd8\x00\x00\xff\xdf\x00\x00', 4),
763n/a ("utf-32be", "\ud800\udfff", b'\x00\x00\xd8\x00\x00\x00\xdf\xff', 4),
764n/a ]
765n/a for enc, s, b, n in tests:
766n/a with self.subTest(encoding=enc, str=s, bytes=b):
767n/a self.assertEqual(
768n/a surrogatepass_errors(
769n/a UnicodeEncodeError(enc, "a" + s + "b",
770n/a 1, 1 + len(s), "ouch")),
771n/a (b, 1 + len(s))
772n/a )
773n/a self.assertEqual(
774n/a surrogatepass_errors(
775n/a UnicodeDecodeError(enc, bytearray(b"a" + b[:n] + b"b"),
776n/a 1, 1 + n, "ouch")),
777n/a (s[:1], 1 + n)
778n/a )
779n/a
780n/a def test_badhandlerresults(self):
781n/a results = ( 42, "foo", (1,2,3), ("foo", 1, 3), ("foo", None), ("foo",), ("foo", 1, 3), ("foo", None), ("foo",) )
782n/a encs = ("ascii", "latin-1", "iso-8859-1", "iso-8859-15")
783n/a
784n/a for res in results:
785n/a codecs.register_error("test.badhandler", lambda x: res)
786n/a for enc in encs:
787n/a self.assertRaises(
788n/a TypeError,
789n/a "\u3042".encode,
790n/a enc,
791n/a "test.badhandler"
792n/a )
793n/a for (enc, bytes) in (
794n/a ("ascii", b"\xff"),
795n/a ("utf-8", b"\xff"),
796n/a ("utf-7", b"+x-"),
797n/a ("unicode-internal", b"\x00"),
798n/a ):
799n/a with test.support.check_warnings():
800n/a # unicode-internal has been deprecated
801n/a self.assertRaises(
802n/a TypeError,
803n/a bytes.decode,
804n/a enc,
805n/a "test.badhandler"
806n/a )
807n/a
808n/a def test_lookup(self):
809n/a self.assertEqual(codecs.strict_errors, codecs.lookup_error("strict"))
810n/a self.assertEqual(codecs.ignore_errors, codecs.lookup_error("ignore"))
811n/a self.assertEqual(codecs.strict_errors, codecs.lookup_error("strict"))
812n/a self.assertEqual(
813n/a codecs.xmlcharrefreplace_errors,
814n/a codecs.lookup_error("xmlcharrefreplace")
815n/a )
816n/a self.assertEqual(
817n/a codecs.backslashreplace_errors,
818n/a codecs.lookup_error("backslashreplace")
819n/a )
820n/a self.assertEqual(
821n/a codecs.namereplace_errors,
822n/a codecs.lookup_error("namereplace")
823n/a )
824n/a
825n/a def test_unencodablereplacement(self):
826n/a def unencrepl(exc):
827n/a if isinstance(exc, UnicodeEncodeError):
828n/a return ("\u4242", exc.end)
829n/a else:
830n/a raise TypeError("don't know how to handle %r" % exc)
831n/a codecs.register_error("test.unencreplhandler", unencrepl)
832n/a for enc in ("ascii", "iso-8859-1", "iso-8859-15"):
833n/a self.assertRaises(
834n/a UnicodeEncodeError,
835n/a "\u4242".encode,
836n/a enc,
837n/a "test.unencreplhandler"
838n/a )
839n/a
840n/a def test_badregistercall(self):
841n/a # enhance coverage of:
842n/a # Modules/_codecsmodule.c::register_error()
843n/a # Python/codecs.c::PyCodec_RegisterError()
844n/a self.assertRaises(TypeError, codecs.register_error, 42)
845n/a self.assertRaises(TypeError, codecs.register_error, "test.dummy", 42)
846n/a
847n/a def test_badlookupcall(self):
848n/a # enhance coverage of:
849n/a # Modules/_codecsmodule.c::lookup_error()
850n/a self.assertRaises(TypeError, codecs.lookup_error)
851n/a
852n/a def test_unknownhandler(self):
853n/a # enhance coverage of:
854n/a # Modules/_codecsmodule.c::lookup_error()
855n/a self.assertRaises(LookupError, codecs.lookup_error, "test.unknown")
856n/a
857n/a def test_xmlcharrefvalues(self):
858n/a # enhance coverage of:
859n/a # Python/codecs.c::PyCodec_XMLCharRefReplaceErrors()
860n/a # and inline implementations
861n/a v = (1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000,
862n/a 500000, 1000000)
863n/a s = "".join([chr(x) for x in v])
864n/a codecs.register_error("test.xmlcharrefreplace", codecs.xmlcharrefreplace_errors)
865n/a for enc in ("ascii", "iso-8859-15"):
866n/a for err in ("xmlcharrefreplace", "test.xmlcharrefreplace"):
867n/a s.encode(enc, err)
868n/a
869n/a def test_decodehelper(self):
870n/a # enhance coverage of:
871n/a # Objects/unicodeobject.c::unicode_decode_call_errorhandler()
872n/a # and callers
873n/a self.assertRaises(LookupError, b"\xff".decode, "ascii", "test.unknown")
874n/a
875n/a def baddecodereturn1(exc):
876n/a return 42
877n/a codecs.register_error("test.baddecodereturn1", baddecodereturn1)
878n/a self.assertRaises(TypeError, b"\xff".decode, "ascii", "test.baddecodereturn1")
879n/a self.assertRaises(TypeError, b"\\".decode, "unicode-escape", "test.baddecodereturn1")
880n/a self.assertRaises(TypeError, b"\\x0".decode, "unicode-escape", "test.baddecodereturn1")
881n/a self.assertRaises(TypeError, b"\\x0y".decode, "unicode-escape", "test.baddecodereturn1")
882n/a self.assertRaises(TypeError, b"\\Uffffeeee".decode, "unicode-escape", "test.baddecodereturn1")
883n/a self.assertRaises(TypeError, b"\\uyyyy".decode, "raw-unicode-escape", "test.baddecodereturn1")
884n/a
885n/a def baddecodereturn2(exc):
886n/a return ("?", None)
887n/a codecs.register_error("test.baddecodereturn2", baddecodereturn2)
888n/a self.assertRaises(TypeError, b"\xff".decode, "ascii", "test.baddecodereturn2")
889n/a
890n/a handler = PosReturn()
891n/a codecs.register_error("test.posreturn", handler.handle)
892n/a
893n/a # Valid negative position
894n/a handler.pos = -1
895n/a self.assertEqual(b"\xff0".decode("ascii", "test.posreturn"), "<?>0")
896n/a
897n/a # Valid negative position
898n/a handler.pos = -2
899n/a self.assertEqual(b"\xff0".decode("ascii", "test.posreturn"), "<?><?>")
900n/a
901n/a # Negative position out of bounds
902n/a handler.pos = -3
903n/a self.assertRaises(IndexError, b"\xff0".decode, "ascii", "test.posreturn")
904n/a
905n/a # Valid positive position
906n/a handler.pos = 1
907n/a self.assertEqual(b"\xff0".decode("ascii", "test.posreturn"), "<?>0")
908n/a
909n/a # Largest valid positive position (one beyond end of input)
910n/a handler.pos = 2
911n/a self.assertEqual(b"\xff0".decode("ascii", "test.posreturn"), "<?>")
912n/a
913n/a # Invalid positive position
914n/a handler.pos = 3
915n/a self.assertRaises(IndexError, b"\xff0".decode, "ascii", "test.posreturn")
916n/a
917n/a # Restart at the "0"
918n/a handler.pos = 6
919n/a self.assertEqual(b"\\uyyyy0".decode("raw-unicode-escape", "test.posreturn"), "<?>0")
920n/a
921n/a class D(dict):
922n/a def __getitem__(self, key):
923n/a raise ValueError
924n/a self.assertRaises(UnicodeError, codecs.charmap_decode, b"\xff", "strict", {0xff: None})
925n/a self.assertRaises(ValueError, codecs.charmap_decode, b"\xff", "strict", D())
926n/a self.assertRaises(TypeError, codecs.charmap_decode, b"\xff", "strict", {0xff: sys.maxunicode+1})
927n/a
928n/a def test_encodehelper(self):
929n/a # enhance coverage of:
930n/a # Objects/unicodeobject.c::unicode_encode_call_errorhandler()
931n/a # and callers
932n/a self.assertRaises(LookupError, "\xff".encode, "ascii", "test.unknown")
933n/a
934n/a def badencodereturn1(exc):
935n/a return 42
936n/a codecs.register_error("test.badencodereturn1", badencodereturn1)
937n/a self.assertRaises(TypeError, "\xff".encode, "ascii", "test.badencodereturn1")
938n/a
939n/a def badencodereturn2(exc):
940n/a return ("?", None)
941n/a codecs.register_error("test.badencodereturn2", badencodereturn2)
942n/a self.assertRaises(TypeError, "\xff".encode, "ascii", "test.badencodereturn2")
943n/a
944n/a handler = PosReturn()
945n/a codecs.register_error("test.posreturn", handler.handle)
946n/a
947n/a # Valid negative position
948n/a handler.pos = -1
949n/a self.assertEqual("\xff0".encode("ascii", "test.posreturn"), b"<?>0")
950n/a
951n/a # Valid negative position
952n/a handler.pos = -2
953n/a self.assertEqual("\xff0".encode("ascii", "test.posreturn"), b"<?><?>")
954n/a
955n/a # Negative position out of bounds
956n/a handler.pos = -3
957n/a self.assertRaises(IndexError, "\xff0".encode, "ascii", "test.posreturn")
958n/a
959n/a # Valid positive position
960n/a handler.pos = 1
961n/a self.assertEqual("\xff0".encode("ascii", "test.posreturn"), b"<?>0")
962n/a
963n/a # Largest valid positive position (one beyond end of input
964n/a handler.pos = 2
965n/a self.assertEqual("\xff0".encode("ascii", "test.posreturn"), b"<?>")
966n/a
967n/a # Invalid positive position
968n/a handler.pos = 3
969n/a self.assertRaises(IndexError, "\xff0".encode, "ascii", "test.posreturn")
970n/a
971n/a handler.pos = 0
972n/a
973n/a class D(dict):
974n/a def __getitem__(self, key):
975n/a raise ValueError
976n/a for err in ("strict", "replace", "xmlcharrefreplace",
977n/a "backslashreplace", "namereplace", "test.posreturn"):
978n/a self.assertRaises(UnicodeError, codecs.charmap_encode, "\xff", err, {0xff: None})
979n/a self.assertRaises(ValueError, codecs.charmap_encode, "\xff", err, D())
980n/a self.assertRaises(TypeError, codecs.charmap_encode, "\xff", err, {0xff: 300})
981n/a
982n/a def test_translatehelper(self):
983n/a # enhance coverage of:
984n/a # Objects/unicodeobject.c::unicode_encode_call_errorhandler()
985n/a # and callers
986n/a # (Unfortunately the errors argument is not directly accessible
987n/a # from Python, so we can't test that much)
988n/a class D(dict):
989n/a def __getitem__(self, key):
990n/a raise ValueError
991n/a #self.assertRaises(ValueError, "\xff".translate, D())
992n/a self.assertRaises(ValueError, "\xff".translate, {0xff: sys.maxunicode+1})
993n/a self.assertRaises(TypeError, "\xff".translate, {0xff: ()})
994n/a
995n/a def test_bug828737(self):
996n/a charmap = {
997n/a ord("&"): "&amp;",
998n/a ord("<"): "&lt;",
999n/a ord(">"): "&gt;",
1000n/a ord('"'): "&quot;",
1001n/a }
1002n/a
1003n/a for n in (1, 10, 100, 1000):
1004n/a text = 'abc<def>ghi'*n
1005n/a text.translate(charmap)
1006n/a
1007n/a def test_mutatingdecodehandler(self):
1008n/a baddata = [
1009n/a ("ascii", b"\xff"),
1010n/a ("utf-7", b"++"),
1011n/a ("utf-8", b"\xff"),
1012n/a ("utf-16", b"\xff"),
1013n/a ("utf-32", b"\xff"),
1014n/a ("unicode-escape", b"\\u123g"),
1015n/a ("raw-unicode-escape", b"\\u123g"),
1016n/a ("unicode-internal", b"\xff"),
1017n/a ]
1018n/a
1019n/a def replacing(exc):
1020n/a if isinstance(exc, UnicodeDecodeError):
1021n/a exc.object = 42
1022n/a return ("\u4242", 0)
1023n/a else:
1024n/a raise TypeError("don't know how to handle %r" % exc)
1025n/a codecs.register_error("test.replacing", replacing)
1026n/a
1027n/a with test.support.check_warnings():
1028n/a # unicode-internal has been deprecated
1029n/a for (encoding, data) in baddata:
1030n/a with self.assertRaises(TypeError):
1031n/a data.decode(encoding, "test.replacing")
1032n/a
1033n/a def mutating(exc):
1034n/a if isinstance(exc, UnicodeDecodeError):
1035n/a exc.object[:] = b""
1036n/a return ("\u4242", 0)
1037n/a else:
1038n/a raise TypeError("don't know how to handle %r" % exc)
1039n/a codecs.register_error("test.mutating", mutating)
1040n/a # If the decoder doesn't pick up the modified input the following
1041n/a # will lead to an endless loop
1042n/a with test.support.check_warnings():
1043n/a # unicode-internal has been deprecated
1044n/a for (encoding, data) in baddata:
1045n/a with self.assertRaises(TypeError):
1046n/a data.decode(encoding, "test.replacing")
1047n/a
1048n/a def test_fake_error_class(self):
1049n/a handlers = [
1050n/a codecs.strict_errors,
1051n/a codecs.ignore_errors,
1052n/a codecs.replace_errors,
1053n/a codecs.backslashreplace_errors,
1054n/a codecs.namereplace_errors,
1055n/a codecs.xmlcharrefreplace_errors,
1056n/a codecs.lookup_error('surrogateescape'),
1057n/a codecs.lookup_error('surrogatepass'),
1058n/a ]
1059n/a for cls in UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError:
1060n/a class FakeUnicodeError(str):
1061n/a __class__ = cls
1062n/a for handler in handlers:
1063n/a with self.subTest(handler=handler, error_class=cls):
1064n/a self.assertRaises(TypeError, handler, FakeUnicodeError())
1065n/a class FakeUnicodeError(Exception):
1066n/a __class__ = cls
1067n/a for handler in handlers:
1068n/a with self.subTest(handler=handler, error_class=cls):
1069n/a with self.assertRaises((TypeError, FakeUnicodeError)):
1070n/a handler(FakeUnicodeError())
1071n/a
1072n/a
1073n/aif __name__ == "__main__":
1074n/a unittest.main()