recovery_property/
recovery_property.rs1#![allow(clippy::unreadable_literal, clippy::cast_possible_truncation)]
8
9use openbim_step::{parse_with, OnMalformed, ParseOptions};
10
11fn lcg(state: &mut u64) -> u64 {
12 *state = state
13 .wrapping_mul(6364136223846793005)
14 .wrapping_add(1442695040888963407);
15 *state >> 33
16}
17
18fn main() {
19 let base = "ISO-10303-21;\nHEADER;\nFILE_DESCRIPTION((''),'2;1');\n\
20 FILE_NAME('n','t',(''),(''),'p','o','a');\nFILE_SCHEMA(('IFC4'));\nENDSEC;\nDATA;\n\
21 #1= IFCPERSON($,$,'a;b',$,$,$,$,$);\n\
22 #2= IFCPIXELTEXTURE(1,1,8,(\"00AA;BB\"));\n\
23 #3= IFCORGANIZATION($,'o''x',$,$,$); /* c;c */\n\
24 #4= IFCDOOR('real');\nENDSEC;\nEND-ISO-10303-21;\n";
25
26 let mut state = 0x5eed_1234_u64;
27 let mut recovered = 0usize;
28 let mut fabricated = 0usize;
29 let mut span_faults = 0usize;
30
31 for _ in 0..20_000 {
32 let mut bytes = base.as_bytes().to_vec();
33 let edits = 1 + (lcg(&mut state) % 3) as usize;
35 for _ in 0..edits {
36 let at = 150 + (lcg(&mut state) as usize % (bytes.len() - 150));
37 match lcg(&mut state) % 3 {
38 0 => bytes[at] = b'@',
39 1 => {
40 bytes.remove(at);
41 }
42 _ => bytes[at] = (lcg(&mut state) % 128) as u8,
43 }
44 }
45
46 let Ok(outcome) = parse_with(
47 &bytes,
48 ParseOptions::default().on_malformed_record(OnMalformed::Skip),
49 ) else {
50 continue;
51 };
52 recovered += 1;
53
54 for diagnostic in &outcome.diagnostics {
55 let span = diagnostic.span();
56 if span.start > span.end || span.end > bytes.len() {
57 span_faults += 1;
58 }
59 }
60
61 for record in &outcome.exchange.data.records {
64 let needle = format!("#{}=", record.id.as_str());
65 let found = String::from_utf8_lossy(&bytes).contains(&needle)
66 || String::from_utf8_lossy(&bytes).contains(&format!("#{} =", record.id.as_str()));
67 if !found {
68 fabricated += 1;
69 eprintln!(
70 "FABRICATED {} in:\n{}",
71 needle,
72 String::from_utf8_lossy(&bytes)
73 );
74 }
75 }
76 }
77
78 println!("recovered={recovered} fabricated={fabricated} span_faults={span_faults}");
79 assert_eq!(fabricated, 0, "recovery invented records");
80 assert_eq!(span_faults, 0, "diagnostic span out of bounds");
81 println!("PROPERTY PROBE OK");
82}