mirror of
https://github.com/awfixers-stuff/src.git
synced 2026-03-24 03:25:59 +00:00
create src
This commit is contained in:
343
src-refspec/tests/refspec/match_group.rs
Normal file
343
src-refspec/tests/refspec/match_group.rs
Normal file
@@ -0,0 +1,343 @@
|
||||
mod single {
|
||||
use crate::matching::baseline;
|
||||
|
||||
#[test]
|
||||
fn fetch_only() {
|
||||
baseline::agrees_with_fetch_specs(Some("refs/heads/main"));
|
||||
baseline::agrees_with_fetch_specs(Some("heads/main"));
|
||||
baseline::agrees_with_fetch_specs(Some("main"));
|
||||
baseline::agrees_with_fetch_specs(Some("v0.0-f1"));
|
||||
baseline::agrees_with_fetch_specs(Some("tags/v0.0-f2"));
|
||||
baseline::of_objects_always_matches_if_the_server_has_the_object(Some(
|
||||
"78b1c1be9421b33a49a7a8176d93eeeafa112da1",
|
||||
));
|
||||
baseline::of_objects_always_matches_if_the_server_has_the_object(Some(
|
||||
"9d2fab1a0ba3585d0bc50922bfdd04ebb59361df",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update() {
|
||||
baseline::of_objects_with_destinations_are_written_into_given_local_branches(
|
||||
Some("78b1c1be9421b33a49a7a8176d93eeeafa112da1:special"),
|
||||
["78b1c1be9421b33a49a7a8176d93eeeafa112da1:refs/heads/special"],
|
||||
);
|
||||
baseline::of_objects_with_destinations_are_written_into_given_local_branches(
|
||||
Some("78b1c1be9421b33a49a7a8176d93eeeafa112da1:1111111111111111111111111111111111111111"),
|
||||
["78b1c1be9421b33a49a7a8176d93eeeafa112da1:refs/heads/1111111111111111111111111111111111111111"],
|
||||
);
|
||||
baseline::of_objects_with_destinations_are_written_into_given_local_branches(
|
||||
Some("9d2fab1a0ba3585d0bc50922bfdd04ebb59361df:tags/special"),
|
||||
["9d2fab1a0ba3585d0bc50922bfdd04ebb59361df:refs/tags/special"],
|
||||
);
|
||||
baseline::of_objects_with_destinations_are_written_into_given_local_branches(
|
||||
Some("9d2fab1a0ba3585d0bc50922bfdd04ebb59361df:refs/tags/special"),
|
||||
["9d2fab1a0ba3585d0bc50922bfdd04ebb59361df:refs/tags/special"],
|
||||
);
|
||||
|
||||
baseline::agrees_but_observable_refs_are_vague(Some("f1:origin/f1"), ["refs/heads/f1:refs/heads/origin/f1"]);
|
||||
baseline::agrees_but_observable_refs_are_vague(
|
||||
Some("f1:remotes/origin/f1"),
|
||||
["refs/heads/f1:refs/remotes/origin/f1"],
|
||||
);
|
||||
baseline::agrees_but_observable_refs_are_vague(Some("f1:notes/f1"), ["refs/heads/f1:refs/heads/notes/f1"]);
|
||||
baseline::agrees_with_fetch_specs(Some("+refs/heads/*:refs/remotes/origin/*"));
|
||||
baseline::agrees_with_fetch_specs(Some("refs/heads/f*:refs/remotes/origin/a*"));
|
||||
baseline::agrees_with_fetch_specs(Some("refs/heads/*1:refs/remotes/origin/*1"));
|
||||
}
|
||||
}
|
||||
|
||||
mod multiple {
|
||||
use gix_refspec::{
|
||||
match_group::validate::Fix,
|
||||
parse::{Error, Operation},
|
||||
};
|
||||
|
||||
use crate::matching::baseline;
|
||||
|
||||
#[test]
|
||||
fn fetch_only() {
|
||||
baseline::agrees_with_fetch_specs(["main", "f1"]);
|
||||
baseline::agrees_with_fetch_specs(["heads/main", "heads/f1"]);
|
||||
baseline::agrees_with_fetch_specs(["refs/heads/main", "refs/heads/f1"]);
|
||||
baseline::agrees_with_fetch_specs(["heads/f1", "f2", "refs/heads/f3", "heads/main"]);
|
||||
baseline::agrees_with_fetch_specs(["f*:a*", "refs/heads/main"]);
|
||||
baseline::agrees_with_fetch_specs([
|
||||
"refs/tags/*:refs/remotes/origin/*",
|
||||
"refs/heads/*:refs/remotes/origin/*",
|
||||
]);
|
||||
baseline::agrees_with_fetch_specs(["refs/tags/*:refs/tags/*"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_and_negations() {
|
||||
baseline::invalid_specs_fail_to_parse_where_git_shows_surprising_behaviour(
|
||||
["refs/heads/f*:refs/remotes/origin/a*", "^f1"],
|
||||
Error::NegativePartialName,
|
||||
);
|
||||
baseline::invalid_specs_fail_to_parse_where_git_shows_surprising_behaviour(
|
||||
["heads/f2", "^refs/heads/f*:refs/remotes/origin/a*"],
|
||||
Error::NegativeWithDestination,
|
||||
);
|
||||
baseline::agrees_with_fetch_specs(["refs/heads/f*:refs/remotes/origin/a*", "^refs/heads/f1"]);
|
||||
baseline::invalid_specs_fail_to_parse_where_git_shows_surprising_behaviour(
|
||||
["^heads/f2", "refs/heads/f*:refs/remotes/origin/a*"],
|
||||
Error::NegativePartialName,
|
||||
);
|
||||
baseline::agrees_with_fetch_specs(["^refs/heads/f2", "refs/heads/f*:refs/remotes/origin/a*"]);
|
||||
baseline::invalid_specs_fail_to_parse_where_git_shows_surprising_behaviour(
|
||||
["^main", "refs/heads/*:refs/remotes/origin/*"],
|
||||
Error::NegativePartialName,
|
||||
);
|
||||
baseline::agrees_with_fetch_specs(["^refs/heads/main", "refs/heads/*:refs/remotes/origin/*"]);
|
||||
baseline::agrees_with_fetch_specs(["refs/heads/*:refs/remotes/origin/*", "^refs/heads/main"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_with_empty_lhs() {
|
||||
baseline::agrees_but_observable_refs_are_vague([":refs/heads/f1"], ["HEAD:refs/heads/f1"]);
|
||||
baseline::agrees_but_observable_refs_are_vague([":f1"], ["HEAD:refs/heads/f1"]);
|
||||
baseline::agrees_but_observable_refs_are_vague(["@:f1"], ["HEAD:refs/heads/f1"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_head_to_head_never_updates_actual_head_ref() {
|
||||
baseline::agrees_but_observable_refs_are_vague(["@:HEAD"], ["HEAD:refs/heads/HEAD"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_head_with_empty_rhs() {
|
||||
baseline::agrees_but_observable_refs_are_vague([":"], ["HEAD:"]);
|
||||
baseline::agrees_but_observable_refs_are_vague(["HEAD:"], ["HEAD:"]);
|
||||
baseline::agrees_but_observable_refs_are_vague(["@:"], ["HEAD:"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_multiple_destinations() {
|
||||
baseline::agrees_with_fetch_specs([
|
||||
"refs/heads/*:refs/remotes/origin/*",
|
||||
"refs/heads/main:refs/remotes/new-origin/main",
|
||||
]);
|
||||
baseline::agrees_with_fetch_specs([
|
||||
"refs/heads/*:refs/remotes/origin/*",
|
||||
"refs/heads/main:refs/remotes/origin/main", // duplicates are removed immediately.
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_with_conflicts() {
|
||||
baseline::agrees_with_fetch_specs_validation_error(
|
||||
[
|
||||
"refs/heads/f1:refs/remotes/origin/conflict",
|
||||
"refs/heads/f2:refs/remotes/origin/conflict",
|
||||
],
|
||||
"Found 1 issue that prevents the refspec mapping to be used: \n\tConflicting destination \"refs/remotes/origin/conflict\" would be written by refs/heads/f1 (\"refs/heads/f1:refs/remotes/origin/conflict\"), refs/heads/f2 (\"refs/heads/f2:refs/remotes/origin/conflict\")",
|
||||
);
|
||||
baseline::agrees_with_fetch_specs_validation_error(
|
||||
[
|
||||
"refs/heads/f1:refs/remotes/origin/conflict2",
|
||||
"refs/heads/f2:refs/remotes/origin/conflict2",
|
||||
"refs/heads/f1:refs/remotes/origin/conflict",
|
||||
"refs/heads/f2:refs/remotes/origin/conflict",
|
||||
"refs/heads/f3:refs/remotes/origin/conflict",
|
||||
],
|
||||
"Found 2 issues that prevent the refspec mapping to be used: \n\tConflicting destination \"refs/remotes/origin/conflict\" would be written by refs/heads/f1 (\"refs/heads/f1:refs/remotes/origin/conflict\"), refs/heads/f2 (\"refs/heads/f2:refs/remotes/origin/conflict\"), refs/heads/f3 (\"refs/heads/f3:refs/remotes/origin/conflict\")\n\tConflicting destination \"refs/remotes/origin/conflict2\" would be written by refs/heads/f1 (\"refs/heads/f1:refs/remotes/origin/conflict2\"), refs/heads/f2 (\"refs/heads/f2:refs/remotes/origin/conflict2\")",
|
||||
);
|
||||
baseline::agrees_with_fetch_specs_validation_error(
|
||||
[
|
||||
"refs/heads/f1:refs/remotes/origin/same",
|
||||
"refs/tags/v0.0-f1:refs/remotes/origin/same",
|
||||
],
|
||||
"Found 1 issue that prevents the refspec mapping to be used: \n\tConflicting destination \"refs/remotes/origin/same\" would be written by refs/heads/f1 (\"refs/heads/f1:refs/remotes/origin/same\"), refs/tags/v0.0-f1 (\"refs/tags/v0.0-f1:refs/remotes/origin/same\")",
|
||||
);
|
||||
baseline::agrees_with_fetch_specs_validation_error(
|
||||
[
|
||||
"+refs/heads/*:refs/remotes/origin/*",
|
||||
"refs/heads/f1:refs/remotes/origin/f2",
|
||||
"refs/heads/f2:refs/remotes/origin/f1",
|
||||
],
|
||||
"Found 2 issues that prevent the refspec mapping to be used: \n\tConflicting destination \"refs/remotes/origin/f1\" would be written by refs/heads/f1 (\"+refs/heads/*:refs/remotes/origin/*\"), refs/heads/f2 (\"refs/heads/f2:refs/remotes/origin/f1\")\n\tConflicting destination \"refs/remotes/origin/f2\" would be written by refs/heads/f2 (\"+refs/heads/*:refs/remotes/origin/*\"), refs/heads/f1 (\"refs/heads/f1:refs/remotes/origin/f2\")",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_and_update_with_fixes() {
|
||||
let glob_spec = "refs/heads/f*:foo/f*";
|
||||
let glob_spec_ref = gix_refspec::parse(glob_spec.into(), Operation::Fetch).unwrap();
|
||||
baseline::agrees_and_applies_fixes(
|
||||
[glob_spec, "f1:f1"],
|
||||
[
|
||||
Fix::MappingWithPartialDestinationRemoved {
|
||||
name: "foo/f1".into(),
|
||||
spec: glob_spec_ref.to_owned(),
|
||||
},
|
||||
Fix::MappingWithPartialDestinationRemoved {
|
||||
name: "foo/f2".into(),
|
||||
spec: glob_spec_ref.to_owned(),
|
||||
},
|
||||
Fix::MappingWithPartialDestinationRemoved {
|
||||
name: "foo/f3".into(),
|
||||
spec: glob_spec_ref.to_owned(),
|
||||
},
|
||||
],
|
||||
["refs/heads/f1:refs/heads/f1"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod complex_globs {
|
||||
use bstr::BString;
|
||||
use gix_hash::ObjectId;
|
||||
use gix_refspec::{parse::Operation, MatchGroup};
|
||||
|
||||
#[test]
|
||||
fn one_sided_complex_glob_patterns_can_be_parsed() {
|
||||
// The key change is that complex glob patterns with multiple asterisks
|
||||
// can now be parsed for one-sided refspecs
|
||||
let spec = gix_refspec::parse("refs/*/foo/*".into(), Operation::Fetch);
|
||||
assert!(spec.is_ok(), "Should parse complex glob pattern for one-sided refspec");
|
||||
|
||||
let spec = gix_refspec::parse("refs/*/*/bar".into(), Operation::Fetch);
|
||||
assert!(
|
||||
spec.is_ok(),
|
||||
"Should parse complex glob pattern with multiple asterisks"
|
||||
);
|
||||
|
||||
let spec = gix_refspec::parse("refs/heads/[a-z.]/release/*".into(), Operation::Fetch);
|
||||
assert!(spec.is_ok(), "Should parse complex glob pattern");
|
||||
|
||||
// Two-sided refspecs with multiple asterisks should still fail
|
||||
let spec = gix_refspec::parse("refs/*/foo/*:refs/remotes/*".into(), Operation::Fetch);
|
||||
assert!(spec.is_err(), "Two-sided refspecs with multiple asterisks should fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_sided_simple_glob_patterns_match() {
|
||||
// Test that simple glob patterns (one asterisk) work correctly with matching
|
||||
let refs = [
|
||||
new_ref("refs/heads/feature/foo", "1111111111111111111111111111111111111111"),
|
||||
new_ref("refs/heads/bugfix/bar", "2222222222222222222222222222222222222222"),
|
||||
new_ref("refs/tags/v1.0", "3333333333333333333333333333333333333333"),
|
||||
new_ref("refs/pull/123", "4444444444444444444444444444444444444444"),
|
||||
];
|
||||
let items: Vec<_> = refs.iter().map(|r| r.to_item()).collect();
|
||||
|
||||
// Test: refs/heads/* should match all refs under refs/heads/
|
||||
let spec = gix_refspec::parse("refs/heads/*".into(), Operation::Fetch).unwrap();
|
||||
let group = MatchGroup::from_fetch_specs([spec]);
|
||||
let outcome = group.match_lhs(items.iter().copied());
|
||||
|
||||
insta::assert_debug_snapshot!(outcome.mappings, @r#"
|
||||
[
|
||||
Mapping {
|
||||
item_index: Some(
|
||||
0,
|
||||
),
|
||||
lhs: FullName(
|
||||
"refs/heads/feature/foo",
|
||||
),
|
||||
rhs: None,
|
||||
spec_index: 0,
|
||||
},
|
||||
Mapping {
|
||||
item_index: Some(
|
||||
1,
|
||||
),
|
||||
lhs: FullName(
|
||||
"refs/heads/bugfix/bar",
|
||||
),
|
||||
rhs: None,
|
||||
spec_index: 0,
|
||||
},
|
||||
]
|
||||
"#);
|
||||
|
||||
// Test: refs/tags/* should match all refs under refs/tags/
|
||||
let items: Vec<_> = refs.iter().map(|r| r.to_item()).collect();
|
||||
let spec = gix_refspec::parse("refs/tags/v[0-9]*".into(), Operation::Fetch).unwrap();
|
||||
let group = MatchGroup::from_fetch_specs([spec]);
|
||||
let outcome = group.match_lhs(items.iter().copied());
|
||||
|
||||
insta::assert_debug_snapshot!(outcome.mappings, @r#"
|
||||
[
|
||||
Mapping {
|
||||
item_index: Some(
|
||||
2,
|
||||
),
|
||||
lhs: FullName(
|
||||
"refs/tags/v1.0",
|
||||
),
|
||||
rhs: None,
|
||||
spec_index: 0,
|
||||
},
|
||||
]
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_sided_glob_with_suffix_matches() {
|
||||
// Test that glob patterns with suffix work correctly
|
||||
let refs = [
|
||||
new_ref("refs/heads/feature", "1111111111111111111111111111111111111111"),
|
||||
new_ref("refs/heads/feat", "2222222222222222222222222222222222222222"),
|
||||
new_ref("refs/heads/main", "3333333333333333333333333333333333333333"),
|
||||
];
|
||||
let items: Vec<_> = refs.iter().map(|r| r.to_item()).collect();
|
||||
|
||||
// Test: refs/heads/feat* should match refs/heads/feature and refs/heads/feat
|
||||
let spec = gix_refspec::parse("refs/heads/feat*".into(), Operation::Fetch).unwrap();
|
||||
let group = MatchGroup::from_fetch_specs([spec]);
|
||||
let outcome = group.match_lhs(items.iter().copied());
|
||||
let mappings = outcome.mappings;
|
||||
|
||||
insta::assert_debug_snapshot!(mappings, @r#"
|
||||
[
|
||||
Mapping {
|
||||
item_index: Some(
|
||||
0,
|
||||
),
|
||||
lhs: FullName(
|
||||
"refs/heads/feature",
|
||||
),
|
||||
rhs: None,
|
||||
spec_index: 0,
|
||||
},
|
||||
Mapping {
|
||||
item_index: Some(
|
||||
1,
|
||||
),
|
||||
lhs: FullName(
|
||||
"refs/heads/feat",
|
||||
),
|
||||
rhs: None,
|
||||
spec_index: 0,
|
||||
},
|
||||
]
|
||||
"#);
|
||||
}
|
||||
|
||||
fn new_ref(name: &str, id_hex: &str) -> Ref {
|
||||
Ref {
|
||||
name: name.into(),
|
||||
target: ObjectId::from_hex(id_hex.as_bytes()).unwrap(),
|
||||
object: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Ref {
|
||||
name: BString,
|
||||
target: ObjectId,
|
||||
object: Option<ObjectId>,
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
fn to_item(&self) -> gix_refspec::match_group::Item<'_> {
|
||||
gix_refspec::match_group::Item {
|
||||
full_ref_name: self.name.as_ref(),
|
||||
target: &self.target,
|
||||
object: self.object.as_deref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user