mod common;
use common::{bytes_to_hex, json_value_to_ipld};
use content_addressable::{canonical, ContentId};
struct Input {
name: &'static str,
value_json: &'static str,
}
fn inputs() -> Vec<Input> {
vec![
Input {
name: "empty_map",
value_json: "{}",
},
Input {
name: "empty_list",
value_json: "[]",
},
Input {
name: "null",
value_json: "null",
},
Input {
name: "bool_true",
value_json: "true",
},
Input {
name: "bool_false",
value_json: "false",
},
Input {
name: "integer",
value_json: "42",
},
Input {
name: "string",
value_json: "\"hello\"",
},
Input {
name: "map_order_independent",
value_json: "{\"zeta\": 1, \"alpha\": 2}",
},
Input {
name: "nested_map",
value_json: "{\"outer\": {\"b\": 2, \"a\": 1}, \"k\": [1, 2, 3]}",
},
Input {
name: "mixed_list",
value_json: "[1, \"two\", [3, 4], null, true]",
},
Input {
name: "ints_strings_bytes_mix",
value_json: "{\"n\": 7, \"s\": \"raw\", \"b\": {\"$bytes\": \"000102ff\"}}",
},
Input {
name: "sample_a",
value_json: "{\"name\": \"hello\", \"attrs\": {\"zeta\": 26, \"alpha\": 1}}",
},
Input {
name: "deeply_nested",
value_json: "{\"a\": {\"b\": {\"c\": {\"d\": [1, [2, [3, [4]]]]}}}}",
},
]
}
fn render(entries: &[Entry]) -> String {
let mut out = String::new();
out.push_str("[\n");
for (i, e) in entries.iter().enumerate() {
out.push_str(" {\n");
out.push_str(&format!(" \"name\": {},\n", json_string(e.name)));
out.push_str(&format!(" \"value\": {},\n", e.value_json));
out.push_str(&format!(
" \"canonical_dagcbor_hex\": {},\n",
json_string(&e.canonical_dagcbor_hex)
));
out.push_str(&format!(
" \"content_id_str\": {},\n",
json_string(&e.content_id_str)
));
out.push_str(&format!(
" \"content_id_bytes_hex\": {},\n",
json_string(&e.content_id_bytes_hex)
));
out.push_str(&format!(
" \"digest_hex\": {}\n",
json_string(&e.digest_hex)
));
if i + 1 < entries.len() {
out.push_str(" },\n");
} else {
out.push_str(" }\n");
}
}
out.push_str("]\n");
out
}
fn json_string(s: &str) -> String {
serde_json::to_string(s).expect("string is always JSON-encodable")
}
struct Entry {
name: &'static str,
value_json: &'static str,
canonical_dagcbor_hex: String,
content_id_str: String,
content_id_bytes_hex: String,
digest_hex: String,
}
#[test]
#[ignore = "writes tests/vectors.json; run explicitly with --ignored to regenerate"]
fn gen_vectors() {
let entries: Vec<Entry> = inputs()
.into_iter()
.map(|input| {
let value: serde_json::Value =
serde_json::from_str(input.value_json).expect("vector value_json must be valid");
let ipld = json_value_to_ipld(&value);
let bytes = canonical::to_canonical_dagcbor(&ipld).expect("vector must encode");
let id = ContentId::from_canonical_bytes(&bytes);
Entry {
name: input.name,
value_json: input.value_json,
canonical_dagcbor_hex: bytes_to_hex(&bytes),
content_id_str: id.to_string(),
content_id_bytes_hex: bytes_to_hex(&id.to_bytes()),
digest_hex: id.digest_hex(),
}
})
.collect();
let rendered = render(&entries);
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/vectors.json");
std::fs::write(path, rendered).expect("write tests/vectors.json");
eprintln!("wrote {} vectors to {path}", entries.len());
}