use serde_json::Value;
pub fn canonicalize(value: &Value) -> anyhow::Result<Vec<u8>> {
serde_jcs::to_vec(value).map_err(|e| anyhow::anyhow!("JCS canonicalization: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn object_keys_are_sorted_and_compact() {
let out = canonicalize(&json!({"b": 1, "a": 2, "c": 3})).unwrap();
assert_eq!(out, br#"{"a":2,"b":1,"c":3}"#);
}
#[test]
fn nested_object_keys_are_sorted() {
let out = canonicalize(&json!({"z": {"b": 1, "a": 2}, "a": 0})).unwrap();
assert_eq!(out, br#"{"a":0,"z":{"a":2,"b":1}}"#);
}
#[test]
fn key_order_is_irrelevant_to_output() {
let a = canonicalize(&json!({"one": 1, "two": 2})).unwrap();
let b = canonicalize(&json!({"two": 2, "one": 1})).unwrap();
assert_eq!(a, b, "canonical form must not depend on source key order");
}
#[test]
fn integer_valued_float_is_normalized() {
assert_eq!(canonicalize(&json!(1.0)).unwrap(), b"1");
assert_eq!(canonicalize(&json!({"v": 3.0})).unwrap(), br#"{"v":3}"#);
}
#[test]
fn no_insignificant_whitespace() {
let out = canonicalize(&json!({"a": [1, 2, 3], "b": "x"})).unwrap();
let s = String::from_utf8(out).unwrap();
assert!(
!s.contains(' ') && !s.contains('\n'),
"JCS output has no insignificant whitespace: {s}"
);
}
}