mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 21:33:09 +00:00
Add tests for normalize_path and fix some bugs
This commit is contained in:
parent
33fd679f68
commit
dea18b34aa
2 changed files with 73 additions and 15 deletions
|
@ -6,6 +6,7 @@ mod wrealpath;
|
|||
|
||||
use std::io::Write;
|
||||
|
||||
use crate::wchar::{wstr, WString};
|
||||
pub(crate) use format::printf::sprintf;
|
||||
pub(crate) use gettext::{wgettext, wgettext_fmt};
|
||||
pub use normalize_path::*;
|
||||
|
@ -27,3 +28,30 @@ pub fn perror(s: &str) {
|
|||
let _ = stderr.write_all(slice);
|
||||
let _ = stderr.write_all(b"\n");
|
||||
}
|
||||
|
||||
/// Joins strings with a separator.
|
||||
pub fn join_strings(strs: &[&wstr], sep: char) -> WString {
|
||||
if strs.is_empty() {
|
||||
return WString::new();
|
||||
}
|
||||
let capacity = strs.iter().fold(0, |acc, s| acc + s.len()) + strs.len() - 1;
|
||||
let mut result = WString::with_capacity(capacity);
|
||||
for (i, s) in strs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
result.push(sep);
|
||||
}
|
||||
result.push_utfstr(s);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_join_strings() {
|
||||
use crate::wchar::L;
|
||||
assert_eq!(join_strings(&[], '/'), "");
|
||||
assert_eq!(join_strings(&[L!("foo")], '/'), "foo");
|
||||
assert_eq!(
|
||||
join_strings(&[L!("foo"), L!("bar"), L!("baz")], '/'),
|
||||
"foo/bar/baz"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
use std::iter::repeat;
|
||||
|
||||
use crate::wchar::{wstr, WString, L};
|
||||
use crate::wutil::join_strings;
|
||||
|
||||
/// Given an input path, "normalize" it:
|
||||
/// 1. Collapse multiple /s into a single /, except maybe at the beginning.
|
||||
/// 2. .. goes up a level.
|
||||
/// 3. Remove /./ in the middle.
|
||||
pub fn normalize_path(path: &wstr, allow_leading_double_slashes: bool) -> WString {
|
||||
// Count the leading slashes.
|
||||
let sep = '/';
|
||||
let mut leading_slashes: usize = 0;
|
||||
for (i, &c) in path.as_char_slice().iter().enumerate() {
|
||||
for c in path.chars() {
|
||||
if c != sep {
|
||||
leading_slashes = i;
|
||||
break;
|
||||
}
|
||||
leading_slashes += 1;
|
||||
}
|
||||
|
||||
let comps = path
|
||||
|
@ -20,11 +23,11 @@ pub fn normalize_path(path: &wstr, allow_leading_double_slashes: bool) -> WStrin
|
|||
.collect::<Vec<_>>();
|
||||
let mut new_comps = Vec::new();
|
||||
for comp in comps {
|
||||
if comp.is_empty() || comp == L!(".") {
|
||||
if comp.is_empty() || comp == "." {
|
||||
continue;
|
||||
} else if comp != L!("..") {
|
||||
} else if comp != ".." {
|
||||
new_comps.push(comp);
|
||||
} else if !new_comps.is_empty() && new_comps.last().map_or(L!(""), |&s| s) != L!("..") {
|
||||
} else if !new_comps.is_empty() && new_comps.last().unwrap() != ".." {
|
||||
// '..' with a real path component, drop that path component.
|
||||
new_comps.pop();
|
||||
} else if leading_slashes == 0 {
|
||||
|
@ -32,12 +35,7 @@ pub fn normalize_path(path: &wstr, allow_leading_double_slashes: bool) -> WStrin
|
|||
new_comps.push(L!(".."));
|
||||
}
|
||||
}
|
||||
let mut result = new_comps.into_iter().fold(Vec::new(), |mut acc, x| {
|
||||
acc.extend_from_slice(x.as_char_slice());
|
||||
acc.push('/');
|
||||
acc
|
||||
});
|
||||
result.pop();
|
||||
let mut result = join_strings(&new_comps, sep);
|
||||
// If we don't allow leading double slashes, collapse them to 1 if there are any.
|
||||
let mut numslashes = if leading_slashes > 0 { 1 } else { 0 };
|
||||
// If we do, prepend one or two leading slashes.
|
||||
|
@ -45,10 +43,42 @@ pub fn normalize_path(path: &wstr, allow_leading_double_slashes: bool) -> WStrin
|
|||
if allow_leading_double_slashes && leading_slashes == 2 {
|
||||
numslashes = 2;
|
||||
}
|
||||
result.splice(0..0, repeat(sep).take(numslashes));
|
||||
for _ in 0..numslashes {
|
||||
result.insert(0, sep);
|
||||
}
|
||||
// Ensure ./ normalizes to . and not empty.
|
||||
if result.is_empty() {
|
||||
result.push('.');
|
||||
}
|
||||
WString::from_chars(result)
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize_path() {
|
||||
fn norm_path(path: &wstr) -> WString {
|
||||
normalize_path(path, true)
|
||||
}
|
||||
assert_eq!(norm_path(L!("")), ".");
|
||||
assert_eq!(norm_path(L!("..")), "..");
|
||||
assert_eq!(norm_path(L!("./")), ".");
|
||||
assert_eq!(norm_path(L!("./.")), ".");
|
||||
assert_eq!(norm_path(L!("/")), "/");
|
||||
assert_eq!(norm_path(L!("//")), "//");
|
||||
assert_eq!(norm_path(L!("///")), "/");
|
||||
assert_eq!(norm_path(L!("////")), "/");
|
||||
assert_eq!(norm_path(L!("/.///")), "/");
|
||||
assert_eq!(norm_path(L!(".//")), ".");
|
||||
assert_eq!(norm_path(L!("/.//../")), "/");
|
||||
assert_eq!(norm_path(L!("////abc")), "/abc");
|
||||
assert_eq!(norm_path(L!("/abc")), "/abc");
|
||||
assert_eq!(norm_path(L!("/abc/")), "/abc");
|
||||
assert_eq!(norm_path(L!("/abc/..def/")), "/abc/..def");
|
||||
assert_eq!(norm_path(L!("//abc/../def/")), "//def");
|
||||
assert_eq!(norm_path(L!("abc/../abc/../abc/../abc")), "abc");
|
||||
assert_eq!(norm_path(L!("../../")), "../..");
|
||||
assert_eq!(norm_path(L!("foo/./bar")), "foo/bar");
|
||||
assert_eq!(norm_path(L!("foo/../")), ".");
|
||||
assert_eq!(norm_path(L!("foo/../foo")), "foo");
|
||||
assert_eq!(norm_path(L!("foo/../foo/")), "foo");
|
||||
assert_eq!(norm_path(L!("foo/././bar/.././baz")), "foo/baz");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue