macro_rules! mktests { ($name:ident, $input:expr, $expected:expr) => { #[test] fn $name() { let actual = gix_validate::reference::name_partial_or_sanitize($input.as_bstr()); assert_eq!(actual, $expected); assert!(gix_validate::reference::name_partial(actual.as_ref()).is_ok()); } };} mod name_partial { mod valid { use bstr::ByteSlice; macro_rules! mktest { ($name:ident, $input:expr) => { #[test] fn $name() { assert!(gix_validate::reference::name_partial($input.as_bstr()).is_ok()) } }; } mktest!(refs_path, b"refs/heads/main"); mktests!(refs_path_san, b"refs/heads/main", "refs/heads/main"); mktest!(main_worktree_pseudo_ref, b"main-worktree/HEAD"); mktests!( main_worktree_pseudo_ref_san, b"main-worktree/HEAD", "main-worktree/HEAD" ); mktest!(main_worktree_ref, b"main-worktree/refs/bisect/good"); mktests!( main_worktree_ref_san, b"main-worktree/refs/bisect/good", "main-worktree/refs/bisect/good" ); mktest!(other_worktree_pseudo_ref, b"worktrees/id/HEAD"); mktests!(other_worktree_pseudo_ref_san, b"worktrees/id/HEAD", "worktrees/id/HEAD"); mktest!(other_worktree_ref, b"worktrees/id/refs/bisect/good"); mktests!( other_worktree_ref_san, b"worktrees/id/refs/bisect/good", "worktrees/id/refs/bisect/good" ); mktest!(worktree_private_ref, b"refs/worktree/private"); mktests!( worktree_private_ref_san, b"refs/worktree/private", "refs/worktree/private" ); mktest!(refs_path_with_file_extension, b"refs/heads/main.ext"); mktests!( refs_path_with_file_extension_san, b"refs/heads/main.ext", "refs/heads/main.ext" ); mktest!(refs_path_underscores_and_dashes, b"refs/heads/main-2nd_ext"); mktests!( refs_path_underscores_and_dashes_san, b"refs/heads/main-2nd_ext", "refs/heads/main-2nd_ext" ); mktest!(relative_path, b"etc/foo"); mktests!(relative_path_san, b"etc/foo", "etc/foo"); mktest!(all_uppercase, b"MAIN"); mktests!(all_uppercase_san, b"MAIN", "MAIN"); mktest!(all_uppercase_with_underscore, b"NEW_HEAD"); mktests!(all_uppercase_with_underscore_san, b"NEW_HEAD", "NEW_HEAD"); mktest!(partial_name_lowercase, b"main"); mktests!(partial_name_lowercase_san, b"main", "main"); mktest!(chinese_utf8, "heads/你好吗".as_bytes()); mktests!(chinese_utf8_san, "heads/你好吗".as_bytes(), "heads/你好吗"); mktest!(parentheses_special_case_upload_pack, b"(null)"); mktests!(parentheses_special_case_upload_pack_san, b"(null)", "(null)"); } mod invalid { use bstr::ByteSlice; use gix_validate::reference::name::Error as RefError; macro_rules! mktest { ($name:ident, $input:literal, $expected:pat) => { #[test] fn $name() { match gix_validate::reference::name_partial($input.as_bstr()) { Err($expected) => {} got => panic!("Wanted {}, got {:?}", stringify!($expected), got), } } }; } mktest!(refs_path_double_dot, b"refs/../somewhere", RefError::StartsWithDot); mktests!(refs_path_double_dot_san, b"refs/../somewhere", "refs/-/somewhere"); mktest!( refs_path_name_starts_with_dot, b".refs/somewhere", RefError::StartsWithDot ); mktest!( refs_path_name_starts_with_multi_dot, b"..refs/somewhere", RefError::RepeatedDot ); mktests!( refs_path_name_starts_with_multi_dot_san, b"..refs/somewhere", "-refs/somewhere" ); mktests!( refs_path_name_starts_with_dot_san, b".refs/somewhere", "-refs/somewhere" ); mktest!( refs_path_component_is_singular_dot, b"refs/./still-inside-but-not-cool", RefError::StartsWithDot ); mktests!( refs_path_component_is_singular_dot_san, b"refs/./still-inside-but-not-cool", "refs/-/still-inside-but-not-cool" ); mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash); mktests!(any_path_starts_with_slash_san, b"/etc/foo", "etc/foo"); mktest!(empty_path, b"", RefError::Empty); mktests!(empty_path_san, b"", "-"); mktest!(refs_starts_with_slash, b"/refs/heads/main", RefError::StartsWithSlash); mktests!(refs_starts_with_slash_san, b"/refs/heads/main", "refs/heads/main"); mktest!(ends_with_slash, b"refs/heads/main/", RefError::EndsWithSlash); mktests!(ends_with_slash_san, b"refs/heads/main/", "refs/heads/main"); mktest!( path_with_duplicate_slashes, b"refs//heads/main", RefError::RepeatedSlash ); mktests!(path_with_duplicate_slashes_san, b"refs//heads/main", "refs/heads/main"); mktest!( path_with_spaces, b"refs/heads/name with spaces", RefError::InvalidByte { .. } ); mktests!( path_with_spaces_san, b"refs//heads////name with spaces", "refs/heads/name-with-spaces" ); mktest!( path_with_backslashes, br"refs\heads/name with spaces", RefError::InvalidByte { .. } ); mktests!( path_with_backslashes_san, br"refs\heads/name with spaces", "refs-heads/name-with-spaces" ); }} mod name { mod valid { use bstr::ByteSlice; macro_rules! mktest { ($name:ident, $input:expr) => { #[test] fn $name() { assert!(gix_validate::reference::name($input.as_bstr()).is_ok()) } }; } mktest!(main_worktree_pseudo_ref, b"main-worktree/HEAD"); mktests!( main_worktree_pseudo_ref_san, b"main-worktree/HEAD", "main-worktree/HEAD" ); mktest!(main_worktree_ref, b"main-worktree/refs/bisect/good"); mktests!( main_worktree_ref_san, b"main-worktree/refs/bisect/good", "main-worktree/refs/bisect/good" ); mktest!(other_worktree_pseudo_ref, b"worktrees/id/HEAD"); mktests!(other_worktree_pseudo_ref_san, b"worktrees/id/HEAD", "worktrees/id/HEAD"); mktest!(other_worktree_ref, b"worktrees/id/refs/bisect/good"); mktests!( other_worktree_ref_san, b"worktrees/id/refs/bisect/good", "worktrees/id/refs/bisect/good" ); mktest!(worktree_private_ref, b"refs/worktree/private"); mktests!( worktree_private_ref_san, b"refs/worktree/private", "refs/worktree/private" ); mktest!(refs_path, b"refs/heads/main"); mktests!(refs_path_san, b"refs/heads/main", "refs/heads/main"); mktest!(refs_path_with_file_extension, b"refs/heads/main.ext"); mktests!( refs_path_with_file_extension_san, b"refs/heads/main.ext", "refs/heads/main.ext" ); mktest!(refs_path_underscores_and_dashes, b"refs/heads/main-2nd_ext"); mktests!( refs_path_underscores_and_dashes_san, b"refs/heads/main-2nd_ext", "refs/heads/main-2nd_ext" ); mktest!(relative_path, b"etc/foo"); mktests!(relative_path_san, b"etc/foo", "etc/foo"); mktest!(all_uppercase, b"MAIN"); mktests!(all_uppercase_san, b"MAIN", "MAIN"); mktest!(all_uppercase_with_underscore, b"NEW_HEAD"); mktests!(all_uppercase_with_underscore_san, b"NEW_HEAD", "NEW_HEAD"); mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes()); mktests!(chinese_utf8_san, "refs/heads/你好吗".as_bytes(), "refs/heads/你好吗"); mktest!(dot_in_directory_component, b"this./totally./works"); mktests!( dot_in_directory_component_san, b"this./totally./works", "this./totally./works" ); } mod invalid { use bstr::ByteSlice; use gix_validate::reference::name::Error as RefError; macro_rules! mktest { ($name:ident, $input:literal, $expected:pat) => { #[test] fn $name() { match gix_validate::reference::name($input.as_bstr()) { Err($expected) => {} got => panic!("Wanted {}, got {:?}", stringify!($expected), got), } } }; } mktest!(refs_path_double_dot, b"refs/../somewhere", RefError::StartsWithDot); mktests!(refs_path_double_dot_san, b"refs/../somewhere", "refs/-/somewhere"); mktest!(refs_name_special_case_upload_pack, b"(null)", RefError::SomeLowercase); mktests!(refs_name_special_case_upload_pack_san, b"(null)", "(null)"); mktest!( refs_path_name_starts_with_dot, b".refs/somewhere", RefError::StartsWithDot ); mktests!( refs_path_name_starts_with_dot_san, b".refs/somewhere", "-refs/somewhere" ); mktest!( refs_path_name_starts_with_dot_in_name, b"refs/.somewhere", RefError::StartsWithDot ); mktests!( refs_path_name_starts_with_dot_in_name_san, b"refs/.somewhere", "refs/-somewhere" ); mktest!( refs_path_name_ends_with_dot_in_name, b"refs/somewhere.", RefError::EndsWithDot ); mktests!( refs_path_name_ends_with_dot_in_name_san, b"refs/somewhere.", "refs/somewhere-" ); mktest!( refs_path_component_is_singular_dot, b"refs/./still-inside-but-not-cool", RefError::StartsWithDot ); mktests!( refs_path_component_is_singular_dot_an, b"refs/./still-inside-but-not-cool", "refs/-/still-inside-but-not-cool" ); mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase); mktests!(capitalized_name_without_path_san, b"Main", "Main"); mktest!(lowercase_name_without_path, b"main", RefError::SomeLowercase); mktests!(lowercase_name_without_path_san, b"main", "main"); mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash); mktests!(any_path_starts_with_slash_san, b"/etc/foo", "etc/foo"); mktest!(empty_path, b"", RefError::Empty); mktests!(empty_path_san, b"", "-"); mktest!(refs_starts_with_slash, b"/refs/heads/main", RefError::StartsWithSlash); mktests!(refs_starts_with_slash_san, b"/refs/heads/main", "refs/heads/main"); mktest!(ends_with_slash, b"refs/heads/main/", RefError::EndsWithSlash); mktests!(ends_with_slash_san, b"refs/heads/main/", "refs/heads/main"); mktest!(ends_with_slash_multiple, b"refs/heads/main///", RefError::EndsWithSlash); mktests!(ends_with_slash_multiple_san, b"refs/heads/main///", "refs/heads/main"); mktest!( a_path_with_duplicate_slashes, b"refs//heads/main", RefError::RepeatedSlash ); mktests!( a_path_with_duplicate_slashes_san, b"refs//heads/main", "refs/heads/main" ); }} mod branch_name { mod valid { use bstr::ByteSlice; #[test] fn refs_heads_main() { assert!(gix_validate::reference::branch_name(b"refs/heads/main".as_bstr()).is_ok()); } #[test] fn refs_heads_head_different_case() { assert!(gix_validate::reference::branch_name(b"refs/heads/HEAd".as_bstr()).is_ok()); } } mod invalid { use bstr::ByteSlice; #[test] fn refs_heads_head_is_reserved() { assert!(matches!( gix_validate::reference::branch_name(b"refs/heads/HEAD".as_bstr()), Err(gix_validate::reference::name::Error::Reserved { name }) if name == "refs/heads/HEAD" )); } #[test] fn invalid_refname_is_wrapped() { assert!(matches!( gix_validate::reference::branch_name(b"refs//heads/main".as_bstr()), Err(gix_validate::reference::name::Error::RepeatedSlash) )); } }}
macro_rules! mktests {
($name:ident, $input:expr, $expected:expr) => {
#[test]
fn $name() {
let actual = gix_validate::reference::name_partial_or_sanitize($input.as_bstr());
assert_eq!(actual, $expected);
assert!(gix_validate::reference::name_partial(actual.as_ref()).is_ok());
}
};
}
mod name_partial {
mod valid {
use bstr::ByteSlice;
macro_rules! mktest {
($name:ident, $input:expr) => {
#[test]
fn $name() {
assert!(gix_validate::reference::name_partial($input.as_bstr()).is_ok())
}
};
}
mktest!(refs_path, b"refs/heads/main");
mktests!(refs_path_san, b"refs/heads/main", "refs/heads/main");
mktest!(main_worktree_pseudo_ref, b"main-worktree/HEAD");
mktests!(
main_worktree_pseudo_ref_san,
b"main-worktree/HEAD",
"main-worktree/HEAD"
);
mktest!(main_worktree_ref, b"main-worktree/refs/bisect/good");
mktests!(
main_worktree_ref_san,
b"main-worktree/refs/bisect/good",
"main-worktree/refs/bisect/good"
);
mktest!(other_worktree_pseudo_ref, b"worktrees/id/HEAD");
mktests!(other_worktree_pseudo_ref_san, b"worktrees/id/HEAD", "worktrees/id/HEAD");
mktest!(other_worktree_ref, b"worktrees/id/refs/bisect/good");
mktests!(
other_worktree_ref_san,
b"worktrees/id/refs/bisect/good",
"worktrees/id/refs/bisect/good"
);
mktest!(worktree_private_ref, b"refs/worktree/private");
mktests!(
worktree_private_ref_san,
b"refs/worktree/private",
"refs/worktree/private"
);
mktest!(refs_path_with_file_extension, b"refs/heads/main.ext");
mktests!(
refs_path_with_file_extension_san,
b"refs/heads/main.ext",
"refs/heads/main.ext"
);
mktest!(refs_path_underscores_and_dashes, b"refs/heads/main-2nd_ext");
mktests!(
refs_path_underscores_and_dashes_san,
b"refs/heads/main-2nd_ext",
"refs/heads/main-2nd_ext"
);
mktest!(relative_path, b"etc/foo");
mktests!(relative_path_san, b"etc/foo", "etc/foo");
mktest!(all_uppercase, b"MAIN");
mktests!(all_uppercase_san, b"MAIN", "MAIN");
mktest!(all_uppercase_with_underscore, b"NEW_HEAD");
mktests!(all_uppercase_with_underscore_san, b"NEW_HEAD", "NEW_HEAD");
mktest!(partial_name_lowercase, b"main");
mktests!(partial_name_lowercase_san, b"main", "main");
mktest!(chinese_utf8, "heads/你好吗".as_bytes());
mktests!(chinese_utf8_san, "heads/你好吗".as_bytes(), "heads/你好吗");
mktest!(parentheses_special_case_upload_pack, b"(null)");
mktests!(parentheses_special_case_upload_pack_san, b"(null)", "(null)");
}
mod invalid {
use bstr::ByteSlice;
use gix_validate::reference::name::Error as RefError;
macro_rules! mktest {
($name:ident, $input:literal, $expected:pat) => {
#[test]
fn $name() {
match gix_validate::reference::name_partial($input.as_bstr()) {
Err($expected) => {}
got => panic!("Wanted {}, got {:?}", stringify!($expected), got),
}
}
};
}
mktest!(refs_path_double_dot, b"refs/../somewhere", RefError::StartsWithDot);
mktests!(refs_path_double_dot_san, b"refs/../somewhere", "refs/-/somewhere");
mktest!(
refs_path_name_starts_with_dot,
b".refs/somewhere",
RefError::StartsWithDot
);
mktest!(
refs_path_name_starts_with_multi_dot,
b"..refs/somewhere",
RefError::RepeatedDot
);
mktests!(
refs_path_name_starts_with_multi_dot_san,
b"..refs/somewhere",
"-refs/somewhere"
);
mktests!(
refs_path_name_starts_with_dot_san,
b".refs/somewhere",
"-refs/somewhere"
);
mktest!(
refs_path_component_is_singular_dot,
b"refs/./still-inside-but-not-cool",
RefError::StartsWithDot
);
mktests!(
refs_path_component_is_singular_dot_san,
b"refs/./still-inside-but-not-cool",
"refs/-/still-inside-but-not-cool"
);
mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);
mktests!(any_path_starts_with_slash_san, b"/etc/foo", "etc/foo");
mktest!(empty_path, b"", RefError::Empty);
mktests!(empty_path_san, b"", "-");
mktest!(refs_starts_with_slash, b"/refs/heads/main", RefError::StartsWithSlash);
mktests!(refs_starts_with_slash_san, b"/refs/heads/main", "refs/heads/main");
mktest!(ends_with_slash, b"refs/heads/main/", RefError::EndsWithSlash);
mktests!(ends_with_slash_san, b"refs/heads/main/", "refs/heads/main");
mktest!(
path_with_duplicate_slashes,
b"refs//heads/main",
RefError::RepeatedSlash
);
mktests!(path_with_duplicate_slashes_san, b"refs//heads/main", "refs/heads/main");
mktest!(
path_with_spaces,
b"refs/heads/name with spaces",
RefError::InvalidByte { .. }
);
mktests!(
path_with_spaces_san,
b"refs//heads////name with spaces",
"refs/heads/name-with-spaces"
);
mktest!(
path_with_backslashes,
br"refs\heads/name with spaces",
RefError::InvalidByte { .. }
);
mktests!(
path_with_backslashes_san,
br"refs\heads/name with spaces",
"refs-heads/name-with-spaces"
);
}
}
mod name {
mod valid {
use bstr::ByteSlice;
macro_rules! mktest {
($name:ident, $input:expr) => {
#[test]
fn $name() {
assert!(gix_validate::reference::name($input.as_bstr()).is_ok())
}
};
}
mktest!(main_worktree_pseudo_ref, b"main-worktree/HEAD");
mktests!(
main_worktree_pseudo_ref_san,
b"main-worktree/HEAD",
"main-worktree/HEAD"
);
mktest!(main_worktree_ref, b"main-worktree/refs/bisect/good");
mktests!(
main_worktree_ref_san,
b"main-worktree/refs/bisect/good",
"main-worktree/refs/bisect/good"
);
mktest!(other_worktree_pseudo_ref, b"worktrees/id/HEAD");
mktests!(other_worktree_pseudo_ref_san, b"worktrees/id/HEAD", "worktrees/id/HEAD");
mktest!(other_worktree_ref, b"worktrees/id/refs/bisect/good");
mktests!(
other_worktree_ref_san,
b"worktrees/id/refs/bisect/good",
"worktrees/id/refs/bisect/good"
);
mktest!(worktree_private_ref, b"refs/worktree/private");
mktests!(
worktree_private_ref_san,
b"refs/worktree/private",
"refs/worktree/private"
);
mktest!(refs_path, b"refs/heads/main");
mktests!(refs_path_san, b"refs/heads/main", "refs/heads/main");
mktest!(refs_path_with_file_extension, b"refs/heads/main.ext");
mktests!(
refs_path_with_file_extension_san,
b"refs/heads/main.ext",
"refs/heads/main.ext"
);
mktest!(refs_path_underscores_and_dashes, b"refs/heads/main-2nd_ext");
mktests!(
refs_path_underscores_and_dashes_san,
b"refs/heads/main-2nd_ext",
"refs/heads/main-2nd_ext"
);
mktest!(relative_path, b"etc/foo");
mktests!(relative_path_san, b"etc/foo", "etc/foo");
mktest!(all_uppercase, b"MAIN");
mktests!(all_uppercase_san, b"MAIN", "MAIN");
mktest!(all_uppercase_with_underscore, b"NEW_HEAD");
mktests!(all_uppercase_with_underscore_san, b"NEW_HEAD", "NEW_HEAD");
mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes());
mktests!(chinese_utf8_san, "refs/heads/你好吗".as_bytes(), "refs/heads/你好吗");
mktest!(dot_in_directory_component, b"this./totally./works");
mktests!(
dot_in_directory_component_san,
b"this./totally./works",
"this./totally./works"
);
}
mod invalid {
use bstr::ByteSlice;
use gix_validate::reference::name::Error as RefError;
macro_rules! mktest {
($name:ident, $input:literal, $expected:pat) => {
#[test]
fn $name() {
match gix_validate::reference::name($input.as_bstr()) {
Err($expected) => {}
got => panic!("Wanted {}, got {:?}", stringify!($expected), got),
}
}
};
}
mktest!(refs_path_double_dot, b"refs/../somewhere", RefError::StartsWithDot);
mktests!(refs_path_double_dot_san, b"refs/../somewhere", "refs/-/somewhere");
mktest!(refs_name_special_case_upload_pack, b"(null)", RefError::SomeLowercase);
mktests!(refs_name_special_case_upload_pack_san, b"(null)", "(null)");
mktest!(
refs_path_name_starts_with_dot,
b".refs/somewhere",
RefError::StartsWithDot
);
mktests!(
refs_path_name_starts_with_dot_san,
b".refs/somewhere",
"-refs/somewhere"
);
mktest!(
refs_path_name_starts_with_dot_in_name,
b"refs/.somewhere",
RefError::StartsWithDot
);
mktests!(
refs_path_name_starts_with_dot_in_name_san,
b"refs/.somewhere",
"refs/-somewhere"
);
mktest!(
refs_path_name_ends_with_dot_in_name,
b"refs/somewhere.",
RefError::EndsWithDot
);
mktests!(
refs_path_name_ends_with_dot_in_name_san,
b"refs/somewhere.",
"refs/somewhere-"
);
mktest!(
refs_path_component_is_singular_dot,
b"refs/./still-inside-but-not-cool",
RefError::StartsWithDot
);
mktests!(
refs_path_component_is_singular_dot_an,
b"refs/./still-inside-but-not-cool",
"refs/-/still-inside-but-not-cool"
);
mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase);
mktests!(capitalized_name_without_path_san, b"Main", "Main");
mktest!(lowercase_name_without_path, b"main", RefError::SomeLowercase);
mktests!(lowercase_name_without_path_san, b"main", "main");
mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);
mktests!(any_path_starts_with_slash_san, b"/etc/foo", "etc/foo");
mktest!(empty_path, b"", RefError::Empty);
mktests!(empty_path_san, b"", "-");
mktest!(refs_starts_with_slash, b"/refs/heads/main", RefError::StartsWithSlash);
mktests!(refs_starts_with_slash_san, b"/refs/heads/main", "refs/heads/main");
mktest!(ends_with_slash, b"refs/heads/main/", RefError::EndsWithSlash);
mktests!(ends_with_slash_san, b"refs/heads/main/", "refs/heads/main");
mktest!(ends_with_slash_multiple, b"refs/heads/main///", RefError::EndsWithSlash);
mktests!(ends_with_slash_multiple_san, b"refs/heads/main///", "refs/heads/main");
mktest!(
a_path_with_duplicate_slashes,
b"refs//heads/main",
RefError::RepeatedSlash
);
mktests!(
a_path_with_duplicate_slashes_san,
b"refs//heads/main",
"refs/heads/main"
);
}
}
mod branch_name {
mod valid {
use bstr::ByteSlice;
#[test]
fn refs_heads_main() {
assert!(gix_validate::reference::branch_name(b"refs/heads/main".as_bstr()).is_ok());
}
#[test]
fn refs_heads_head_different_case() {
assert!(gix_validate::reference::branch_name(b"refs/heads/HEAd".as_bstr()).is_ok());
}
}
mod invalid {
use bstr::ByteSlice;
#[test]
fn refs_heads_head_is_reserved() {
assert!(matches!(
gix_validate::reference::branch_name(b"refs/heads/HEAD".as_bstr()),
Err(gix_validate::reference::name::Error::Reserved { name }) if name == "refs/heads/HEAD"
));
}
#[test]
fn invalid_refname_is_wrapped() {
assert!(matches!(
gix_validate::reference::branch_name(b"refs//heads/main".as_bstr()),
Err(gix_validate::reference::name::Error::RepeatedSlash)
));
}
}
}