117 lines
4.3 KiB
Rust
117 lines
4.3 KiB
Rust
//! Source-only preflight; parent compiles/runs this against its exact oa-core.
|
|
//! Usage: preflight.exe PATH_TO_lifecycle-native.arcadia
|
|
use oa_core::{operations, source_project, validation, *};
|
|
use std::collections::BTreeMap;
|
|
|
|
fn id(n: u128) -> Id {
|
|
Id::from_u128(0x21c0fe00000040008000000000000000 + n)
|
|
}
|
|
fn main() {
|
|
let args: Vec<_> = std::env::args().collect();
|
|
assert_eq!(args.len(), 2, "Pass the prepared source file");
|
|
let source = std::fs::read_to_string(&args[1]).unwrap();
|
|
let p = language::parse(&source).expect("Prepared source must parse through actual core");
|
|
let issues = validation::validate(&p);
|
|
let errors: Vec<_> = issues
|
|
.iter()
|
|
.filter(|issue| issue.severity == validation::Severity::Error)
|
|
.collect();
|
|
assert!(errors.is_empty(), "Fixture admission failed: {errors:#?}");
|
|
validate_candidate(&p).expect("Ordinary command admission must accept the whole Project");
|
|
let bundle = source_project::SourceBundle {
|
|
entry: "lifecycle-native.arcadia".into(),
|
|
files: BTreeMap::from([("lifecycle-native.arcadia".into(), source.clone())]),
|
|
};
|
|
let compiled = source_project::compile_bundle(&bundle, Default::default())
|
|
.expect("Use the actual source-project admission path");
|
|
assert_eq!(
|
|
compiled.bundle, bundle,
|
|
"Keep comments, Unicode and all explicit IDs byte-for-byte"
|
|
);
|
|
assert_eq!(compiled.decoded.project, p);
|
|
let canonical = language::format(&p);
|
|
let reparsed = language::parse(&canonical).unwrap();
|
|
assert_eq!(
|
|
reparsed, p,
|
|
"Compare the entire Project, not selected elements"
|
|
);
|
|
assert_eq!(language::format(&reparsed), canonical);
|
|
assert_eq!(p.elements.len(), 61);
|
|
assert_eq!(p.relations.len(), 5);
|
|
for (owner, steps) in [
|
|
(1000, vec![1005, 1040, 1030, 1060, 1050, 1070]),
|
|
(2000, vec![2005, 2040, 2030, 2060, 2050, 2070]),
|
|
(3000, vec![3010, 3020, 3040, 3050, 3070]),
|
|
(4000, vec![4040, 4080]),
|
|
(5000, vec![5040, 5070, 5050]),
|
|
(6000, vec![6080]),
|
|
] {
|
|
assert_eq!(
|
|
p.elements[&id(owner)].steps().unwrap(),
|
|
&steps.into_iter().map(id).collect::<Vec<_>>()
|
|
);
|
|
}
|
|
for base in [1000, 2000] {
|
|
for (offset, call, expression) in [
|
|
(40, 40, "420.0"),
|
|
(30, 30, "380.0"),
|
|
(60, 30, "378.0"),
|
|
(50, 40, "418.0"),
|
|
] {
|
|
let occurrence = id(base + offset);
|
|
let Some(SharedBody::Occurrence {
|
|
body: OccurrenceBody::Exchange { values, .. },
|
|
..
|
|
}) = p.elements[&occurrence].shared()
|
|
else {
|
|
panic!("Expected an exchange occurrence")
|
|
};
|
|
assert_eq!(values.len(), 1);
|
|
assert_eq!(values[0].expression, expression);
|
|
if base == 2000 {
|
|
let operations::OperationResolution::Selected(proof) =
|
|
operations::resolve(&p, occurrence).unwrap()
|
|
else {
|
|
panic!("SA pressure operation must remain actually bound")
|
|
};
|
|
assert_eq!(proof.invocation, id(base + call));
|
|
assert_eq!(proof.allocation, id(220));
|
|
assert_eq!(proof.caller_port, id(202));
|
|
assert_eq!(proof.provider_port, id(203));
|
|
} else {
|
|
assert_eq!(
|
|
operations::resolve(&p, occurrence).unwrap(),
|
|
operations::OperationResolution::Ordinary
|
|
);
|
|
}
|
|
}
|
|
}
|
|
let Some(SharedBody::Occurrence {
|
|
body:
|
|
OccurrenceBody::Exchange {
|
|
sender,
|
|
receiver,
|
|
reply_to,
|
|
..
|
|
},
|
|
..
|
|
}) = p.elements[&id(5050)].shared()
|
|
else {
|
|
panic!("Expected incomplete reply")
|
|
};
|
|
assert_eq!(
|
|
(*sender, *receiver, *reply_to),
|
|
(None, Some(id(5001)), Some(id(5040)))
|
|
);
|
|
for issue in &issues {
|
|
println!(
|
|
"{:?} {} {:?}: {}",
|
|
issue.severity, issue.code, issue.element, issue.message
|
|
);
|
|
}
|
|
println!(
|
|
"PASS: six scenarios,61 elements,5 relations,zero Errors,{} warnings; exact source bundle and whole-Project roundtrip; bound OA values and SA operation proofs preserved",
|
|
issues.len()
|
|
);
|
|
}
|