#![allow(missing_docs)]
use openbim_step::SchemaGraph;
const DIAMOND: &str = "\
SCHEMA D;
ENTITY top; t : INTEGER; END_ENTITY;
ENTITY a SUBTYPE OF (top); x : INTEGER; END_ENTITY;
ENTITY b SUBTYPE OF (top); y : INTEGER; END_ENTITY;
ENTITY c SUBTYPE OF (a, b); z : INTEGER; END_ENTITY;
ENTITY d SUBTYPE OF (c); w : INTEGER; END_ENTITY;
END_SCHEMA;";
#[test]
fn multiple_supertypes_are_laid_out_in_subtype_of_order_once_each() {
let g = SchemaGraph::from_express(DIAMOND);
assert_eq!(g.attribute_names("c"), ["t", "x", "y", "z"]);
assert_eq!(g.attribute_names("d"), ["t", "x", "y", "z", "w"]);
assert_eq!(g.direct_supertypes("c"), ["a", "b"]);
assert_eq!(g.supertypes("d"), ["c", "a", "top", "b"]);
assert!(g.is_a("c", "b"));
assert!(g.is_a("d", "top"));
assert!(!g.is_a("a", "b"));
assert_eq!(g.direct_subtypes("b"), ["c"]);
assert_eq!(g.subtypes("top"), ["a", "c", "d", "b"]);
}
#[test]
fn supertype_order_follows_the_subtype_of_clause() {
let g = SchemaGraph::from_express(
"SCHEMA O; ENTITY zz; z : INTEGER; END_ENTITY; ENTITY aa; a : INTEGER; END_ENTITY;
ENTITY both SUBTYPE OF (zz, aa); END_ENTITY; END_SCHEMA;",
);
assert_eq!(g.attribute_names("both"), ["z", "a"]);
}
#[test]
fn explicit_redeclaration_keeps_the_inherited_slot() {
let g = SchemaGraph::from_express(
r"SCHEMA R;
ENTITY styled; name : STRING; target : thing; END_ENTITY;
ENTITY plane SUBTYPE OF (styled);
SELF\styled.target : plane_target;
extra : INTEGER;
END_ENTITY;
END_SCHEMA;",
);
assert_eq!(g.attribute_names("plane"), ["name", "target", "extra"]);
}
#[test]
fn cyclic_multiple_inheritance_terminates() {
let (done, finished) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let g = SchemaGraph::from_express(
"SCHEMA X; ENTITY p SUBTYPE OF (q, p); a : INTEGER; END_ENTITY;
ENTITY q SUBTYPE OF (p); b : INTEGER; END_ENTITY; END_SCHEMA;",
);
let layout = g.attribute_names("p").len();
let _ = g.supertypes("p");
let _ = g.subtypes("p");
let _ = done.send((layout, g.is_a("p", "q")));
});
let (layout, is_a) = finished
.recv_timeout(std::time::Duration::from_secs(10))
.expect("cyclic multiple inheritance must not blow up the walk");
assert_eq!(layout, 2, "each entity contributes its slots once");
assert!(is_a);
}
#[test]
fn subtypes_is_the_inverse_of_is_a_under_multiple_inheritance() {
let g = SchemaGraph::from_express(DIAMOND);
let names: Vec<&str> = g.entity_names().collect();
for &ancestor in &names {
let down = g.subtypes(ancestor);
for &candidate in &names {
let expected = candidate != ancestor && g.is_a(candidate, ancestor);
assert_eq!(
down.contains(&candidate),
expected,
"{candidate} vs {ancestor}"
);
}
}
}
#[test]
fn ap242_positional_layouts_match_part21_on_multiple_inheritance() {
let Some(dir) = std::env::var_os("STEP_AP_SCHEMA_DIR") else {
return;
};
let path = std::path::Path::new(&dir).join("242_mim_lf.exp");
let g = SchemaGraph::from_express(&std::fs::read_to_string(path).expect("schema readable"));
assert_eq!(
g.attribute_names("advanced_face"),
["name", "bounds", "face_geometry", "same_sense"]
);
assert_eq!(
g.attribute_names("annotation_plane"),
["name", "styles", "item", "elements"]
);
assert_eq!(
g.attribute_names("common_datum"),
[
"name",
"description",
"of_shape",
"product_definitional",
"identification"
]
);
assert_eq!(
g.attribute_names("characterized_representation"),
["name", "items", "context_of_items", "name", "description"]
);
assert!(g.is_a("common_datum", "datum"));
}