@@ -1258,19 +1258,41 @@ def test_unquote_with_unicode(self):
12581258 "using unquote(): %r != %r" % (expect , result ))
12591259
12601260 def test_unquote_ascii_and_non_ascii_agree (self ):
1261- # ASCII input takes a fast path; a non-ASCII prefix forces the
1262- # general path. Both must decode the escapes the same way.
1261+ # ASCII input takes a fast path; with a non-UTF-8 encoding, a
1262+ # non-ASCII prefix forces the general path. Both must decode the
1263+ # escapes the same way.
12631264 for given in ['%41%zz%' , 'a%20b%2Fc%E2%82%AC' , '%F3%B1' , '%C3%BC+%2B' ]:
1264- for encoding , errors in [('utf-8 ' , 'replace ' ),
1265- ('latin-1 ' , 'strict ' ),
1266- ('ascii ' , 'ignore ' )]:
1265+ for encoding , errors in [('latin-1 ' , 'strict ' ),
1266+ ('ascii ' , 'ignore ' ),
1267+ ('cp1252 ' , 'replace ' )]:
12671268 with self .subTest (given = given , encoding = encoding ,
12681269 errors = errors ):
12691270 expect = urllib .parse .unquote (given , encoding , errors )
12701271 result = urllib .parse .unquote ('\u00e9 ' + given ,
12711272 encoding , errors )
12721273 self .assertEqual (result , '\u00e9 ' + expect )
12731274
1275+ def test_unquote_non_ascii_utf8 (self ):
1276+ # Non-ASCII input decoded as UTF-8 takes a fast path that encodes
1277+ # the whole string at once. Literal characters must not combine
1278+ # with adjacent invalid escapes.
1279+ cases = [
1280+ ('\u00e9 %ff' , '\u00e9 \ufffd ' ),
1281+ ('%C3\u00e9 ' , '\ufffd \u00e9 ' ),
1282+ ('%F0%9F\U0001F600 ' , '\ufffd \U0001F600 ' ),
1283+ ('\u6f22 %20\u5b57 %E2%82%AC' , '\u6f22 \u5b57 \u20ac ' ),
1284+ # Lone surrogates cannot be encoded and are passed through.
1285+ ('\ud800 %41' , '\ud800 A' ),
1286+ ]
1287+ for given , expect in cases :
1288+ with self .subTest (given = given ):
1289+ self .assertEqual (urllib .parse .unquote (given ), expect )
1290+ self .assertEqual (urllib .parse .unquote (given , 'utf8' ), expect )
1291+ self .assertEqual (urllib .parse .unquote_plus ('caf\u00e9 +%2B' ),
1292+ 'caf\u00e9 +' )
1293+ self .assertRaises (UnicodeDecodeError , urllib .parse .unquote ,
1294+ '\u00e9 %ff' , errors = 'strict' )
1295+
12741296 def test_unquoting_with_bytes_input (self ):
12751297 # ASCII characters decoded to a string
12761298 given = b'blueberryjam'
0 commit comments