use crate::{CadIr, NativeUnknownRecord};
fn record(key: &str, links: &[&str]) -> NativeUnknownRecord {
NativeUnknownRecord {
id: crate::ids::UnknownId::mint(format!("test:native:unknown#{key}")).unwrap(),
links: links
.iter()
.map(|link| (*link).try_into().unwrap())
.collect(),
}
}
#[test]
fn reserved_unknown_arena_accepts_owned_and_borrowed_records() {
let records = [record("b", &[]), record("a", &["test:model:body#0"])];
let mut owned = CadIr::empty();
owned
.set_native_unknowns_from(
&cadmpeg_test_support::service_decode_context(),
"test",
records.clone(),
)
.unwrap();
let mut borrowed = CadIr::empty();
borrowed
.set_native_unknowns_from(
&cadmpeg_test_support::service_decode_context(),
"test",
records.iter(),
)
.unwrap();
assert_eq!(owned, borrowed);
assert_eq!(
owned.native_unknowns("test").unwrap(),
[records[1].clone(), records[0].clone()]
);
let wire = owned.to_canonical_json().unwrap();
assert_eq!(CadIr::from_json(&wire).unwrap(), owned);
let value: serde_json::Value = serde_json::from_str(&wire).unwrap();
assert_eq!(
value["native"]["test"]["unknowns"],
serde_json::json!([
{"id": "test:native:unknown#a", "links": ["test:model:body#0"]},
{"id": "test:native:unknown#b"}
])
);
}
#[test]
fn duplicate_unknown_replacement_leaves_existing_document_unchanged() {
for existing in [false, true] {
let mut document = CadIr::empty();
if existing {
document
.set_native_unknowns(
&cadmpeg_test_support::service_decode_context(),
"test",
&[record("original", &[])],
)
.unwrap();
}
let before = document.clone();
let error = document
.set_native_unknowns_from(
&cadmpeg_test_support::service_decode_context(),
"test",
[
record("duplicate", &["test:model:body#first"]),
record("duplicate", &["test:model:body#second"]),
],
)
.unwrap_err();
assert!(
error.to_string().contains("test:native:unknown#duplicate"),
"{error}"
);
assert_eq!(document, before);
}
}
#[test]
fn complete_document_keeps_raw_native_fields_but_product_reader_checks_links() {
let mut document = CadIr::empty();
document
.set_native_unknowns(
&cadmpeg_test_support::service_decode_context(),
"test",
&[record("a", &["test:model:body#unresolved"])],
)
.unwrap();
let valid = serde_json::to_value(&document).unwrap();
let parsed = CadIr::from_json(&valid.to_string()).unwrap();
assert_eq!(
parsed.native_unknowns("test").unwrap(),
document.native_unknowns("test").unwrap()
);
for links in [
serde_json::json!(null),
serde_json::json!(true),
serde_json::json!(1),
serde_json::json!("test:model:body#unresolved"),
serde_json::json!({}),
serde_json::json!([null]),
serde_json::json!([false]),
serde_json::json!([3]),
serde_json::json!([{}]),
serde_json::json!([[]]),
serde_json::json!([""]),
serde_json::json!(["test:body#missing-scope"]),
] {
let mut wire = valid.clone();
wire["native"]["test"]["unknowns"][0]["links"] = links;
for parsed in [
CadIr::from_json(&wire.to_string()).unwrap(),
serde_json::from_value::<CadIr>(wire.clone()).unwrap(),
] {
assert_eq!(serde_json::to_value(&parsed).unwrap(), wire);
assert!(parsed.native_unknowns("test").is_err());
assert!(parsed.native_unknowns_iter("test").next().unwrap().is_err());
}
}
}
#[test]
fn native_unknown_replacement_keeps_the_document_on_depth_and_record_text_refusals() {
use cadmpeg_core::decode::{DecodeArena, DecodeContext, DecodePolicy, ResourceDimension};
use cadmpeg_core::CodecError;
for dimension in [
ResourceDimension::RetainedBytes,
ResourceDimension::RecursionDepth,
] {
let mut document = CadIr::empty();
document
.set_native_unknowns(
&cadmpeg_test_support::service_decode_context(),
"test",
&[record("prior", &[])],
)
.unwrap();
let before = document.clone();
let arena = DecodeArena::new();
let mut policy = DecodePolicy::service();
if dimension == ResourceDimension::RetainedBytes {
policy.limits.max_retained_bytes = 0;
} else {
policy.limits.max_recursion_depth = 0;
}
let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).unwrap();
let error = CodecError::from(
document
.set_native_unknowns(
&ctx,
"test",
&[record("incoming", &["test:model:body#one"])],
)
.unwrap_err(),
);
assert!(matches!(&error, CodecError::ResourceLimit(limit) if limit.dimension == dimension));
assert_eq!(
ctx.finish_session().unwrap_err().to_string(),
error.to_string()
);
assert_eq!(document, before);
}
}