use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[serde(rename_all="kebab-case")]
struct VectorFile {
base_uri: String,
#[serde(with = "hex")]
base_cri: Vec<u8>,
test_vectors: Vec<VectorItem>,
}
#[derive(Deserialize)]
#[serde(rename_all="kebab-case")]
struct VectorItem {
uri: Option<String>,
#[serde(with = "hex")]
cri: Vec<u8>,
uri_from_cri: Option<String>,
#[serde(with = "hex")]
resolved_cri: Vec<u8>,
resolved_uri: String,
description: Option<String>,
invalid: Option<String>,
}
impl core::fmt::Debug for VectorItem {
fn fmt(&self, w: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
fn pretty(data: &[u8]) -> String {
cbor_diag::parse_bytes(data)
.map(|parsed| parsed.to_diag_pretty())
.unwrap_or_else(|_| hex::encode(&data))
}
writeln!(w, "VectorItem {{")?;
if let Some(description) = &self.description {
writeln!(w, " description: {description}")?;
}
if let Some(uri) = &self.uri {
writeln!(w, " uri: {uri}")?;
}
writeln!(w, " cri: {}", pretty(&self.cri))?;
if let Some(uri_from_cri) = &self.uri_from_cri {
writeln!(w, " uri_from_cri: {uri_from_cri}")?;
}
writeln!(w, " resolved_cri: {}", pretty(&self.resolved_cri))?;
writeln!(w, " resolved_uri: {}", self.resolved_uri)?;
if let Some(invalid) = &self.invalid {
writeln!(w, " invalid: {invalid}")?;
}
writeln!(w, "}}")?;
Ok(())
}
}
#[test]
fn test_vectors() -> Result<(), std::io::Error> {
use crate::native_cbor::{NativeCBORCriRef, NativeCBORCri};
use crate::accessor::{CriRef, Cri};
let mut parse_failures = 0;
let mut rebuild_failures = 0;
let testfiles = ["test/tests.json"];
for f in testfiles {
let v: VectorFile = serde_json::from_reader(
std::fs::File::open(f)
.expect("Test file not found"))
.expect("Failed to load test file");
let base_cri: NativeCBORCriRef = v.base_cri[..].try_into().expect("Failed to parse base CRI");
let base_cri: NativeCBORCri = base_cri.try_into().expect("Base CRI is not absolute");
assert_eq!(v.base_uri, base_cri.render_uri(), "Base CRI of file {} mismatched with base URI", f);
for i in v.test_vectors {
match (i.cri[..].try_into(), i.resolved_cri[..].try_into()) {
(Err(e), _) => {
println!("Failed to parse CRI reference {:?}: {:?}", i, e);
parse_failures += 1;
}
(_, Err(e)) => {
println!("Failed to parse resolved CRI {:?}: {:?}", i, e);
parse_failures += 1;
}
(Ok(cri @ NativeCBORCriRef { .. }), Ok(resolved_cri @ NativeCBORCriRef { .. })) => {
let rebuilt = cri.render_uri_ref_like();
if let Some(uri_from_cri) = &i.uri_from_cri {
if i.invalid.is_none() {
if &rebuilt != uri_from_cri {
rebuild_failures += 1;
println!("Failed to rebuild {:?}:\nCRI is {:?},\nexpected <{}>,\nproduced <{}>", i, cri, uri_from_cri, rebuilt);
}
}
} else {
println!("Warning: Rebuilt URI {} from CRI even though test vector says there is no corresponding CRI reference.\n{:?}", rebuilt, i);
}
if let Ok(absolute @ NativeCBORCri { .. }) = cri.clone().try_into() {
let rebuilt_absolute = absolute.render_uri();
if rebuilt_absolute != rebuilt {
println!("Failed to rebuild URI form of {i:?}\nURI <{rebuilt_absolute}>\nref <{rebuilt}>.");
rebuild_failures += 1;
}
}
let resolved_cri: NativeCBORCri = resolved_cri.try_into()
.expect("Resolved CRI should not just be a reference");
let built_from_preresolved = resolved_cri.render_uri();
if i.invalid.is_none() && built_from_preresolved != i.resolved_uri {
println!("Failed to rebuild resolved URI from preresolved CRI {:?}\nCRI is {:?}\nexpected <{}>\nproduced <{}>", i, resolved_cri, i.resolved_uri, built_from_preresolved);
rebuild_failures += 1;
}
let resolved = base_cri.resolve(cri);
let built_resolved_uri = resolved.render_uri();
if i.invalid.is_none() {
if built_resolved_uri != i.resolved_uri {
println!("URI form of resolved value differs for {i:?}\nexpected <{}>\nproduced <{}>", i.resolved_uri, built_resolved_uri);
rebuild_failures += 1;
} else {
assert!(resolved.equals(&resolved_cri), "Equality check failed");
}
}
if i.uri_from_cri.map(|a| a == "") != Some(true) {
assert!(!resolved.equals(&base_cri), "Resolved should not equal base CRI");
}
}
};
}
}
assert_eq!(parse_failures, 0, "Some vectors could not be parsed");
assert_eq!(rebuild_failures, 0, "Some vectors could not be rebuilt");
Ok(())
}