use super::*;
use ifc_lite_core::EntityDecoder;
fn wrap(data: &str) -> String {
format!(
"ISO-10303-21;\nHEADER;\nFILE_DESCRIPTION((''),'2;1');\n\
FILE_NAME('t.ifc','2024-01-01T00:00:00',(''),(''),'','','');\n\
FILE_SCHEMA(('IFC4'));\nENDSEC;\nDATA;\n{data}ENDSEC;\nEND-ISO-10303-21;\n"
)
}
fn identity_of(data: &str, id: u32) -> bool {
let content = wrap(data);
let (tx, rx) = std::sync::mpsc::channel();
let handle = std::thread::spawn(move || {
let mut decoder = EntityDecoder::new(&content);
let item = decoder.decode_by_id(id).expect("decode item");
let _ = tx.send(item_has_identity_position(item, &mut decoder));
});
let outcome = rx.recv_timeout(std::time::Duration::from_secs(30));
assert!(
outcome.is_ok(),
"item_has_identity_position did not terminate"
);
let _ = handle.join();
outcome.unwrap()
}
#[test]
fn self_referential_first_operand_terminates() {
assert!(!identity_of(
"#10=IFCBOOLEANRESULT(.DIFFERENCE.,#10,#20);\n#20=IFCBLOCK($,1.,1.,1.);\n",
10
));
}
#[test]
fn two_node_first_operand_cycle_terminates() {
assert!(!identity_of(
"#10=IFCBOOLEANRESULT(.DIFFERENCE.,#11,#20);\n\
#11=IFCBOOLEANRESULT(.DIFFERENCE.,#10,#20);\n\
#20=IFCBLOCK($,1.,1.,1.);\n",
10
));
}
#[test]
fn boolean_over_identity_extrusion_still_reports_identity() {
assert!(identity_of(
"#10=IFCBOOLEANRESULT(.DIFFERENCE.,#11,#20);\n\
#11=IFCEXTRUDEDAREASOLID(#12,#13,#16,3000.);\n\
#12=IFCRECTANGLEPROFILEDEF(.AREA.,$,$,200.,4000.);\n\
#13=IFCAXIS2PLACEMENT3D(#14,$,$);\n\
#14=IFCCARTESIANPOINT((0.,0.,0.));\n\
#16=IFCDIRECTION((0.,0.,1.));\n\
#20=IFCBLOCK($,1.,1.,1.);\n",
10
));
}
#[test]
fn boolean_over_translated_extrusion_reports_non_identity() {
assert!(!identity_of(
"#10=IFCBOOLEANRESULT(.DIFFERENCE.,#11,#20);\n\
#11=IFCEXTRUDEDAREASOLID(#12,#13,#16,3000.);\n\
#12=IFCRECTANGLEPROFILEDEF(.AREA.,$,$,200.,4000.);\n\
#13=IFCAXIS2PLACEMENT3D(#14,$,$);\n\
#14=IFCCARTESIANPOINT((500.,0.,0.));\n\
#16=IFCDIRECTION((0.,0.,1.));\n\
#20=IFCBLOCK($,1.,1.,1.);\n",
10
));
}
#[test]
fn a_long_acyclic_operand_chain_walks_all_the_way_down() {
let n: u32 = 20_000;
let mut data = String::new();
for i in 1..n {
data.push_str(&format!(
"#{}=IFCBOOLEANRESULT(.DIFFERENCE.,#{},#90000);\n",
i,
i + 1
));
}
data.push_str(&format!(
"#{n}=IFCEXTRUDEDAREASOLID(#90001,#90002,#90004,3000.);\n"
));
data.push_str("#90000=IFCBLOCK($,1.,1.,1.);\n");
data.push_str("#90001=IFCRECTANGLEPROFILEDEF(.AREA.,$,$,200.,4000.);\n");
data.push_str("#90002=IFCAXIS2PLACEMENT3D(#90003,$,$);\n");
data.push_str("#90003=IFCCARTESIANPOINT((0.,0.,0.));\n");
data.push_str("#90004=IFCDIRECTION((0.,0.,1.));\n");
assert!(
identity_of(&data, 1),
"a {n}-deep acyclic chain over an identity extrusion must report identity"
);
}