summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_codecs.py
diff options
context:
space:
mode:
authorJohn Sloboda <sloboda@gmail.com>2024-03-17 04:58:42 (GMT)
committerGitHub <noreply@github.com>2024-03-17 04:58:42 (GMT)
commit649857a1574a02235ccfac9e2ac1c12914cf8fe0 (patch)
treecf08eb67a84db277e1a687eb7177c709d16616b6 /Lib/test/test_codecs.py
parentc514a975abe35fa4604cd3541e2286168ef67d10 (diff)
downloadcpython-649857a1574a02235ccfac9e2ac1c12914cf8fe0.zip
cpython-649857a1574a02235ccfac9e2ac1c12914cf8fe0.tar.gz
cpython-649857a1574a02235ccfac9e2ac1c12914cf8fe0.tar.bz2
gh-85287: Change codecs to raise precise UnicodeEncodeError and UnicodeDecodeError (#113674)
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
Diffstat (limited to 'Lib/test/test_codecs.py')
-rw-r--r--Lib/test/test_codecs.py123
1 files changed, 114 insertions, 9 deletions
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index 9585f94..fe3776d 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -482,11 +482,11 @@ class UTF32Test(ReadTest, unittest.TestCase):
def test_badbom(self):
s = io.BytesIO(4*b"\xff")
f = codecs.getreader(self.encoding)(s)
- self.assertRaises(UnicodeError, f.read)
+ self.assertRaises(UnicodeDecodeError, f.read)
s = io.BytesIO(8*b"\xff")
f = codecs.getreader(self.encoding)(s)
- self.assertRaises(UnicodeError, f.read)
+ self.assertRaises(UnicodeDecodeError, f.read)
def test_partial(self):
self.check_partial(
@@ -666,11 +666,11 @@ class UTF16Test(ReadTest, unittest.TestCase):
def test_badbom(self):
s = io.BytesIO(b"\xff\xff")
f = codecs.getreader(self.encoding)(s)
- self.assertRaises(UnicodeError, f.read)
+ self.assertRaises(UnicodeDecodeError, f.read)
s = io.BytesIO(b"\xff\xff\xff\xff")
f = codecs.getreader(self.encoding)(s)
- self.assertRaises(UnicodeError, f.read)
+ self.assertRaises(UnicodeDecodeError, f.read)
def test_partial(self):
self.check_partial(
@@ -1356,13 +1356,29 @@ class PunycodeTest(unittest.TestCase):
def test_decode_invalid(self):
testcases = [
- (b"xn--w&", "strict", UnicodeError()),
+ (b"xn--w&", "strict", UnicodeDecodeError("punycode", b"", 5, 6, "")),
+ (b"&egbpdaj6bu4bxfgehfvwxn", "strict", UnicodeDecodeError("punycode", b"", 0, 1, "")),
+ (b"egbpdaj6bu&4bx&fgehfvwxn", "strict", UnicodeDecodeError("punycode", b"", 10, 11, "")),
+ (b"egbpdaj6bu4bxfgehfvwxn&", "strict", UnicodeDecodeError("punycode", b"", 22, 23, "")),
+ (b"\xFFProprostnemluvesky-uyb24dma41a", "strict", UnicodeDecodeError("ascii", b"", 0, 1, "")),
+ (b"Pro\xFFprostnemluvesky-uyb24dma41a", "strict", UnicodeDecodeError("ascii", b"", 3, 4, "")),
+ (b"Proprost&nemluvesky-uyb24&dma41a", "strict", UnicodeDecodeError("punycode", b"", 25, 26, "")),
+ (b"Proprostnemluvesky&-&uyb24dma41a", "strict", UnicodeDecodeError("punycode", b"", 20, 21, "")),
+ (b"Proprostnemluvesky-&uyb24dma41a", "strict", UnicodeDecodeError("punycode", b"", 19, 20, "")),
+ (b"Proprostnemluvesky-uyb24d&ma41a", "strict", UnicodeDecodeError("punycode", b"", 25, 26, "")),
+ (b"Proprostnemluvesky-uyb24dma41a&", "strict", UnicodeDecodeError("punycode", b"", 30, 31, "")),
(b"xn--w&", "ignore", "xn-"),
]
for puny, errors, expected in testcases:
with self.subTest(puny=puny, errors=errors):
if isinstance(expected, Exception):
- self.assertRaises(UnicodeError, puny.decode, "punycode", errors)
+ with self.assertRaises(UnicodeDecodeError) as cm:
+ puny.decode("punycode", errors)
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, puny)
+ self.assertEqual(exc.start, expected.start)
+ self.assertEqual(exc.end, expected.end)
else:
self.assertEqual(puny.decode("punycode", errors), expected)
@@ -1532,7 +1548,7 @@ class NameprepTest(unittest.TestCase):
orig = str(orig, "utf-8", "surrogatepass")
if prepped is None:
# Input contains prohibited characters
- self.assertRaises(UnicodeError, nameprep, orig)
+ self.assertRaises(UnicodeEncodeError, nameprep, orig)
else:
prepped = str(prepped, "utf-8", "surrogatepass")
try:
@@ -1542,6 +1558,23 @@ class NameprepTest(unittest.TestCase):
class IDNACodecTest(unittest.TestCase):
+
+ invalid_decode_testcases = [
+ (b"\xFFpython.org", UnicodeDecodeError("idna", b"\xFFpython.org", 0, 1, "")),
+ (b"pyt\xFFhon.org", UnicodeDecodeError("idna", b"pyt\xFFhon.org", 3, 4, "")),
+ (b"python\xFF.org", UnicodeDecodeError("idna", b"python\xFF.org", 6, 7, "")),
+ (b"python.\xFForg", UnicodeDecodeError("idna", b"python.\xFForg", 7, 8, "")),
+ (b"python.o\xFFrg", UnicodeDecodeError("idna", b"python.o\xFFrg", 8, 9, "")),
+ (b"python.org\xFF", UnicodeDecodeError("idna", b"python.org\xFF", 10, 11, "")),
+ (b"xn--pythn-&mua.org", UnicodeDecodeError("idna", b"xn--pythn-&mua.org", 10, 11, "")),
+ (b"xn--pythn-m&ua.org", UnicodeDecodeError("idna", b"xn--pythn-m&ua.org", 11, 12, "")),
+ (b"xn--pythn-mua&.org", UnicodeDecodeError("idna", b"xn--pythn-mua&.org", 13, 14, "")),
+ ]
+ invalid_encode_testcases = [
+ (f"foo.{'\xff'*60}", UnicodeEncodeError("idna", f"foo.{'\xff'*60}", 4, 64, "")),
+ ("あさ.\u034f", UnicodeEncodeError("idna", "あさ.\u034f", 3, 4, "")),
+ ]
+
def test_builtin_decode(self):
self.assertEqual(str(b"python.org", "idna"), "python.org")
self.assertEqual(str(b"python.org.", "idna"), "python.org.")
@@ -1555,16 +1588,38 @@ class IDNACodecTest(unittest.TestCase):
self.assertEqual(str(b"bugs.XN--pythn-mua.org.", "idna"),
"bugs.pyth\xf6n.org.")
+ def test_builtin_decode_invalid(self):
+ for case, expected in self.invalid_decode_testcases:
+ with self.subTest(case=case, expected=expected):
+ with self.assertRaises(UnicodeDecodeError) as cm:
+ case.decode("idna")
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, expected.object)
+ self.assertEqual(exc.start, expected.start, msg=f'reason: {exc.reason}')
+ self.assertEqual(exc.end, expected.end)
+
def test_builtin_encode(self):
self.assertEqual("python.org".encode("idna"), b"python.org")
self.assertEqual("python.org.".encode("idna"), b"python.org.")
self.assertEqual("pyth\xf6n.org".encode("idna"), b"xn--pythn-mua.org")
self.assertEqual("pyth\xf6n.org.".encode("idna"), b"xn--pythn-mua.org.")
+ def test_builtin_encode_invalid(self):
+ for case, expected in self.invalid_encode_testcases:
+ with self.subTest(case=case, expected=expected):
+ with self.assertRaises(UnicodeEncodeError) as cm:
+ case.encode("idna")
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, expected.object)
+ self.assertEqual(exc.start, expected.start)
+ self.assertEqual(exc.end, expected.end)
+
def test_builtin_decode_length_limit(self):
- with self.assertRaisesRegex(UnicodeError, "way too long"):
+ with self.assertRaisesRegex(UnicodeDecodeError, "way too long"):
(b"xn--016c"+b"a"*1100).decode("idna")
- with self.assertRaisesRegex(UnicodeError, "too long"):
+ with self.assertRaisesRegex(UnicodeDecodeError, "too long"):
(b"xn--016c"+b"a"*70).decode("idna")
def test_stream(self):
@@ -1602,6 +1657,39 @@ class IDNACodecTest(unittest.TestCase):
self.assertEqual(decoder.decode(b"rg."), "org.")
self.assertEqual(decoder.decode(b"", True), "")
+ def test_incremental_decode_invalid(self):
+ iterdecode_testcases = [
+ (b"\xFFpython.org", UnicodeDecodeError("idna", b"\xFF", 0, 1, "")),
+ (b"pyt\xFFhon.org", UnicodeDecodeError("idna", b"pyt\xFF", 3, 4, "")),
+ (b"python\xFF.org", UnicodeDecodeError("idna", b"python\xFF", 6, 7, "")),
+ (b"python.\xFForg", UnicodeDecodeError("idna", b"\xFF", 0, 1, "")),
+ (b"python.o\xFFrg", UnicodeDecodeError("idna", b"o\xFF", 1, 2, "")),
+ (b"python.org\xFF", UnicodeDecodeError("idna", b"org\xFF", 3, 4, "")),
+ (b"xn--pythn-&mua.org", UnicodeDecodeError("idna", b"xn--pythn-&mua.", 10, 11, "")),
+ (b"xn--pythn-m&ua.org", UnicodeDecodeError("idna", b"xn--pythn-m&ua.", 11, 12, "")),
+ (b"xn--pythn-mua&.org", UnicodeDecodeError("idna", b"xn--pythn-mua&.", 13, 14, "")),
+ ]
+ for case, expected in iterdecode_testcases:
+ with self.subTest(case=case, expected=expected):
+ with self.assertRaises(UnicodeDecodeError) as cm:
+ list(codecs.iterdecode((bytes([c]) for c in case), "idna"))
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, expected.object)
+ self.assertEqual(exc.start, expected.start)
+ self.assertEqual(exc.end, expected.end)
+
+ decoder = codecs.getincrementaldecoder("idna")()
+ for case, expected in self.invalid_decode_testcases:
+ with self.subTest(case=case, expected=expected):
+ with self.assertRaises(UnicodeDecodeError) as cm:
+ decoder.decode(case)
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, expected.object)
+ self.assertEqual(exc.start, expected.start)
+ self.assertEqual(exc.end, expected.end)
+
def test_incremental_encode(self):
self.assertEqual(
b"".join(codecs.iterencode("python.org", "idna")),
@@ -1630,6 +1718,23 @@ class IDNACodecTest(unittest.TestCase):
self.assertEqual(encoder.encode("ample.org."), b"xn--xample-9ta.org.")
self.assertEqual(encoder.encode("", True), b"")
+ def test_incremental_encode_invalid(self):
+ iterencode_testcases = [
+ (f"foo.{'\xff'*60}", UnicodeEncodeError("idna", f"{'\xff'*60}", 0, 60, "")),
+ ("あさ.\u034f", UnicodeEncodeError("idna", "\u034f", 0, 1, "")),
+ ]
+ for case, expected in iterencode_testcases:
+ with self.subTest(case=case, expected=expected):
+ with self.assertRaises(UnicodeEncodeError) as cm:
+ list(codecs.iterencode(case, "idna"))
+ exc = cm.exception
+ self.assertEqual(exc.encoding, expected.encoding)
+ self.assertEqual(exc.object, expected.object)
+ self.assertEqual(exc.start, expected.start)
+ self.assertEqual(exc.end, expected.end)
+
+ # codecs.getincrementalencoder.encode() does not throw an error
+
def test_errors(self):
"""Only supports "strict" error handler"""
"python.org".encode("idna", "strict")