use serde_json::Value;
use sha2::{Digest, Sha256};
use std::{fs, path::Path};
use webmcp::{Manifest, Tool, ToolDef, Transport, RUNTIME_JS, RUNTIME_SHA256};
fn fixture(name: &str) {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("conformance/fixtures")
.join(name);
let fixture: Value = serde_json::from_slice(&fs::read(path).unwrap()).unwrap();
let definition: ToolDef = serde_json::from_value(fixture["definition"].clone()).unwrap();
let transport: Transport = serde_json::from_value(fixture["transport"].clone()).unwrap();
let tool = Tool::new(definition).unwrap();
let manifest = Manifest::build(&[&tool], transport).unwrap();
let parsed: Value = serde_json::from_str(&manifest.to_json()).unwrap();
assert_eq!(parsed["webmcpManifestVersion"], 1);
assert_eq!(parsed["transport"], fixture["transport"]);
assert_eq!(parsed["tools"].as_array().unwrap().len(), 1);
assert_eq!(parsed["tools"][0], fixture["expected"], "fixture {name}");
}
#[test]
fn read_array_fixture() {
fixture("read-array.json");
}
#[test]
fn write_post_fixture() {
fixture("write-post.json");
}
#[test]
fn projection_result_fixture() {
fixture("projection-result.json");
}
#[test]
fn every_shared_fixture() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("conformance/fixtures");
let mut names: Vec<String> = fs::read_dir(dir)
.unwrap()
.map(|entry| entry.unwrap().file_name().into_string().unwrap())
.filter(|name| name.ends_with(".json"))
.collect();
names.sort();
assert!(
names.len() >= 4,
"expected the shared fixtures, found {names:?}"
);
for name in names {
fixture(&name);
}
}
#[test]
fn runtime_matches_pinned_sha256() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let pin = fs::read_to_string(root.join("conformance/RUNTIME.sha256")).unwrap();
let fields: Vec<_> = pin.split_whitespace().collect();
assert_eq!(fields.len(), 2);
assert_eq!(fields[1], "runtime/webmcp-runtime.js");
let bytes = fs::read(root.join(fields[1])).unwrap();
assert_eq!(bytes, RUNTIME_JS.as_bytes());
assert_eq!(format!("{:x}", Sha256::digest(&bytes)), fields[0]);
assert_eq!(RUNTIME_SHA256, fields[0]);
}