#![allow(missing_docs)]
use openbim_step::express::{parse, Attribute, EntityDef, ParsedSchema, TypeDef, TypeKind};
#[test]
fn schema_model_builders_preserve_the_ifc_schema_surface() {
let attribute = Attribute::new("Items", "IfcLabel").optional().aggregate();
assert!(attribute.optional);
assert!(attribute.aggregate);
let entity = EntityDef::new("IfcExample")
.with_supertype("IfcRoot")
.with_attribute(attribute);
assert_eq!(entity.supertype.as_deref(), Some("IfcRoot"));
assert_eq!(entity.attributes.len(), 1);
let defined = TypeDef {
name: "IfcLabel".into(),
kind: TypeKind::Defined("STRING".into()),
};
assert!(defined.is_defined());
}
const SCHEMA: &str = r"
SCHEMA DEMO;
(* ENTITY Fake; value : TEXT; END_ENTITY; *)
TYPE Distance = REAL;
END_TYPE;
TYPE Shade = ENUMERATION OF (RED, GREEN, BLUE);
END_TYPE;
TYPE AnyValue = SELECT (Distance, Shade);
END_TYPE;
ENTITY Root ABSTRACT SUPERTYPE OF (ONEOF(Item));
Label : OPTIONAL STRING;
END_ENTITY;
ENTITY Item SUBTYPE OF (Root);
Size : Distance;
Points : LIST [1:?] OF Distance;
DERIVE
Doubled : Distance := Size * 2;
WHERE
Positive : Size > 0;
END_ENTITY;
END_SCHEMA;
";
#[test]
fn structural_partial_express_parser_extracts_supported_declarations() {
let ParsedSchema {
name,
entities,
types,
} = parse(SCHEMA);
assert_eq!(name, "DEMO");
assert_eq!(entities.len(), 2);
assert_eq!(types.len(), 3);
let root = &entities[0];
assert_eq!(
root,
&EntityDef {
name: "Root".into(),
supertype: None,
abstract_: true,
attributes: vec![Attribute {
name: "Label".into(),
type_name: "STRING".into(),
optional: true,
aggregate: false
}],
derived: Vec::new(),
}
);
let item = &entities[1];
assert_eq!(item.supertype.as_deref(), Some("Root"));
assert_eq!(
item.attributes.len(),
2,
"DERIVE and WHERE are not explicit slots"
);
assert!(item.attributes[1].aggregate);
assert_eq!(
types[0],
TypeDef {
name: "Distance".into(),
kind: TypeKind::Defined("REAL".into())
}
);
assert_eq!(
types[1].kind,
TypeKind::Enumeration(vec!["RED".into(), "GREEN".into(), "BLUE".into()])
);
assert_eq!(
types[2].kind,
TypeKind::Select(vec!["Distance".into(), "Shade".into()])
);
}
#[test]
fn derive_blocks_report_redeclared_attribute_names() {
let source = "\
SCHEMA test;
ENTITY parent;
Precision : REAL;
Dimension : INTEGER;
END_ENTITY;
ENTITY child
SUBTYPE OF (parent);
ParentRef : parent;
DERIVE
SELF\\parent.Precision : REAL := NVL(ParentRef.Precision, 1.E-5);
SELF\\parent.Dimension : INTEGER := ParentRef.Dimension;
WHERE
NoSub : TRUE;
END_ENTITY;
END_SCHEMA;
";
let schema = parse(source);
let child = schema
.entities
.iter()
.find(|entity| entity.name == "child")
.expect("child entity");
assert_eq!(
child.derived,
vec!["Precision".to_owned(), "Dimension".to_owned()],
"the SELF\\Entity. prefix names the supertype, not the attribute"
);
assert!(
child.is_derived("precision"),
"matching is case-insensitive"
);
assert!(
!child.is_derived("ParentRef"),
"explicit attributes are not derived"
);
assert!(!child.is_derived("NoSub"));
let parent = schema
.entities
.iter()
.find(|entity| entity.name == "parent")
.expect("parent entity");
assert!(parent.derived.is_empty());
}
#[test]
fn unqualified_derived_attributes_are_reported() {
let source = "\
SCHEMA test;
ENTITY thing;
Length : REAL;
DERIVE
Area : REAL := Length * Length;
END_ENTITY;
END_SCHEMA;
";
let schema = parse(source);
let thing = &schema.entities[0];
assert_eq!(thing.derived, vec!["Area".to_owned()]);
assert_eq!(
thing.attributes.len(),
1,
"a derived attribute is not an explicit positional attribute"
);
}
#[test]
fn where_rule_labels_are_not_reported_as_derived() {
let source = "\
SCHEMA test;
ENTITY child;
ParentRef : INTEGER;
DERIVE
SELF\\parent.Precision : REAL := 1.0;
WHERE
FirstRule : TRUE;
SecondRule : TRUE;
ThirdRule : TRUE;
END_ENTITY;
END_SCHEMA;
";
let schema = parse(source);
let child = &schema.entities[0];
assert_eq!(
child.derived,
vec!["Precision".to_owned()],
"only the DERIVE statement, not the WHERE rule labels"
);
for rule in ["FirstRule", "SecondRule", "ThirdRule"] {
assert!(
!child.is_derived(rule),
"{rule} is a constraint, not an attribute"
);
}
}
#[test]
fn inverse_and_unique_clauses_do_not_leak_into_derived() {
let source = "\
SCHEMA test;
ENTITY child;
Ref : INTEGER;
DERIVE
Computed : REAL := 1.0;
INVERSE
FirstBack : SET OF other FOR Ref;
SecondBack : SET OF other FOR Ref;
UNIQUE
FirstKey : Ref;
SecondKey : Ref;
END_ENTITY;
END_SCHEMA;
";
let schema = parse(source);
let child = &schema.entities[0];
assert_eq!(child.derived, vec!["Computed".to_owned()]);
for name in ["FirstBack", "SecondBack", "FirstKey", "SecondKey"] {
assert!(!child.is_derived(name), "{name} must not be derived");
}
}