use crate::features::{
BodyMember, BodyMembers, BodySelection, DistinctMembers, FaceSelection, FeatureId,
GeneratedBodyRef, GeneratedFaceRef, NativeSelections, NonEmptyMembers, SelectionMembers,
};
use crate::ids::{BodyId, FaceId, FeatureInputTopologyId, HistoricalBodyId, HistoricalFaceId};
fn state(name: &str) -> FeatureInputTopologyId {
FeatureInputTopologyId::mint(format!("test:model:state#{name}")).expect("state identity")
}
fn faces(name: &str) -> FaceSelection {
FaceSelection::Faces(vec![
FaceId::mint(format!("test:model:face#{name}")).expect("face identity")
])
}
fn bodies(name: &str) -> BodySelection {
BodySelection::Bodies(DistinctMembers(vec![BodyId::mint(format!(
"test:model:body#{name}"
))
.expect("body identity")]))
}
#[test]
fn selection_overlap_preserves_every_membership_form() {
let native =
|| cadmpeg_core::text::NonBlankString::new("native").expect("nonblank native selection");
let historical_face = |partial, other_state| {
let id = HistoricalFaceId::mint("test:model:face#historical").expect("historical face");
let state = state(if other_state { "other" } else { "same" });
if partial {
FaceSelection::HistoricalPartial {
state,
faces: DistinctMembers(vec![id]),
unresolved: NativeSelections(vec!["unresolved".into()]),
native: native(),
}
} else {
FaceSelection::Historical {
state,
faces: SelectionMembers(vec![id]),
native: native(),
}
}
};
let generated_face = |feature: &str, local: &str| FaceSelection::Generated {
faces: NonEmptyMembers(vec![GeneratedFaceRef {
feature: FeatureId::mint(format!("test:model:feature#{feature}"))
.expect("feature identity"),
local_id: local.to_owned().try_into().expect("local identity"),
}]),
native: "native".to_owned().try_into().expect("native selection"),
};
let same_face = FaceId::mint("test:model:face#same").expect("face identity");
let face_cases = [
(
faces("same"),
FaceSelection::Resolved {
faces: vec![same_face],
native: "native".into(),
},
true,
),
(faces("first"), faces("other"), false),
(
historical_face(false, false),
historical_face(true, false),
true,
),
(
historical_face(false, false),
historical_face(true, true),
false,
),
(
generated_face("same", "same"),
generated_face("same", "same"),
true,
),
(
generated_face("same", "same"),
generated_face("other", "same"),
false,
),
(
generated_face("same", "same"),
generated_face("same", "other"),
false,
),
(
FaceSelection::Native("same".into()),
FaceSelection::Native("same".into()),
false,
),
];
let paired_body = |historical, other_state| {
if historical {
BodySelection::HistoricalSet {
state: state(if other_state { "other" } else { "same" }),
members: BodyMembers(vec![BodyMember::new(
HistoricalBodyId::mint("test:model:body#historical").expect("historical body"),
native(),
)]),
}
} else {
BodySelection::ResolvedSet {
members: BodyMembers(vec![BodyMember::new(
BodyId::mint("test:model:body#same").expect("body identity"),
native(),
)]),
}
}
};
let historical_body = || BodySelection::Historical {
state: state("same"),
bodies: SelectionMembers(vec![
HistoricalBodyId::mint("test:model:body#historical").expect("historical body")
]),
native: "native".to_owned().try_into().expect("native selection"),
};
let generated_body = |feature: &str, local: &str| BodySelection::Generated {
bodies: SelectionMembers(vec![GeneratedBodyRef {
feature: FeatureId::mint(format!("test:model:feature#{feature}"))
.expect("feature identity"),
local_id: local.to_owned().try_into().expect("local identity"),
}]),
native: "native".to_owned().try_into().expect("native selection"),
};
let local_body = |name: &str| BodySelection::Local {
bodies: NativeSelections(vec![name.into()]),
native: "native".to_owned().try_into().expect("native selection"),
};
let body_cases = [
(bodies("same"), paired_body(false, false), true),
(paired_body(false, false), bodies("same"), true),
(paired_body(false, false), paired_body(false, false), true),
(bodies("first"), bodies("other"), false),
(historical_body(), paired_body(true, false), true),
(paired_body(true, false), historical_body(), true),
(historical_body(), paired_body(true, true), false),
(
generated_body("same", "same"),
generated_body("same", "same"),
true,
),
(
generated_body("same", "same"),
generated_body("other", "same"),
false,
),
(
generated_body("same", "same"),
generated_body("same", "other"),
false,
),
(local_body("same"), local_body("same"), true),
(local_body("same"), local_body("other"), false),
(bodies("same"), historical_body(), false),
];
for (first, second, expected) in face_cases {
assert_eq!(super::face_selections_overlap(&first, &second), expected);
}
for (first, second, expected) in body_cases {
assert_eq!(super::body_selections_overlap(&first, &second), expected);
}
}
#[test]
fn selection_overlap_stops_at_the_first_shared_member() {
let first_id = FaceId::mint("test:model:face#first").expect("face identity");
let first = FaceSelection::Faces(vec![
first_id.clone(),
FaceId::mint("test:model:face#second").expect("face identity"),
]);
let second = FaceSelection::Faces(vec![
first_id.clone(),
FaceId::mint("test:model:face#third").expect("face identity"),
]);
assert!(super::face_selections_overlap(&first, &second));
}