77import  unittest .mock  as  mock 
88import  _testcapi 
99from  test .support  import  import_helper 
10+ from  test .support .script_helper  import  assert_python_failure 
1011
1112_testlimitedcapi  =  import_helper .import_module ('_testlimitedcapi' )
1213
@@ -745,55 +746,34 @@ def test_codec_stream_writer(self):
745746                codec_stream_writer (NULL , stream , 'strict' )
746747
747748
748- class  UnsafeUnicodeEncodeError (UnicodeEncodeError ):
749-     def  __init__ (self , encoding , message , start , end , reason ):
750-         self .may_crash  =  (end  -  start ) <  0  or  (end  -  start ) >=  len (message )
751-         super ().__init__ (encoding , message , start , end , reason )
752- 
753- 
754- class  UnsafeUnicodeDecodeError (UnicodeDecodeError ):
755-     def  __init__ (self , encoding , message , start , end , reason ):
756-         # the case end - start >= len(message) does not crash 
757-         self .may_crash  =  (end  -  start ) <  0 
758-         super ().__init__ (encoding , message , start , end , reason )
759- 
760- 
761- class  UnsafeUnicodeTranslateError (UnicodeTranslateError ):
762-     def  __init__ (self , message , start , end , reason ):
763-         # <= 0 because PyCodec_ReplaceErrors tries to check the Unicode kind 
764-         # of a 0-length result (which is by convention PyUnicode_1BYTE_KIND 
765-         # and not PyUnicode_2BYTE_KIND as it currently expects) 
766-         self .may_crash  =  (end  -  start ) <=  0  or  (end  -  start ) >=  len (message )
767-         super ().__init__ (message , start , end , reason )
768- 
769- 
770749class  CAPICodecErrors (unittest .TestCase ):
750+ 
771751    @classmethod  
772752    def  _generate_exception_args (cls ):
773-         for  objlen  in  range (10 ):
774-             m  =  2  *  max (2 , objlen )
775-             for  start  in  range (- m ,  m ):
776-                 for  end  in  range (- m ,  m ):
753+         for  objlen  in  range (5 ):
754+             maxind  =  2  *  max (2 , objlen )
755+             for  start  in  range (- maxind ,  maxind   +   1 ):
756+                 for  end  in  range (- maxind ,  maxind   +   1 ):
777757                    yield  objlen , start , end 
778758
779759    @classmethod  
780760    def  generate_encode_errors (cls ):
781761        return  tuple (
782-             UnsafeUnicodeEncodeError ('utf-8' , '0'  *  objlen , start , end , 'why' )
762+             UnicodeEncodeError ('utf-8' , '0'  *  objlen , start , end , 'why' )
783763            for  objlen , start , end  in  cls ._generate_exception_args ()
784764        )
785765
786766    @classmethod  
787767    def  generate_decode_errors (cls ):
788768        return  tuple (
789-             UnsafeUnicodeDecodeError ('utf-8' , b'0'  *  objlen , start , end , 'why' )
769+             UnicodeDecodeError ('utf-8' , b'0'  *  objlen , start , end , 'why' )
790770            for  objlen , start , end  in  cls ._generate_exception_args ()
791771        )
792772
793773    @classmethod  
794774    def  generate_translate_errors (cls ):
795775        return  tuple (
796-             UnsafeUnicodeTranslateError ('0'  *  objlen , start , end , 'why' )
776+             UnicodeTranslateError ('0'  *  objlen , start , end , 'why' )
797777            for  objlen , start , end  in  cls ._generate_exception_args ()
798778        )
799779
@@ -879,15 +859,16 @@ def do_test_codec_errors_handler(self, handler, exceptions):
879859        for  exc  in  exceptions :
880860            # See https://github.com/python/cpython/issues/123378 and related 
881861            # discussion and issues for details. 
882-             if  exc . may_crash :
862+             if  self . _exception_may_crash ( exc ) :
883863                continue 
884864
885865            at_least_one  =  True 
886866            with  self .subTest (handler = handler , exc = exc ):
887867                # test that the handler does not crash 
888868                self .assertIsInstance (handler (exc ), tuple )
889869
890-         self .assertTrue (at_least_one , "all exceptions are crashing" )
870+         if  exceptions :
871+             self .assertTrue (at_least_one , "all exceptions are crashing" )
891872
892873        for  bad_exc  in  (
893874            self .bad_unicode_errors 
@@ -896,6 +877,28 @@ def do_test_codec_errors_handler(self, handler, exceptions):
896877            with  self .subTest ('bad type' , handler = handler , exc = bad_exc ):
897878                self .assertRaises (TypeError , handler , bad_exc )
898879
880+     @classmethod  
881+     def  _exception_may_crash (cls , exc ):
882+         """Indicate whether a Unicode exception may crash the interpreter 
883+         when used by a built-in codecs error handler. 
884+ 
885+         This should only be used by "do_test_codec_errors_handler". 
886+         """ 
887+         message , start , end  =  exc .object , exc .start , exc .end 
888+         match  exc :
889+             case  UnicodeEncodeError ():
890+                 return  end  <  start  or  (end  -  start ) >=  len (message )
891+             case  UnicodeDecodeError ():
892+                 # The case "end - start >= len(message)" does not crash. 
893+                 return  end  <  start 
894+             case  UnicodeTranslateError ():
895+                 # Test "end <= start" because PyCodec_ReplaceErrors checks 
896+                 # the Unicode kind of a 0-length string which by convention 
897+                 # is PyUnicode_1BYTE_KIND and not PyUnicode_2BYTE_KIND as 
898+                 # the handler currently expects. 
899+                 return  end  <=  start  or  (end  -  start ) >=  len (message )
900+         return  False 
901+ 
899902
900903if  __name__  ==  "__main__" :
901904    unittest .main ()
0 commit comments