1use alloc::string::String;
4
5pub fn canonicalize(path: &str) -> String {
20 let mut buf = String::new();
21 let is_absolute = path.starts_with('/');
22 for part in path.split('/') {
23 match part {
24 "" | "." => continue,
25 ".." => {
26 while !buf.is_empty() {
27 if buf == "/" {
28 break;
29 }
30 let c = buf.pop().unwrap();
31 if c == '/' {
32 break;
33 }
34 }
35 }
36 _ => {
37 if buf.is_empty() {
38 if is_absolute {
39 buf.push('/');
40 }
41 } else if &buf[buf.len() - 1..] != "/" {
42 buf.push('/');
43 }
44 buf.push_str(part);
45 }
46 }
47 }
48 if is_absolute && buf.is_empty() {
49 buf.push('/');
50 }
51 buf
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn test_path_canonicalize() {
60 assert_eq!(canonicalize(""), "");
61 assert_eq!(canonicalize("///"), "/");
62 assert_eq!(canonicalize("//a//.//b///c//"), "/a/b/c");
63 assert_eq!(canonicalize("/a/../"), "/");
64 assert_eq!(canonicalize("/a/../..///"), "/");
65 assert_eq!(canonicalize("a/../"), "");
66 assert_eq!(canonicalize("a/..//.."), "");
67 assert_eq!(canonicalize("././a"), "a");
68 assert_eq!(canonicalize(".././a"), "a");
69 assert_eq!(canonicalize("/././a"), "/a");
70 assert_eq!(canonicalize("/abc/../abc"), "/abc");
71 assert_eq!(canonicalize("/test"), "/test");
72 assert_eq!(canonicalize("/test/"), "/test");
73 assert_eq!(canonicalize("test/"), "test");
74 assert_eq!(canonicalize("test"), "test");
75 assert_eq!(canonicalize("/test//"), "/test");
76 assert_eq!(canonicalize("/test/foo"), "/test/foo");
77 assert_eq!(canonicalize("/test/foo/"), "/test/foo");
78 assert_eq!(canonicalize("/test/foo/bar"), "/test/foo/bar");
79 assert_eq!(canonicalize("/test/foo/bar//"), "/test/foo/bar");
80 assert_eq!(canonicalize("/test//foo/bar//"), "/test/foo/bar");
81 assert_eq!(canonicalize("/test//./foo/bar//"), "/test/foo/bar");
82 assert_eq!(canonicalize("/test//./.foo/bar//"), "/test/.foo/bar");
83 assert_eq!(canonicalize("/test//./..foo/bar//"), "/test/..foo/bar");
84 assert_eq!(canonicalize("/test//./../foo/bar//"), "/foo/bar");
85 assert_eq!(canonicalize("/test/../foo"), "/foo");
86 assert_eq!(canonicalize("/test/bar/../foo"), "/test/foo");
87 assert_eq!(canonicalize("../foo"), "foo");
88 assert_eq!(canonicalize("../foo/"), "foo");
89 assert_eq!(canonicalize("/../foo"), "/foo");
90 assert_eq!(canonicalize("/../foo/"), "/foo");
91 assert_eq!(canonicalize("/../../foo"), "/foo");
92 assert_eq!(canonicalize("/bleh/../../foo"), "/foo");
93 assert_eq!(canonicalize("/bleh/bar/../../foo"), "/foo");
94 assert_eq!(canonicalize("/bleh/bar/../../foo/.."), "/");
95 assert_eq!(canonicalize("/bleh/bar/../../foo/../meh"), "/meh");
96 }
97}