@@ -1667,6 +1667,8 @@ class IDNACodecTest(unittest.TestCase):
16671667 (b"xn--pythn-&mua.org" , UnicodeDecodeError ("idna" , b"xn--pythn-&mua.org" , 10 , 11 , "" )),
16681668 (b"xn--pythn-m&ua.org" , UnicodeDecodeError ("idna" , b"xn--pythn-m&ua.org" , 11 , 12 , "" )),
16691669 (b"xn--pythn-mua&.org" , UnicodeDecodeError ("idna" , b"xn--pythn-mua&.org" , 13 , 14 , "" )),
1670+ (b"bugs.xn--pythn-&mua.org" , UnicodeDecodeError ("idna" , b"bugs.xn--pythn-&mua.org" , 15 , 16 , "" )),
1671+ (b".xn--pythn-&mua.org" , UnicodeDecodeError ("idna" , b".xn--pythn-&mua.org" , 11 , 12 , "" )),
16701672 ]
16711673 invalid_encode_testcases = [
16721674 (f"foo.{ '\xff ' * 60 } " , UnicodeEncodeError ("idna" , f"foo.{ '\xff ' * 60 } " , 4 , 64 , "" )),
@@ -1786,6 +1788,22 @@ def test_incremental_decode(self):
17861788 self .assertEqual (decoder .decode (b"rg." ), "org." )
17871789 self .assertEqual (decoder .decode (b"" , True ), "" )
17881790
1791+ def test_incremental_decode_leading_empty_labels (self ):
1792+ # The dot after an empty label at the start of the input has to be
1793+ # counted as consumed, or it is decoded again by the next call.
1794+ for data in b".python.org" , b"..python.org." , b".." , b"." * 100 :
1795+ with self .subTest (data = data ):
1796+ decoder = codecs .getincrementaldecoder ("idna" )()
1797+ result = decoder .decode (data )
1798+ self .assertNotIn (b"." , decoder .getstate ()[0 ])
1799+ result += decoder .decode (b"" , True )
1800+ self .assertEqual (result , data .decode ("idna" ))
1801+ self .assertEqual (decoder .getstate (), (b"" , 0 ))
1802+ self .assertEqual (decoder .decode (b"" , True ), "" )
1803+
1804+ with io .TextIOWrapper (io .BytesIO (b"." * 100 ), encoding = "idna" ) as f :
1805+ self .assertEqual (f .readline (), "." * 100 )
1806+
17891807 def test_incremental_decode_invalid (self ):
17901808 iterdecode_testcases = [
17911809 (b"\xFF python.org" , UnicodeDecodeError ("idna" , b"\xFF " , 0 , 1 , "" )),
0 commit comments