use serde_json::Value;
use crate::{
error::Result,
runtime::{
memory::{peak_memory_source, peak_working_set_bytes},
ort_runtime::ort_runtime_fingerprint,
provider::ort_runtime_version,
},
};
pub const RUNTIME_FIELD_NAMES: [&str; 4] = [
"peak_working_set_bytes",
"memory_source",
"ort_runtime",
"ort_runtime_version",
];
pub fn attach_runtime_fields(report: &mut Value) -> Result<()> {
let object = report.as_object_mut().ok_or_else(|| {
crate::error::RapidOcrError::InvalidInput(
"an evaluation report must be a JSON object before the runtime fields can be \
attached; an array has no place to put them"
.to_string(),
)
})?;
object.insert(
"peak_working_set_bytes".to_string(),
serde_json::json!(peak_working_set_bytes()),
);
object.insert(
"memory_source".to_string(),
serde_json::json!(peak_memory_source()),
);
object.insert(
"ort_runtime".to_string(),
serde_json::to_value(ort_runtime_fingerprint())
.map_err(|error| crate::error::RapidOcrError::Config(error.to_string()))?,
);
object.insert(
"ort_runtime_version".to_string(),
serde_json::json!(ort_runtime_version()),
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::{RUNTIME_FIELD_NAMES, attach_runtime_fields};
use serde_json::json;
#[test]
fn every_named_field_is_actually_attached() {
let mut report = json!({ "mean_cer": 0.4476 });
attach_runtime_fields(&mut report).expect("an object report accepts runtime fields");
for name in RUNTIME_FIELD_NAMES {
assert!(
report.get(name).is_some(),
"the field {name} is declared as a runtime field but was not attached"
);
}
assert_eq!(report["mean_cer"], 0.4476);
}
#[test]
fn the_attachment_does_not_rename_or_drop_domain_fields() {
let mut report = json!({ "domain": "table", "metric_scope": { "structure_only": true } });
let before = report.clone();
attach_runtime_fields(&mut report).expect("an object report accepts runtime fields");
assert_eq!(report["domain"], before["domain"]);
assert_eq!(report["metric_scope"], before["metric_scope"]);
}
#[test]
fn an_array_is_rejected_rather_than_silently_left_alone() {
let mut report = json!([{ "image": "a.png", "cer": 0.0 }]);
let error = attach_runtime_fields(&mut report)
.expect_err("an array is not a report and cannot carry runtime fields");
assert!(
error.to_string().contains("must be a JSON object"),
"the error must say why an array is refused, got: {error}"
);
assert!(report.is_array());
}
#[test]
fn the_ort_fingerprint_is_an_object_not_a_bare_version_string() {
let mut report = json!({});
attach_runtime_fields(&mut report).expect("an empty object accepts runtime fields");
assert!(
report["ort_runtime"].is_object() || report["ort_runtime"].is_null(),
"ort_runtime must stay a structured fingerprint, got {}",
report["ort_runtime"]
);
}
}