@@ -124,6 +124,22 @@ def test_splitdrive(self):
124
124
tester ('ntpath.splitdrive("//?/UNC/server/share/dir")' ,
125
125
("//?/UNC/server/share" ,"/dir" ))
126
126
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
+
127
143
def test_splitroot (self ):
128
144
tester ("ntpath.splitroot('')" , ('' ,'' ,'' ))
129
145
tester ("ntpath.splitroot('foo')" , ('' ,'' ,'foo' ))
@@ -214,6 +230,22 @@ def test_splitroot(self):
214
230
tester ('ntpath.splitroot(" :/foo")' , (" :" ,"/" ,"foo" ))
215
231
tester ('ntpath.splitroot("/:/foo")' , ("" ,"/" ,":/foo" ))
216
232
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
+
217
249
def test_split (self ):
218
250
tester ('ntpath.split("c:\\ foo\\ bar")' , ('c:\\ foo' ,'bar' ))
219
251
tester ('ntpath.split("\\ \\ conky\\ mountpoint\\ foo\\ bar")' ,
@@ -226,6 +258,21 @@ def test_split(self):
226
258
tester ('ntpath.split("c:/")' , ('c:/' ,'' ))
227
259
tester ('ntpath.split("//conky/mountpoint/")' , ('//conky/mountpoint/' ,'' ))
228
260
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
+
229
276
def test_isabs (self ):
230
277
tester ('ntpath.isabs("foo\\ bar")' ,0 )
231
278
tester ('ntpath.isabs("foo/bar")' ,0 )
@@ -333,6 +380,30 @@ def test_join(self):
333
380
tester ("ntpath.join('D:a', './c:b')" ,'D:a\\ .\\ c:b' )
334
381
tester ("ntpath.join('D:/a', './c:b')" ,'D:\\ a\\ .\\ c:b' )
335
382
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
+
336
407
def test_normpath (self ):
337
408
tester ("ntpath.normpath('A//////././//.//B')" ,r'A\B' )
338
409
tester ("ntpath.normpath('A/./B')" ,r'A\B' )
@@ -381,6 +452,21 @@ def test_normpath(self):
381
452
tester ("ntpath.normpath('\\ \\ ')" ,'\\ \\ ' )
382
453
tester ("ntpath.normpath('//?/UNC/server/share/..')" ,'\\ \\ ?\\ UNC\\ server\\ share\\ ' )
383
454
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
+
384
470
def test_realpath_curdir (self ):
385
471
expected = ntpath .normpath (os .getcwd ())
386
472
tester ("ntpath.realpath('.')" ,expected )
@@ -420,10 +506,6 @@ def test_realpath_basic(self):
420
506
d = drives .pop ().encode ()
421
507
self .assertEqual (ntpath .realpath (d ),d )
422
508
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
-
427
509
@os_helper .skip_unless_symlink
428
510
@unittest .skipUnless (HAVE_GETFINALPATHNAME ,'need _getfinalpathname' )
429
511
def test_realpath_strict (self ):
@@ -434,8 +516,51 @@ def test_realpath_strict(self):
434
516
self .addCleanup (os_helper .unlink ,ABSTFN )
435
517
self .assertRaises (FileNotFoundError ,ntpath .realpath ,ABSTFN ,strict = True )
436
518
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 )
437
528
# 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 )
439
564
440
565
@os_helper .skip_unless_symlink
441
566
@unittest .skipUnless (HAVE_GETFINALPATHNAME ,'need _getfinalpathname' )
@@ -812,8 +937,6 @@ def test_abspath(self):
812
937
tester ('ntpath.abspath("C:/nul")' ,"\\ \\ .\\ nul" )
813
938
tester ('ntpath.abspath("C:\\ nul")' ,"\\ \\ .\\ nul" )
814
939
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" )
817
940
tester ('ntpath.abspath("//..")' ,"\\ \\ " )
818
941
tester ('ntpath.abspath("//../")' ,"\\ \\ ..\\ " )
819
942
tester ('ntpath.abspath("//../..")' ,"\\ \\ ..\\ " )
@@ -847,6 +970,26 @@ def test_abspath(self):
847
970
drive ,_ = ntpath .splitdrive (cwd_dir )
848
971
tester ('ntpath.abspath("/abc/")' ,drive + "\\ abc" )
849
972
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
+
850
993
def test_relpath (self ):
851
994
tester ('ntpath.relpath("a")' ,'a' )
852
995
tester ('ntpath.relpath(ntpath.abspath("a"))' ,'a' )
@@ -989,6 +1132,18 @@ def test_ismount(self):
989
1132
self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$" ))
990
1133
self .assertTrue (ntpath .ismount (b"\\ \\ localhost\\ c$\\ " ))
991
1134
1135
+ def test_ismount_invalid_paths (self ):
1136
+ ismount = ntpath .ismount
1137
+ self .assertFalse (ismount ("c:\\ \udfff " ))
1138
+ if sys .platform == 'win32' :
1139
+ self .assertRaises (ValueError ,ismount ,"c:\\ \x00 " )
1140
+ self .assertRaises (ValueError ,ismount ,b"c:\\ \x00 " )
1141
+ self .assertRaises (UnicodeDecodeError ,ismount ,b"c:\\ \xff " )
1142
+ else :
1143
+ self .assertFalse (ismount ("c:\\ \x00 " ))
1144
+ self .assertFalse (ismount (b"c:\\ \x00 " ))
1145
+ self .assertFalse (ismount (b"c:\\ \xff " ))
1146
+
992
1147
def test_isreserved (self ):
993
1148
self .assertFalse (ntpath .isreserved ('' ))
994
1149
self .assertFalse (ntpath .isreserved ('.' ))
@@ -1095,6 +1250,13 @@ def test_isjunction(self):
1095
1250
self .assertFalse (ntpath .isjunction ('tmpdir' ))
1096
1251
self .assertPathEqual (ntpath .realpath ('testjunc' ),ntpath .realpath ('tmpdir' ))
1097
1252
1253
+ def test_isfile_invalid_paths (self ):
1254
+ isfile = ntpath .isfile
1255
+ self .assertIs (isfile ('/tmp\udfff abcds' ),False )
1256
+ self .assertIs (isfile (b'/tmp\xff abcds' ),False )
1257
+ self .assertIs (isfile ('/tmp\x00 abcds' ),False )
1258
+ self .assertIs (isfile (b'/tmp\x00 abcds' ),False )
1259
+
1098
1260
@unittest .skipIf (sys .platform != 'win32' ,"drive letters are a windows concept" )
1099
1261
def test_isfile_driveletter (self ):
1100
1262
drive = os .environ .get ('SystemDrive' )
@@ -1195,9 +1357,6 @@ def _check_function(self, func):
1195
1357
1196
1358
def test_path_normcase (self ):
1197
1359
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' )
1201
1360
1202
1361
def test_path_isabs (self ):
1203
1362
self ._check_function (self .path .isabs )