#[test]
fn join_components_with_forward_slashes_tests() {
struct Case {
input: &'static str,
expected: &'static str,
}
const VALID_TEST_CASES: &[Case] = &[
Case {
input: r#"/"#,
expected: "/",
},
Case {
input: r#"//"#,
expected: "/",
},
Case {
input: r#"\"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"/"
} else {
r#"\"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"/"
} else {
r#"\\"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"/foo"
} else {
r#"\\foo"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\foo\bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//foo/bar/" // UNC with implied root
} else {
r#"\\foo\bar"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"//foo"#,
expected: "/foo", // Redundant slash removed.
},
Case {
input: r#"//foo/bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//foo/bar/" // UNC with implied root
} else {
"/foo/bar"
},
},
Case {
input: r#"\\server\share"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC with implied root
} else {
r#"\\server\share"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\server\share\"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC
} else {
r#"\\server\share\"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\server\share\foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo" // UNC
} else {
r#"\\server\share\foo"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"\\server\share\foo\bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
r#"\\server\share\foo\bar"# // Backslash not interpreted as a separator
},
},
Case {
// XXX: trailing slash stripped
input: r#"\\server\share\foo\bar\"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
r#"\\server\share\foo\bar\"# // Backslash not interpreted as a separator
},
},
Case {
input: r#"//server/share"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC with implied root
} else {
r#"/server/share"# // Redundant slash removed.
},
},
Case {
input: r#"//server/share/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC
} else {
r#"/server/share"# // Redundant slash removed. XXX: trailing slash stripped.
},
},
Case {
input: r#"//server/share/foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo" // UNC
} else {
// Redundant slash removed.
"/server/share/foo"
},
},
Case {
input: r#"//server/share/foo/bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
r#"/server/share/foo/bar"#
}, // Redundant slash removed.
},
Case {
// XXX: trailing slash stripped
input: r#"//server/share/foo/bar/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
r#"/server/share/foo/bar"# // Redundant slash removed.
},
},
Case {
input: r#"//server\share"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC with implied root
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server\share"#
},
},
Case {
input: r#"//server\share/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
// XXX: trailing slash stripped.
r#"/server\share"#
},
},
Case {
input: r#"//server\share/foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server\share/foo"#
},
},
Case {
input: r#"//server\share/foo/bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server\share/foo/bar"#
},
},
Case {
// XXX: trailing slash stripped
input: r#"//server\share/foo/bar/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server\share/foo/bar"#
},
},
Case {
input: r#"\\server\share"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC with implied root
} else {
// Backslash not interpreted as a separator.
r#"\\server\share"#
},
},
Case {
input: r#"\\server\share/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC
} else {
// Backslash not interpreted as a separator.
// XXX: trailing slash stripped.
r#"\\server\share"#
},
},
Case {
input: r#"\\server\share/foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo" // UNC
} else {
// Backslash not interpreted as a separator.
r#"\\server\share/foo"#
},
},
Case {
input: r#"\\server\share/foo/bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
// Backslash not interpreted as a separator.
r#"\\server\share/foo/bar"#
},
},
Case {
// XXX: trailing slash stripped
input: r#"\\server\share/foo/bar/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
// Backslash not interpreted as a separator.
r#"\\server\share/foo/bar"#
},
},
Case {
input: r#"//server/share\"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server/share\"#
},
},
Case {
input: r#"//server/share\foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server/share\foo"#
},
},
Case {
input: r#"//server/share/foo\bar"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar" // UNC
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server/share/foo\bar"#
},
},
Case {
// XXX: trailing slash stripped
input: r#"//server/share\foo/bar/"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"//server/share/foo/bar"
} else {
// Redundant slash removed. Backslash not interpreted as a separator.
r#"/server/share\foo/bar"#
},
},
Case {
input: r#"C:foo"#,
expected: "C:foo",
},
Case {
input: r#"C:\foo"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"C:/foo"
} else {
r#"C:\foo"# // Backslash not interpreted as a separator.
},
},
Case {
input: r#"C:/foo"#,
expected: "C:/foo",
},
Case {
input: r#"a\b"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"a/b"
} else {
r#"a\b"# // Backslash not interpreted as a separator.
},
},
Case {
input: r#"/a/b"#,
expected: "/a/b",
},
Case {
input: r#"\a\b"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"/a/b"
} else {
r#"\a\b"# // Backslash not interpreted as a separator.
},
},
Case {
input: r#".\b"#,
expected: if TARGET_SUPPORTS_UNCS_AND_BACKSLASHES {
"./b"
} else {
r#".\b"# // Backslash not interpreted as a separator.
},
},
Case {
input: r#"../b"#,
expected: "../b",
},
Case {
input: r#"a/../b"#,
expected: "a/../b",
},
Case {
// XXX: Trailing slash is skipped.
input: r#"a/./b/"#,
expected: "a/b",
},
];
let failures = VALID_TEST_CASES
.iter()
.filter_map(|Case { input, expected }| {
let actual = join_components_with_forward_slashes(Path::new(input)).unwrap();
if actual == AsRef::<OsStr>::as_ref(expected) {
None
} else {
Some((input, actual, expected))
}
})
.collect::<Vec<_>>();
assert_eq!(failures, &[]);
}
in briansmith/ring#2730 (comment), @500-internal-server-error wrote:
rustc -vV:Interestingly, It seems to parse the backslash form like Windows, which seems like a bug as well; presumably Cygwin shouldn't be accepting backslashes as a path separator.
I noticed that it processes the inputr#"//foo/bar"#correctly!Reading the source code, I speculate that this is related to the 8-byte "prefix" buffer In the prefix parser, as "//server/path" has the third slash as the 9th byte whereas "//foo/bar" has it within 8 bytes.Edit: I misread the test results.
r#"//foo/bar"#is also parsed incorrectly.Here are several test vectors that you are happy to modify and incorporate under the standard Apache/MIT license. Note that these tests are actually testing a wrapper that replaces path separators with '/' so they can't be used as-is, but these tests are what found the issue.
Details