@@ -15,6 +15,13 @@ use std::ptr;
15
15
use std:: rc:: Rc ;
16
16
use std:: sync:: Arc ;
17
17
18
+ #[ cfg( unix) ]
19
+ use std:: os:: unix:: ffi:: OsStrExt ;
20
+ #[ cfg( windows) ]
21
+ use std:: os:: windows:: ffi:: OsStrExt ;
22
+ #[ cfg( windows) ]
23
+ use std:: os:: windows:: ffi:: OsStringExt ;
24
+
18
25
#[ allow( unknown_lints, unused_macro_rules) ]
19
26
macro_rules! t (
20
27
( $path: expr, iter: $iter: expr) => (
@@ -1235,7 +1242,7 @@ pub fn test_push() {
1235
1242
tp ! ( "foo//" , "bar" , r"foo//bar" ) ;
1236
1243
tp ! ( r"foo\\" , "bar" , r"foo\\bar" ) ;
1237
1244
tp ! ( "foo/." , "bar" , r"foo/.\bar" ) ;
1238
- tp ! ( "foo./." , "bar" , r"foo./.\ bar" ) ;
1245
+ tp ! ( "foo./." , "bar" , r"foo././ bar" ) ;
1239
1246
tp ! ( r"foo\." , "bar" , r"foo\.\bar" ) ;
1240
1247
tp ! ( r"foo.\." , "bar" , r"foo.\.\bar" ) ;
1241
1248
tp ! ( "foo" , "" , "foo\\ " ) ;
@@ -1976,3 +1983,102 @@ fn clone_to_uninit() {
1976
1983
unsafe { a. clone_to_uninit ( ptr:: from_mut :: < Path > ( & mut b) . cast ( ) ) } ;
1977
1984
assert_eq ! ( a, & * b) ;
1978
1985
}
1986
+
1987
+ // Test: Only separators (e.g., "/" or "\\")
1988
+ // This test checks how Path handles a string that consists only of path separators.
1989
+ // It should recognize the root and not treat it as a normal component.
1990
+ #[ test]
1991
+ fn test_only_separators ( ) {
1992
+ let path = Path :: new ( "/////" ) ;
1993
+ assert ! ( path. has_root( ) ) ;
1994
+ assert_eq ! ( path. iter( ) . count( ) , 1 ) ;
1995
+ assert_eq ! ( path. parent( ) , None ) ;
1996
+ }
1997
+
1998
+ // Test: Non-ASCII/Unicode
1999
+ // This test verifies that Path can handle Unicode and non-ASCII characters in the path.
2000
+ // It ensures that such paths are not rejected or misinterpreted.
2001
+ #[ test]
2002
+ fn test_non_ascii_unicode ( ) {
2003
+ let path = Path :: new ( "/tmp/❤/🚀/file.txt" ) ;
2004
+ assert ! ( path. to_str( ) . is_some( ) ) ;
2005
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( "file.txt" ) ) ) ;
2006
+ }
2007
+
2008
+ // Test: Embedded null bytes
2009
+ // This test checks that Path can be constructed from a byte slice containing a null byte (on Unix).
2010
+ // It ensures that null bytes are not treated as string terminators.
2011
+ #[ test]
2012
+ fn test_embedded_null_byte ( ) {
2013
+ use std:: ffi:: OsStr ;
2014
+ let bytes = b"foo\0 bar" ;
2015
+ let os_str = OsStr :: from_bytes ( bytes) ;
2016
+ let path = Path :: new ( os_str) ;
2017
+ assert ! ( path. as_os_str( ) . as_bytes( ) . contains( & 0 ) ) ;
2018
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( "foo\0 bar" ) ) ) ;
2019
+ assert_eq ! ( path. to_str( ) , Some ( "foo\0 bar" ) ) ;
2020
+ }
2021
+
2022
+ // Test: Reserved device names (Windows)
2023
+ // This test ensures that reserved device names like "CON", "PRN", etc., are handled as normal paths on non-Windows platforms,
2024
+ // and as special cases on Windows (if applicable).
2025
+ #[ test]
2026
+ #[ cfg( windows) ]
2027
+ fn test_reserved_device_names ( ) {
2028
+ for & name in & [ "CON" , "PRN" , "AUX" , "NUL" , "COM1" , "LPT1" ] {
2029
+ let path = Path :: new ( name) ;
2030
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( name) ) ) ;
2031
+ assert_eq ! ( path. extension( ) , None ) ;
2032
+ }
2033
+ }
2034
+
2035
+ // Test: Trailing dots/spaces (Windows)
2036
+ // This test checks how Path handles trailing dots or spaces, which are special on Windows.
2037
+ // On Unix, these should be treated as normal characters.
2038
+ #[ test]
2039
+ #[ cfg( windows) ]
2040
+ fn test_trailing_dots_and_spaces ( ) {
2041
+ let path = Path :: new ( "foo. " ) ;
2042
+ assert_eq ! ( path. file_stem( ) , Some ( OsStr :: new( "foo" ) ) ) ;
2043
+ assert_eq ! ( path. extension( ) , Some ( OsStr :: new( " " ) ) ) ;
2044
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( "foo. " ) ) ) ;
2045
+ assert_eq ! ( path. to_str( ) , Some ( "foo. " ) ) ;
2046
+ let path = Path :: new ( "bar..." ) ;
2047
+ assert_eq ! ( path. file_stem( ) , Some ( OsStr :: new( "bar" ) ) ) ;
2048
+ assert_eq ! ( path. extension( ) , Some ( OsStr :: new( "..." ) ) ) ;
2049
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( "bar..." ) ) ) ;
2050
+ assert_eq ! ( path. to_str( ) , Some ( "bar..." ) ) ;
2051
+ }
2052
+
2053
+ // Test: Only extension (e.g., ".gitignore")
2054
+ // This test verifies that files with only an extension and no base name are handled correctly.
2055
+ // It checks that the extension is recognized and the file stem is None or empty as appropriate.
2056
+ #[ test]
2057
+ fn test_only_extension ( ) {
2058
+ let path = Path :: new ( ".ext" ) ;
2059
+ assert_eq ! ( path. extension( ) , None ) ;
2060
+ assert_eq ! ( path. file_stem( ) , Some ( OsStr :: new( ".ext" ) ) ) ;
2061
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( ".ext" ) ) ) ;
2062
+ }
2063
+
2064
+ // Test: Long components
2065
+ // This test checks that Path can handle very long path components without truncation or error.
2066
+ // It ensures that the length of the component is preserved.
2067
+ #[ test]
2068
+ fn test_long_component ( ) {
2069
+ let long = "a" . repeat ( 300 ) ;
2070
+ let path = Path :: new ( & long) ;
2071
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( & long) ) ) ;
2072
+ assert_eq ! ( path. to_str( ) , Some ( long. as_str( ) ) ) ;
2073
+ assert_eq ! ( path. iter( ) . count( ) , 1 ) ;
2074
+ }
2075
+
2076
+ // Test: Embedded newlines
2077
+ // This test verifies that newlines within path components are preserved and do not break path parsing.
2078
+ // It ensures that Path treats newlines as normal characters.
2079
+ #[ test]
2080
+ fn test_embedded_newline ( ) {
2081
+ let path = Path :: new ( "foo\n bar" ) ;
2082
+ assert_eq ! ( path. file_name( ) , Some ( OsStr :: new( "foo\n bar" ) ) ) ;
2083
+ assert_eq ! ( path. to_str( ) , Some ( "foo\n bar" ) ) ;
2084
+ }
0 commit comments