Skip to content

Commit

Permalink
Fixed PathExt.normalize() on Windows
Browse files Browse the repository at this point in the history
  - Windows path prefixes and roots need to be handled in a particular
    way. Added logic to PathExt.normalize() to check that the number of
    segments being removed preserves these correctly.

  - Added Windows-specific tests for PathExt.normalize().
  • Loading branch information
danwilliams committed Nov 11, 2024
1 parent 4477bd2 commit c8a43ac
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
28 changes: 22 additions & 6 deletions crates/rubedo/src/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,12 +1337,18 @@ impl PathExt for Path {
return cwd;
}
let mut segments: Vec<OsString> = vec![];
let mut had_prefix = false;
let mut had_root = false;
for (i, component) in self.components().enumerate() {
match component {
PathComponent::Prefix(_) |
PathComponent::RootDir => {
if i == 0 {
PathComponent::Prefix(prefix) => {
segments.push(prefix.as_os_str().to_os_string());
had_prefix = true;
},
PathComponent::RootDir => {
if had_prefix || i == 0 {
segments.push(component.as_os_str().to_os_string());
had_root = true;
}
},
PathComponent::CurDir |
Expand All @@ -1355,8 +1361,11 @@ impl PathExt for Path {
.as_mut()
);
}
if component == PathComponent::ParentDir && segments.len() > 1 {
drop(segments.pop());
if component == PathComponent::ParentDir {
// Only pop if we have segments beyond the root components
if segments.len() > usize::from(had_prefix).saturating_add(usize::from(had_root)) {
drop(segments.pop());
}
}
},
PathComponent::Normal(_) => {
Expand Down Expand Up @@ -1430,7 +1439,14 @@ impl PathExt for Path {
},
}
}
segments.iter().collect()
if cfg!(windows) {
segments.iter()
.collect::<PathBuf>()
.to_str()
.map_or_else(PathBuf::new, |s| PathBuf::from(s.trim_start_matches('\\')))
} else {
segments.iter().collect()
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions crates/rubedo/src/tests/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,38 @@ mod path_ext {
path = PathBuf::from("tests/🥳.rs");
assert_eq!(path.normalize(), cwd.join("tests/🥳.rs"));

if cfg!(windows) {
path = PathBuf::from(r"C:\tests\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"C:\tests\std.rs"));

path = PathBuf::from(r"C:\tests\\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"C:\tests\std.rs"));

path = PathBuf::from(r"C:\tests\.\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"C:\tests\std.rs"));

path = PathBuf::from(r"C:\tests\..\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"C:\std.rs"));

path = PathBuf::from(r"C:\tests\..\..\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"C:\std.rs"));

path = PathBuf::from(r"\\SERVER\Share\tests\\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"\\SERVER\Share\tests\std.rs"));

path = PathBuf::from(r"\\SERVER\Share\tests\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"\\SERVER\Share\tests\std.rs"));

path = PathBuf::from(r"\\SERVER\Share\tests\.\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"\\SERVER\Share\tests\std.rs"));

path = PathBuf::from(r"\\SERVER\Share\tests\..\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"\\SERVER\Share\std.rs"));

path = PathBuf::from(r"\\SERVER\Share\tests\..\..\std.rs");
assert_eq!(path.normalize(), PathBuf::from(r"\\SERVER\Share\std.rs"));
}

let path2: &Path = Path::new("/tests/std.rs");
assert_eq!(path2.normalize(), Path::new("/tests/std.rs"));
assert_eq!(path2.normalize(), PathBuf::from("/tests/std.rs"));
Expand Down

0 comments on commit c8a43ac

Please sign in to comment.