use ifc_element_type::table::{
IFCBEAMTYPE, IFCCREWRESOURCETYPE, IFCDOORTYPE, IFCFURNITURETYPE, IFCPUMPTYPE, IFCSPACETYPE,
IFCTASKTYPE,
};
use ifc_element_type::{create_type, Family, Slot6, TypeDraft, ALL};
use ifc_model::{Model, Transaction, Value};
const GUID: &str = "3Ss_vDJfz2dgLcbZKkqAd$";
#[test]
fn an_element_type_uses_the_element_layout() {
let model = Model::new();
let mut tx = Transaction::new(&model);
let id = create_type(
&mut tx,
IFCBEAMTYPE,
GUID,
Some("JOIST"),
TypeDraft::new()
.name("IPE 300")
.tag_or_long_description("B-01"),
)
.expect("a well formed beam type is accepted");
let mut model = model;
tx.commit(&mut model).expect("commit");
let e = model.get(id).expect("staged");
assert_eq!(e.type_name.as_ref(), "IFCBEAMTYPE");
assert_eq!(e.attributes.len(), 10);
assert_eq!(e.attributes[2], Value::Text("IPE 300".into()));
assert_eq!(e.attributes[7], Value::Text("B-01".into()), "Tag at 7");
assert_eq!(e.attributes[9], Value::Enum("JOIST".into()), "slot 9");
}
#[test]
fn a_resource_type_uses_the_later_predefined_slot() {
let model = Model::new();
let mut tx = Transaction::new(&model);
let id = create_type(
&mut tx,
IFCCREWRESOURCETYPE,
GUID,
Some("SITE"),
TypeDraft::new()
.name("T")
.maps_or_identification(Slot6::Identification("CREW-7"))
.tag_or_long_description("day shift"),
)
.expect("a well formed crew resource type is accepted");
let mut model = model;
tx.commit(&mut model).expect("commit");
let e = model.get(id).expect("staged");
assert_eq!(e.attributes.len(), 12);
assert_eq!(
e.attributes[6],
Value::Text("CREW-7".into()),
"Identification at 6"
);
assert_eq!(
e.attributes[7],
Value::Text("day shift".into()),
"LongDescription at 7"
);
assert_eq!(e.attributes[9], Value::Null, "BaseCosts stays empty");
assert_eq!(e.attributes[11], Value::Enum("SITE".into()), "slot 11");
}
#[test]
fn userdefined_without_its_fallback_is_refused() {
let model = Model::new();
let mut tx = Transaction::new(&model);
assert!(
create_type(
&mut tx,
IFCPUMPTYPE,
GUID,
Some("USERDEFINED"),
TypeDraft::new().name("T")
)
.is_err(),
"USERDEFINED with no ElementType"
);
assert!(
create_type(
&mut tx,
IFCPUMPTYPE,
GUID,
Some("USERDEFINED"),
TypeDraft::new().name("T").fallback(" "),
)
.is_err(),
"blank is not a name"
);
let ok = create_type(
&mut tx,
IFCPUMPTYPE,
GUID,
Some("USERDEFINED"),
TypeDraft::new().name("T").fallback("borehole pump"),
);
assert!(ok.is_ok(), "named USERDEFINED is accepted");
}
#[test]
fn a_token_from_another_enum_is_refused() {
let model = Model::new();
let mut tx = Transaction::new(&model);
assert!(
create_type(
&mut tx,
IFCPUMPTYPE,
GUID,
Some("JOIST"),
TypeDraft::new().name("T")
)
.is_err(),
"JOIST is a beam token"
);
assert!(
create_type(
&mut tx,
IFCBEAMTYPE,
GUID,
Some("SITE"),
TypeDraft::new().name("T")
)
.is_err(),
"SITE is a crew token"
);
assert!(
create_type(&mut tx, IFCBEAMTYPE, GUID, None, TypeDraft::new().name("T")).is_err(),
"a required predefined type cannot be omitted"
);
assert!(
create_type(
&mut tx,
IFCFURNITURETYPE,
GUID,
None,
TypeDraft::new().name("T").assembly_place("FACTORY")
)
.is_ok(),
"furniture declares it optional"
);
assert!(
create_type(
&mut tx,
IFCBEAMTYPE,
"not-a-guid",
Some("JOIST"),
TypeDraft::new().name("T")
)
.is_err(),
"malformed GlobalId"
);
}
#[test]
fn slot_six_shape_must_match_the_family() {
let model = Model::new();
let mut tx = Transaction::new(&model);
let map = tx.create(ifc_model::Entity::new(
"IFCREPRESENTATIONMAP",
vec![Value::Null; 2],
));
assert!(
create_type(
&mut tx,
IFCTASKTYPE,
GUID,
Some("CONSTRUCTION"),
TypeDraft::new()
.name("T")
.maps_or_identification(Slot6::RepresentationMaps(&[map])),
)
.is_err(),
"a task type has no representation maps"
);
assert!(
create_type(
&mut tx,
IFCBEAMTYPE,
GUID,
Some("JOIST"),
TypeDraft::new()
.name("T")
.maps_or_identification(Slot6::Identification("X")),
)
.is_err(),
"a beam type has no identification at 6"
);
}
#[test]
fn the_catalogue_holds_its_invariants() {
assert_eq!(ALL.len(), 132, "concrete IfcTypeObject subtypes");
for t in ALL {
assert_eq!(
t.fallback_slot, 8,
"{}: fallback is always slot 8",
t.type_name
);
assert!(
t.predefined_slot > t.fallback_slot,
"{}: predefined type follows the fallback",
t.type_name
);
assert!(
t.predefined_slot < t.arity,
"{}: predefined slot inside the entity",
t.type_name
);
assert!(
t.members.contains(&"USERDEFINED"),
"{}: the rule is meaningless without the token",
t.type_name
);
assert!(t.type_name.starts_with("IFC"), "{}", t.type_name);
assert!(t.type_name.ends_with("TYPE"), "{}", t.type_name);
}
let resource = ALL
.iter()
.filter(|t| t.fallback_attr == "ResourceType")
.count();
assert_eq!(resource, 6, "six resource types");
let process = ALL
.iter()
.filter(|t| t.fallback_attr == "ProcessType")
.count();
assert_eq!(process, 3, "event, procedure, task");
assert_eq!(IFCSPACETYPE.fallback_attr, "ElementType");
assert_eq!(IFCDOORTYPE.predefined_slot, 9);
assert_eq!(IFCFURNITURETYPE.predefined_slot, 10);
assert_eq!(
ALL.iter().filter(|t| t.predefined_optional).count(),
2,
"only furniture and system furniture make it optional"
);
assert_eq!(IFCCREWRESOURCETYPE.family, Family::ResourceOrProcess);
assert_eq!(IFCBEAMTYPE.family, Family::Element);
}
#[test]
fn the_fallback_name_reaches_slot_eight() {
let model = Model::new();
let mut tx = Transaction::new(&model);
let pump = create_type(
&mut tx,
IFCPUMPTYPE,
GUID,
Some("USERDEFINED"),
TypeDraft::new().name("T").fallback("borehole pump"),
)
.expect("named USERDEFINED");
let crew = create_type(
&mut tx,
IFCCREWRESOURCETYPE,
GUID,
Some("USERDEFINED"),
TypeDraft::new().name("T").fallback("night gang"),
)
.expect("named USERDEFINED");
let mut model = model;
tx.commit(&mut model).expect("commit");
assert_eq!(
model.get(pump).expect("staged").attributes[8],
Value::Text("borehole pump".into()),
"ElementType at 8"
);
assert_eq!(
model.get(crew).expect("staged").attributes[8],
Value::Text("night gang".into()),
"ResourceType at 8, same slot, different name"
);
}