use std::io::Cursor;
use cadmpeg_core::decode::InspectOptions;
use cadmpeg_ir::codec::write::{target::TargetRequest, EncodeInput, Encoder};
use cadmpeg_ir::codec::{Codec, DecodeOptions};
use cadmpeg_test_support::golden::{elide_local_digests, snapshot_text, Branch, Harness};
use super::{StepCodec, StepSchema};
const FIXTURE_EXTENSION: &str = "p21";
const REGENERATE: &str = "UPDATE_GOLDEN=1 cargo test -p cadmpeg-codec-step golden";
fn harness() -> Harness {
Harness::new(env!("CARGO_MANIFEST_DIR"), FIXTURE_EXTENSION, REGENERATE)
.with_fixture_dir(std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures"))
}
fn branches() -> [Branch; 2] {
[
Branch::named("inspect", inspect_snapshot),
Branch::named("decode", decode_snapshot),
]
}
fn encode_branch() -> [Branch; 1] {
[Branch::named("encode", encode_snapshot)]
}
const ENCODE_FIXTURES: [&str; 4] = [
"ap203_sheet",
"ap214_sheet",
"ap242_minimal",
"ap242_geometry",
];
fn encode_inputs() -> Vec<(String, Vec<u8>)> {
let all = harness().fixture_inputs();
let selected: Vec<(String, Vec<u8>)> = all
.into_iter()
.filter(|(name, _)| ENCODE_FIXTURES.contains(&name.as_str()))
.collect();
assert_eq!(
selected.len(),
ENCODE_FIXTURES.len(),
"ENCODE_FIXTURES names a stem with no `.{FIXTURE_EXTENSION}` fixture"
);
selected
}
fn inspect_snapshot(bytes: &[u8]) -> String {
let value = match StepCodec::default()
.inspect(&mut Cursor::new(bytes.to_vec()), &InspectOptions::default())
{
Ok(summary) => serde_json::to_value(&summary).expect("serialize inspect summary"),
Err(error) => serde_json::json!({ "inspect_error": error.to_string() }),
};
snapshot_text(&value)
}
fn decode_snapshot(bytes: &[u8]) -> String {
let value = match StepCodec::default()
.decode(&mut Cursor::new(bytes.to_vec()), &DecodeOptions::default())
{
Ok(result) => {
let mut result = cadmpeg_test_support::EditableDecodeResult::from(result);
if let Some(source) = result.ir_mut().source.as_mut() {
elide_local_digests(&mut source.attributes);
}
serde_json::json!({
"ir": serde_json::to_value(result.ir()).expect("serialize ir"),
"report": serde_json::to_value(result.report()).expect("serialize report"),
"source_fidelity": serde_json::to_value(result.source_fidelity())
.expect("serialize source_fidelity"),
})
}
Err(error) => serde_json::json!({ "decode_error": error.to_string() }),
};
snapshot_text(&value)
}
fn encode_snapshot(bytes: &[u8]) -> String {
let decoded = match StepCodec::default()
.decode(&mut Cursor::new(bytes.to_vec()), &DecodeOptions::default())
{
Ok(result) => result,
Err(error) => {
return snapshot_text(&serde_json::json!({ "decode_error": error.to_string() }))
}
};
let value = serde_json::json!({
"inherit": encode_arm(&decoded, TargetRequest::Inherit),
"explicit_default": encode_arm(
&decoded,
TargetRequest::Explicit(StepSchema::Ap214.descriptor().id.as_str()),
),
"explicit_ap242_e3": encode_arm(
&decoded,
TargetRequest::Explicit(StepSchema::Ap242Edition3.descriptor().id.as_str()),
),
});
snapshot_text(&value)
}
fn encode_arm(
decoded: &cadmpeg_ir::codec::DecodeResult,
request: TargetRequest<'_>,
) -> serde_json::Value {
let outcome = Encoder::plan(
&StepCodec::default(),
EncodeInput::new(decoded.ir(), None),
request,
)
.and_then(|plan| {
let mut produced = Vec::new();
plan.write_to(&mut produced)
.map(|report| (report, produced))
});
match outcome {
Ok((report, produced)) => serde_json::json!({
"report": report,
"output": String::from_utf8_lossy(&produced),
}),
Err(error) => serde_json::json!({ "encode_error": error.to_string() }),
}
}
#[test]
fn golden_snapshots_hold() {
harness().check(&branches());
harness().check_inputs(&encode_inputs(), &encode_branch());
}
#[test]
fn golden_output_is_deterministic() {
harness().check_determinism(&branches());
harness().check_determinism_inputs(&encode_inputs(), &encode_branch());
}