@@ -124,6 +124,21 @@ def test_splitdrive(self):
124124        tester ('ntpath.splitdrive("//?/UNC/server/share/dir")' ,
125125               ("//?/UNC/server/share" , "/dir" ))
126126
127+     def  test_splitdrive_invalid_paths (self ):
128+         self .assertEqual (ntpath .splitdrive ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
129+                          ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ di\x00 r' ))
130+         self .assertEqual (ntpath .splitdrive (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
131+                          (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ di\x00 r' ))
132+         self .assertEqual (ntpath .splitdrive ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
133+                          ('\\ \\ \udfff \\ \udffe ' , '\\ \udffd ' ))
134+         if  sys .platform  ==  'win32' :
135+             self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ \xff \\ share\\ dir' )
136+             self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ server\\ \xff \\ dir' )
137+             self .assertRaises (UnicodeDecodeError , ntpath .splitdrive , b'\\ \\ server\\ share\\ \xff ' )
138+         else :
139+             self .assertEqual (ntpath .splitdrive (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
140+                              (b'\\ \\ \xff \\ \xfe ' , b'\\ \xfd ' ))
141+ 
127142    def  test_splitroot (self ):
128143        tester ("ntpath.splitroot('')" , ('' , '' , '' ))
129144        tester ("ntpath.splitroot('foo')" , ('' , '' , 'foo' ))
@@ -214,6 +229,21 @@ def test_splitroot(self):
214229        tester ('ntpath.splitroot(" :/foo")' , (" :" , "/" , "foo" ))
215230        tester ('ntpath.splitroot("/:/foo")' , ("" , "/" , ":/foo" ))
216231
232+     def  test_splitroot_invalid_paths (self ):
233+         self .assertEqual (ntpath .splitroot ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
234+                          ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ ' , 'di\x00 r' ))
235+         self .assertEqual (ntpath .splitroot (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
236+                          (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ ' , b'di\x00 r' ))
237+         self .assertEqual (ntpath .splitroot ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
238+                          ('\\ \\ \udfff \\ \udffe ' , '\\ ' , '\udffd ' ))
239+         if  sys .platform  ==  'win32' :
240+             self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ \xff \\ share\\ dir' )
241+             self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ server\\ \xff \\ dir' )
242+             self .assertRaises (UnicodeDecodeError , ntpath .splitroot , b'\\ \\ server\\ share\\ \xff ' )
243+         else :
244+             self .assertEqual (ntpath .splitroot (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
245+                              (b'\\ \\ \xff \\ \xfe ' , b'\\ ' , b'\xfd ' ))
246+ 
217247    def  test_split (self ):
218248        tester ('ntpath.split("c:\\ foo\\ bar")' , ('c:\\ foo' , 'bar' ))
219249        tester ('ntpath.split("\\ \\ conky\\ mountpoint\\ foo\\ bar")' ,
@@ -226,6 +256,20 @@ def test_split(self):
226256        tester ('ntpath.split("c:/")' , ('c:/' , '' ))
227257        tester ('ntpath.split("//conky/mountpoint/")' , ('//conky/mountpoint/' , '' ))
228258
259+     def  test_split_invalid_paths (self ):
260+         self .assertEqual (ntpath .split ('c:\\ fo\x00 o\\ ba\x00 r' ),
261+                          ('c:\\ fo\x00 o' , 'ba\x00 r' ))
262+         self .assertEqual (ntpath .split (b'c:\\ fo\x00 o\\ ba\x00 r' ),
263+                          (b'c:\\ fo\x00 o' , b'ba\x00 r' ))
264+         self .assertEqual (ntpath .split ('c:\\ \udfff \\ \udffe ' ),
265+                          ('c:\\ \udfff ' , '\udffe ' ))
266+         if  sys .platform  ==  'win32' :
267+             self .assertRaises (UnicodeDecodeError , ntpath .split , b'c:\\ \xff \\ bar' )
268+             self .assertRaises (UnicodeDecodeError , ntpath .split , b'c:\\ foo\\ \xff ' )
269+         else :
270+             self .assertEqual (ntpath .split (b'c:\\ \xff \\ \xfe ' ),
271+                              (b'c:\\ \xff ' , b'\xfe ' ))
272+ 
229273    def  test_isabs (self ):
230274        tester ('ntpath.isabs("foo\\ bar")' , 0 )
231275        tester ('ntpath.isabs("foo/bar")' , 0 )
@@ -333,6 +377,29 @@ def test_join(self):
333377        tester ("ntpath.join('D:a', './c:b')" , 'D:a\\ .\\ c:b' )
334378        tester ("ntpath.join('D:/a', './c:b')" , 'D:\\ a\\ .\\ c:b' )
335379
380+     def  test_normcase (self ):
381+         normcase  =  ntpath .normcase 
382+         self .assertEqual (normcase ('' ), '' )
383+         self .assertEqual (normcase (b'' ), b'' )
384+         self .assertEqual (normcase ('ABC' ), 'abc' )
385+         self .assertEqual (normcase (b'ABC' ), b'abc' )
386+         self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' ), '\xe4 \u0142 \u03c8 ' )
387+         expected  =  '\u03c9 \u2126 '  if  sys .platform  ==  'win32'  else  '\u03c9 \u03c9 ' 
388+         self .assertEqual (normcase ('\u03a9 \u2126 ' ), expected )
389+         if  sys .platform  ==  'win32'  or  sys .getfilesystemencoding () ==  'utf-8' :
390+             self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' .encode ()),
391+                              '\xe4 \u0142 \u03c8 ' .encode ())
392+             self .assertEqual (normcase ('\u03a9 \u2126 ' .encode ()),
393+                              expected .encode ())
394+ 
395+     def  test_normcase_invalid_paths (self ):
396+         self .assertEqual (ntpath .normcase ('abc\x00 def' ), 'abc\x00 def' )
397+         self .assertEqual (ntpath .normcase (b'abc\x00 def' ), b'abc\x00 def' )
398+         self .assertEqual (ntpath .normcase ('\udfff ' ), '\udfff ' )
399+         if  sys .platform  ==  'win32' :
400+             path  =  b'ABC'  +  bytes (range (128 , 256 ))
401+             self .assertEqual (ntpath .normcase (path ), path .lower ())
402+ 
336403    def  test_normpath (self ):
337404        tester ("ntpath.normpath('A//////././//.//B')" , r'A\B' )
338405        tester ("ntpath.normpath('A/./B')" , r'A\B' )
@@ -381,6 +448,21 @@ def test_normpath(self):
381448        tester ("ntpath.normpath('\\ \\ ')" , '\\ \\ ' )
382449        tester ("ntpath.normpath('//?/UNC/server/share/..')" , '\\ \\ ?\\ UNC\\ server\\ share\\ ' )
383450
451+     def  test_normpath_invalid_paths (self ):
452+         normpath  =  ntpath .normpath 
453+         self .assertEqual (normpath ('fo\x00 o' ), 'fo\x00 o' )
454+         self .assertEqual (normpath (b'fo\x00 o' ), b'fo\x00 o' )
455+         self .assertEqual (normpath ('fo\x00 o\\ ..\\ bar' ), 'bar' )
456+         self .assertEqual (normpath (b'fo\x00 o\\ ..\\ bar' ), b'bar' )
457+         self .assertEqual (normpath ('\udfff ' ), '\udfff ' )
458+         self .assertEqual (normpath ('\udfff \\ ..\\ foo' ), 'foo' )
459+         if  sys .platform  ==  'win32' :
460+             self .assertRaises (UnicodeDecodeError , normpath , b'\xff ' )
461+             self .assertRaises (UnicodeDecodeError , normpath , b'\xff \\ ..\\ foo' )
462+         else :
463+             self .assertEqual (normpath (b'\xff ' ), b'\xff ' )
464+             self .assertEqual (normpath (b'\xff \\ ..\\ foo' ), b'foo' )
465+ 
384466    def  test_realpath_curdir (self ):
385467        expected  =  ntpath .normpath (os .getcwd ())
386468        tester ("ntpath.realpath('.')" , expected )
@@ -420,10 +502,6 @@ def test_realpath_basic(self):
420502        d  =  drives .pop ().encode ()
421503        self .assertEqual (ntpath .realpath (d ), d )
422504
423-         # gh-106242: Embedded nulls and non-strict fallback to abspath 
424-         self .assertEqual (ABSTFN  +  "\0 spam" ,
425-                          ntpath .realpath (os_helper .TESTFN  +  "\0 spam" , strict = False ))
426- 
427505    @os_helper .skip_unless_symlink  
428506    @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' ) 
429507    def  test_realpath_strict (self ):
@@ -434,8 +512,51 @@ def test_realpath_strict(self):
434512        self .addCleanup (os_helper .unlink , ABSTFN )
435513        self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN , strict = True )
436514        self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN  +  "2" , strict = True )
515+ 
516+     @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' ) 
517+     def  test_realpath_invalid_paths (self ):
518+         realpath  =  ntpath .realpath 
519+         ABSTFN  =  ntpath .abspath (os_helper .TESTFN )
520+         ABSTFNb  =  os .fsencode (ABSTFN )
521+         path  =  ABSTFN  +  '\x00 ' 
522+         # gh-106242: Embedded nulls and non-strict fallback to abspath 
523+         self .assertEqual (realpath (path , strict = False ), path )
437524        # gh-106242: Embedded nulls should raise OSError (not ValueError) 
438-         self .assertRaises (OSError , ntpath .realpath , ABSTFN  +  "\0 spam" , strict = True )
525+         self .assertRaises (OSError , realpath , path , strict = True )
526+         path  =  ABSTFNb  +  b'\x00 ' 
527+         self .assertEqual (realpath (path , strict = False ), path )
528+         self .assertRaises (OSError , realpath , path , strict = True )
529+         path  =  ABSTFN  +  '\\ nonexistent\\ x\x00 ' 
530+         self .assertEqual (realpath (path , strict = False ), path )
531+         self .assertRaises (OSError , realpath , path , strict = True )
532+         path  =  ABSTFNb  +  b'\\ nonexistent\\ x\x00 ' 
533+         self .assertEqual (realpath (path , strict = False ), path )
534+         self .assertRaises (OSError , realpath , path , strict = True )
535+         path  =  ABSTFN  +  '\x00 \\ ..' 
536+         self .assertEqual (realpath (path , strict = False ), os .getcwd ())
537+         self .assertEqual (realpath (path , strict = True ), os .getcwd ())
538+         path  =  ABSTFNb  +  b'\x00 \\ ..' 
539+         self .assertEqual (realpath (path , strict = False ), os .getcwdb ())
540+         self .assertEqual (realpath (path , strict = True ), os .getcwdb ())
541+         path  =  ABSTFN  +  '\\ nonexistent\\ x\x00 \\ ..' 
542+         self .assertEqual (realpath (path , strict = False ), ABSTFN  +  '\\ nonexistent' )
543+         self .assertRaises (OSError , realpath , path , strict = True )
544+         path  =  ABSTFNb  +  b'\\ nonexistent\\ x\x00 \\ ..' 
545+         self .assertEqual (realpath (path , strict = False ), ABSTFNb  +  b'\\ nonexistent' )
546+         self .assertRaises (OSError , realpath , path , strict = True )
547+ 
548+         path  =  ABSTFNb  +  b'\xff ' 
549+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
550+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
551+         path  =  ABSTFNb  +  b'\\ nonexistent\\ \xff ' 
552+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
553+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
554+         path  =  ABSTFNb  +  b'\xff \\ ..' 
555+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
556+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
557+         path  =  ABSTFNb  +  b'\\ nonexistent\\ \xff \\ ..' 
558+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
559+         self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
439560
440561    @os_helper .skip_unless_symlink  
441562    @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' ) 
@@ -847,6 +968,21 @@ def test_abspath(self):
847968            drive , _  =  ntpath .splitdrive (cwd_dir )
848969            tester ('ntpath.abspath("/abc/")' , drive  +  "\\ abc" )
849970
971+     def  test_abspath_invalid_paths (self ):
972+         abspath  =  ntpath .abspath 
973+         self .assertEqual (abspath ('c:\\ fo\x00 o' ), 'c:\\ fo\x00 o' )
974+         self .assertEqual (abspath (b'c:\\ fo\x00 o' ), b'c:\\ fo\x00 o' )
975+         self .assertEqual (abspath ('c:\\ fo\x00 o\\ ..\\ bar' ), 'c:\\ bar' )
976+         self .assertEqual (abspath (b'c:\\ fo\x00 o\\ ..\\ bar' ), b'c:\\ bar' )
977+         self .assertEqual (abspath ('c:\\ \udfff ' ), 'c:\\ \udfff ' )
978+         self .assertEqual (abspath ('c:\\ \udfff \\ ..\\ foo' ), 'c:\\ foo' )
979+         if  sys .platform  ==  'win32' :
980+             self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff ' )
981+             self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff \\ ..\\ foo' )
982+         else :
983+             self .assertEqual (abspath (b'c:\\ \xff ' ), b'c:\\ \xff ' )
984+             self .assertEqual (abspath (b'c:\\ \xff \\ ..\\ foo' ), b'c:\\ foo' )
985+ 
850986    def  test_relpath (self ):
851987        tester ('ntpath.relpath("a")' , 'a' )
852988        tester ('ntpath.relpath(ntpath.abspath("a"))' , 'a' )
@@ -989,6 +1125,17 @@ def test_ismount(self):
9891125            self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$" ))
9901126            self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$\\ " ))
9911127
1128+     def  test_ismount_invalid_paths (self ):
1129+         self .assertFalse (ntpath .ismount ("c:\\ \udfff " ))
1130+         if  sys .platform  ==  'win32' :
1131+             self .assertRaises (ValueError , ntpath .ismount , "c:\\ \x00 " )
1132+             self .assertRaises (ValueError , ntpath .ismount , b"c:\\ \x00 " )
1133+             self .assertRaises (UnicodeDecodeError , ntpath .ismount , b"c:\\ \xff " )
1134+         else :
1135+             self .assertFalse (ntpath .ismount ("c:\\ \x00 " ))
1136+             self .assertFalse (ntpath .ismount (b"c:\\ \x00 " ))
1137+             self .assertFalse (ntpath .ismount (b"c:\\ \xff " ))
1138+ 
9921139    def  test_isreserved (self ):
9931140        self .assertFalse (ntpath .isreserved ('' ))
9941141        self .assertFalse (ntpath .isreserved ('.' ))
@@ -1095,12 +1242,11 @@ def test_isjunction(self):
10951242                self .assertFalse (ntpath .isjunction ('tmpdir' ))
10961243                self .assertPathEqual (ntpath .realpath ('testjunc' ), ntpath .realpath ('tmpdir' ))
10971244
1098-     @unittest .skipIf (sys .platform  !=  'win32' , "drive letters are a windows concept" ) 
1099-     def  test_isfile_driveletter (self ):
1100-         drive  =  os .environ .get ('SystemDrive' )
1101-         if  drive  is  None  or  len (drive ) !=  2  or  drive [1 ] !=  ':' :
1102-             raise  unittest .SkipTest ('SystemDrive is not defined or malformed' )
1103-         self .assertFalse (os .path .isfile ('\\ \\ .\\ '  +  drive ))
1245+     def  test_isfile_invalid_paths (self ):
1246+         self .assertIs (ntpath .isfile ('/tmp\udfff abcds' ), False )
1247+         self .assertIs (ntpath .isfile (b'/tmp\xff abcds' ), False )
1248+         self .assertIs (ntpath .isfile ('/tmp\x00 abcds' ), False )
1249+         self .assertIs (ntpath .isfile (b'/tmp\x00 abcds' ), False )
11041250
11051251    @unittest .skipUnless (hasattr (os , 'pipe' ), "need os.pipe()" ) 
11061252    def  test_isfile_anonymous_pipe (self ):
@@ -1195,9 +1341,6 @@ def _check_function(self, func):
11951341
11961342    def  test_path_normcase (self ):
11971343        self ._check_function (self .path .normcase )
1198-         if  sys .platform  ==  'win32' :
1199-             self .assertEqual (ntpath .normcase ('\u03a9 \u2126 ' ), 'ωΩ' )
1200-             self .assertEqual (ntpath .normcase ('abc\x00 def' ), 'abc\x00 def' )
12011344
12021345    def  test_path_isabs (self ):
12031346        self ._check_function (self .path .isabs )
0 commit comments