@@ -124,6 +124,22 @@ 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+ splitdrive = ntpath .splitdrive
129+ self .assertEqual (splitdrive ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
130+ ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ di\x00 r' ))
131+ self .assertEqual (splitdrive (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
132+ (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ di\x00 r' ))
133+ self .assertEqual (splitdrive ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
134+ ('\\ \\ \udfff \\ \udffe ' , '\\ \udffd ' ))
135+ if sys .platform == 'win32' :
136+ self .assertRaises (UnicodeDecodeError , splitdrive , b'\\ \\ \xff \\ share\\ dir' )
137+ self .assertRaises (UnicodeDecodeError , splitdrive , b'\\ \\ server\\ \xff \\ dir' )
138+ self .assertRaises (UnicodeDecodeError , splitdrive , b'\\ \\ server\\ share\\ \xff ' )
139+ else :
140+ self .assertEqual (splitdrive (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
141+ (b'\\ \\ \xff \\ \xfe ' , b'\\ \xfd ' ))
142+
127143 def test_splitroot (self ):
128144 tester ("ntpath.splitroot('')" , ('' , '' , '' ))
129145 tester ("ntpath.splitroot('foo')" , ('' , '' , 'foo' ))
@@ -214,6 +230,22 @@ def test_splitroot(self):
214230 tester ('ntpath.splitroot(" :/foo")' , (" :" , "/" , "foo" ))
215231 tester ('ntpath.splitroot("/:/foo")' , ("" , "/" , ":/foo" ))
216232
233+ def test_splitroot_invalid_paths (self ):
234+ splitroot = ntpath .splitroot
235+ self .assertEqual (splitroot ('\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
236+ ('\\ \\ ser\x00 ver\\ sha\x00 re' , '\\ ' , 'di\x00 r' ))
237+ self .assertEqual (splitroot (b'\\ \\ ser\x00 ver\\ sha\x00 re\\ di\x00 r' ),
238+ (b'\\ \\ ser\x00 ver\\ sha\x00 re' , b'\\ ' , b'di\x00 r' ))
239+ self .assertEqual (splitroot ("\\ \\ \udfff \\ \udffe \\ \udffd " ),
240+ ('\\ \\ \udfff \\ \udffe ' , '\\ ' , '\udffd ' ))
241+ if sys .platform == 'win32' :
242+ self .assertRaises (UnicodeDecodeError , splitroot , b'\\ \\ \xff \\ share\\ dir' )
243+ self .assertRaises (UnicodeDecodeError , splitroot , b'\\ \\ server\\ \xff \\ dir' )
244+ self .assertRaises (UnicodeDecodeError , splitroot , b'\\ \\ server\\ share\\ \xff ' )
245+ else :
246+ self .assertEqual (splitroot (b'\\ \\ \xff \\ \xfe \\ \xfd ' ),
247+ (b'\\ \\ \xff \\ \xfe ' , b'\\ ' , b'\xfd ' ))
248+
217249 def test_split (self ):
218250 tester ('ntpath.split("c:\\ foo\\ bar")' , ('c:\\ foo' , 'bar' ))
219251 tester ('ntpath.split("\\ \\ conky\\ mountpoint\\ foo\\ bar")' ,
@@ -226,6 +258,21 @@ def test_split(self):
226258 tester ('ntpath.split("c:/")' , ('c:/' , '' ))
227259 tester ('ntpath.split("//conky/mountpoint/")' , ('//conky/mountpoint/' , '' ))
228260
261+ def test_split_invalid_paths (self ):
262+ split = ntpath .split
263+ self .assertEqual (split ('c:\\ fo\x00 o\\ ba\x00 r' ),
264+ ('c:\\ fo\x00 o' , 'ba\x00 r' ))
265+ self .assertEqual (split (b'c:\\ fo\x00 o\\ ba\x00 r' ),
266+ (b'c:\\ fo\x00 o' , b'ba\x00 r' ))
267+ self .assertEqual (split ('c:\\ \udfff \\ \udffe ' ),
268+ ('c:\\ \udfff ' , '\udffe ' ))
269+ if sys .platform == 'win32' :
270+ self .assertRaises (UnicodeDecodeError , split , b'c:\\ \xff \\ bar' )
271+ self .assertRaises (UnicodeDecodeError , split , b'c:\\ foo\\ \xff ' )
272+ else :
273+ self .assertEqual (split (b'c:\\ \xff \\ \xfe ' ),
274+ (b'c:\\ \xff ' , b'\xfe ' ))
275+
229276 def test_isabs (self ):
230277 tester ('ntpath.isabs("foo\\ bar")' , 0 )
231278 tester ('ntpath.isabs("foo/bar")' , 0 )
@@ -333,6 +380,30 @@ def test_join(self):
333380 tester ("ntpath.join('D:a', './c:b')" , 'D:a\\ .\\ c:b' )
334381 tester ("ntpath.join('D:/a', './c:b')" , 'D:\\ a\\ .\\ c:b' )
335382
383+ def test_normcase (self ):
384+ normcase = ntpath .normcase
385+ self .assertEqual (normcase ('' ), '' )
386+ self .assertEqual (normcase (b'' ), b'' )
387+ self .assertEqual (normcase ('ABC' ), 'abc' )
388+ self .assertEqual (normcase (b'ABC' ), b'abc' )
389+ self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' ), '\xe4 \u0142 \u03c8 ' )
390+ expected = '\u03c9 \u2126 ' if sys .platform == 'win32' else '\u03c9 \u03c9 '
391+ self .assertEqual (normcase ('\u03a9 \u2126 ' ), expected )
392+ if sys .platform == 'win32' or sys .getfilesystemencoding () == 'utf-8' :
393+ self .assertEqual (normcase ('\xc4 \u0141 \u03a8 ' .encode ()),
394+ '\xe4 \u0142 \u03c8 ' .encode ())
395+ self .assertEqual (normcase ('\u03a9 \u2126 ' .encode ()),
396+ expected .encode ())
397+
398+ def test_normcase_invalid_paths (self ):
399+ normcase = ntpath .normcase
400+ self .assertEqual (normcase ('abc\x00 def' ), 'abc\x00 def' )
401+ self .assertEqual (normcase (b'abc\x00 def' ), b'abc\x00 def' )
402+ self .assertEqual (normcase ('\udfff ' ), '\udfff ' )
403+ if sys .platform == 'win32' :
404+ path = b'ABC' + bytes (range (128 , 256 ))
405+ self .assertEqual (normcase (path ), path .lower ())
406+
336407 def test_normpath (self ):
337408 tester ("ntpath.normpath('A//////././//.//B')" , r'A\B' )
338409 tester ("ntpath.normpath('A/./B')" , r'A\B' )
@@ -381,6 +452,21 @@ def test_normpath(self):
381452 tester ("ntpath.normpath('\\ \\ ')" , '\\ \\ ' )
382453 tester ("ntpath.normpath('//?/UNC/server/share/..')" , '\\ \\ ?\\ UNC\\ server\\ share\\ ' )
383454
455+ def test_normpath_invalid_paths (self ):
456+ normpath = ntpath .normpath
457+ self .assertEqual (normpath ('fo\x00 o' ), 'fo\x00 o' )
458+ self .assertEqual (normpath (b'fo\x00 o' ), b'fo\x00 o' )
459+ self .assertEqual (normpath ('fo\x00 o\\ ..\\ bar' ), 'bar' )
460+ self .assertEqual (normpath (b'fo\x00 o\\ ..\\ bar' ), b'bar' )
461+ self .assertEqual (normpath ('\udfff ' ), '\udfff ' )
462+ self .assertEqual (normpath ('\udfff \\ ..\\ foo' ), 'foo' )
463+ if sys .platform == 'win32' :
464+ self .assertRaises (UnicodeDecodeError , normpath , b'\xff ' )
465+ self .assertRaises (UnicodeDecodeError , normpath , b'\xff \\ ..\\ foo' )
466+ else :
467+ self .assertEqual (normpath (b'\xff ' ), b'\xff ' )
468+ self .assertEqual (normpath (b'\xff \\ ..\\ foo' ), b'foo' )
469+
384470 def test_realpath_curdir (self ):
385471 expected = ntpath .normpath (os .getcwd ())
386472 tester ("ntpath.realpath('.')" , expected )
@@ -420,10 +506,6 @@ def test_realpath_basic(self):
420506 d = drives .pop ().encode ()
421507 self .assertEqual (ntpath .realpath (d ), d )
422508
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-
427509 @os_helper .skip_unless_symlink
428510 @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
429511 def test_realpath_strict (self ):
@@ -434,8 +516,51 @@ def test_realpath_strict(self):
434516 self .addCleanup (os_helper .unlink , ABSTFN )
435517 self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN , strict = True )
436518 self .assertRaises (FileNotFoundError , ntpath .realpath , ABSTFN + "2" , strict = True )
519+
520+ @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
521+ def test_realpath_invalid_paths (self ):
522+ realpath = ntpath .realpath
523+ ABSTFN = ntpath .abspath (os_helper .TESTFN )
524+ ABSTFNb = os .fsencode (ABSTFN )
525+ path = ABSTFN + '\x00 '
526+ # gh-106242: Embedded nulls and non-strict fallback to abspath
527+ self .assertEqual (realpath (path , strict = False ), path )
437528 # gh-106242: Embedded nulls should raise OSError (not ValueError)
438- self .assertRaises (OSError , ntpath .realpath , ABSTFN + "\0 spam" , strict = True )
529+ self .assertRaises (OSError , realpath , path , strict = True )
530+ path = ABSTFNb + b'\x00 '
531+ self .assertEqual (realpath (path , strict = False ), path )
532+ self .assertRaises (OSError , realpath , path , strict = True )
533+ path = ABSTFN + '\\ nonexistent\\ x\x00 '
534+ self .assertEqual (realpath (path , strict = False ), path )
535+ self .assertRaises (OSError , realpath , path , strict = True )
536+ path = ABSTFNb + b'\\ nonexistent\\ x\x00 '
537+ self .assertEqual (realpath (path , strict = False ), path )
538+ self .assertRaises (OSError , realpath , path , strict = True )
539+ path = ABSTFN + '\x00 \\ ..'
540+ self .assertEqual (realpath (path , strict = False ), os .getcwd ())
541+ self .assertEqual (realpath (path , strict = True ), os .getcwd ())
542+ path = ABSTFNb + b'\x00 \\ ..'
543+ self .assertEqual (realpath (path , strict = False ), os .getcwdb ())
544+ self .assertEqual (realpath (path , strict = True ), os .getcwdb ())
545+ path = ABSTFN + '\\ nonexistent\\ x\x00 \\ ..'
546+ self .assertEqual (realpath (path , strict = False ), ABSTFN + '\\ nonexistent' )
547+ self .assertRaises (OSError , realpath , path , strict = True )
548+ path = ABSTFNb + b'\\ nonexistent\\ x\x00 \\ ..'
549+ self .assertEqual (realpath (path , strict = False ), ABSTFNb + b'\\ nonexistent' )
550+ self .assertRaises (OSError , realpath , path , strict = True )
551+
552+ path = ABSTFNb + b'\xff '
553+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
554+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
555+ path = ABSTFNb + b'\\ nonexistent\\ \xff '
556+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
557+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
558+ path = ABSTFNb + b'\xff \\ ..'
559+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
560+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
561+ path = ABSTFNb + b'\\ nonexistent\\ \xff \\ ..'
562+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = False )
563+ self .assertRaises (UnicodeDecodeError , realpath , path , strict = True )
439564
440565 @os_helper .skip_unless_symlink
441566 @unittest .skipUnless (HAVE_GETFINALPATHNAME , 'need _getfinalpathname' )
@@ -812,8 +937,6 @@ def test_abspath(self):
812937 tester ('ntpath.abspath("C:/nul")' , "\\ \\ .\\ nul" )
813938 tester ('ntpath.abspath("C:\\ nul")' , "\\ \\ .\\ nul" )
814939 self .assertTrue (ntpath .isabs (ntpath .abspath ("C:spam" )))
815- self .assertEqual (ntpath .abspath ("C:\x00 " ), ntpath .join (ntpath .abspath ("C:" ), "\x00 " ))
816- self .assertEqual (ntpath .abspath ("\x00 :spam" ), "\x00 :\\ spam" )
817940 tester ('ntpath.abspath("//..")' , "\\ \\ " )
818941 tester ('ntpath.abspath("//../")' , "\\ \\ ..\\ " )
819942 tester ('ntpath.abspath("//../..")' , "\\ \\ ..\\ " )
@@ -847,6 +970,26 @@ def test_abspath(self):
847970 drive , _ = ntpath .splitdrive (cwd_dir )
848971 tester ('ntpath.abspath("/abc/")' , drive + "\\ abc" )
849972
973+ def test_abspath_invalid_paths (self ):
974+ abspath = ntpath .abspath
975+ if sys .platform == 'win32' :
976+ self .assertEqual (abspath ("C:\x00 " ), ntpath .join (abspath ("C:" ), "\x00 " ))
977+ self .assertEqual (abspath (b"C:\x00 " ), ntpath .join (abspath (b"C:" ), b"\x00 " ))
978+ self .assertEqual (abspath ("\x00 :spam" ), "\x00 :\\ spam" )
979+ self .assertEqual (abspath (b"\x00 :spam" ), b"\x00 :\\ spam" )
980+ self .assertEqual (abspath ('c:\\ fo\x00 o' ), 'c:\\ fo\x00 o' )
981+ self .assertEqual (abspath (b'c:\\ fo\x00 o' ), b'c:\\ fo\x00 o' )
982+ self .assertEqual (abspath ('c:\\ fo\x00 o\\ ..\\ bar' ), 'c:\\ bar' )
983+ self .assertEqual (abspath (b'c:\\ fo\x00 o\\ ..\\ bar' ), b'c:\\ bar' )
984+ self .assertEqual (abspath ('c:\\ \udfff ' ), 'c:\\ \udfff ' )
985+ self .assertEqual (abspath ('c:\\ \udfff \\ ..\\ foo' ), 'c:\\ foo' )
986+ if sys .platform == 'win32' :
987+ self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff ' )
988+ self .assertRaises (UnicodeDecodeError , abspath , b'c:\\ \xff \\ ..\\ foo' )
989+ else :
990+ self .assertEqual (abspath (b'c:\\ \xff ' ), b'c:\\ \xff ' )
991+ self .assertEqual (abspath (b'c:\\ \xff \\ ..\\ foo' ), b'c:\\ foo' )
992+
850993 def test_relpath (self ):
851994 tester ('ntpath.relpath("a")' , 'a' )
852995 tester ('ntpath.relpath(ntpath.abspath("a"))' , 'a' )
@@ -990,6 +1133,18 @@ def test_ismount(self):
9901133 self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$" ))
9911134 self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$\\ " ))
9921135
1136+ def test_ismount_invalid_paths (self ):
1137+ ismount = ntpath .ismount
1138+ self .assertFalse (ismount ("c:\\ \udfff " ))
1139+ if sys .platform == 'win32' :
1140+ self .assertRaises (ValueError , ismount , "c:\\ \x00 " )
1141+ self .assertRaises (ValueError , ismount , b"c:\\ \x00 " )
1142+ self .assertRaises (UnicodeDecodeError , ismount , b"c:\\ \xff " )
1143+ else :
1144+ self .assertFalse (ismount ("c:\\ \x00 " ))
1145+ self .assertFalse (ismount (b"c:\\ \x00 " ))
1146+ self .assertFalse (ismount (b"c:\\ \xff " ))
1147+
9931148 def test_isreserved (self ):
9941149 self .assertFalse (ntpath .isreserved ('' ))
9951150 self .assertFalse (ntpath .isreserved ('.' ))
@@ -1096,6 +1251,13 @@ def test_isjunction(self):
10961251 self .assertFalse (ntpath .isjunction ('tmpdir' ))
10971252 self .assertPathEqual (ntpath .realpath ('testjunc' ), ntpath .realpath ('tmpdir' ))
10981253
1254+ def test_isfile_invalid_paths (self ):
1255+ isfile = ntpath .isfile
1256+ self .assertIs (isfile ('/tmp\udfff abcds' ), False )
1257+ self .assertIs (isfile (b'/tmp\xff abcds' ), False )
1258+ self .assertIs (isfile ('/tmp\x00 abcds' ), False )
1259+ self .assertIs (isfile (b'/tmp\x00 abcds' ), False )
1260+
10991261 @unittest .skipIf (sys .platform != 'win32' , "drive letters are a windows concept" )
11001262 def test_isfile_driveletter (self ):
11011263 drive = os .environ .get ('SystemDrive' )
@@ -1196,9 +1358,6 @@ def _check_function(self, func):
11961358
11971359 def test_path_normcase (self ):
11981360 self ._check_function (self .path .normcase )
1199- if sys .platform == 'win32' :
1200- self .assertEqual (ntpath .normcase ('\u03a9 \u2126 ' ), 'ωΩ' )
1201- self .assertEqual (ntpath .normcase ('abc\x00 def' ), 'abc\x00 def' )
12021361
12031362 def test_path_isabs (self ):
12041363 self ._check_function (self .path .isabs )
0 commit comments