use serde::Deserialize;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ParticipantMeta {
pub id: String,
pub config_schema: serde_json::Value,
}
pub fn parse_participant_metadata(section_bytes: &[u8]) -> serde_json::Result<ParticipantMeta> {
serde_json::from_slice(section_bytes)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_the_current_section_shape() {
let json = br#"{"id":"drive","config_schema":{"type":"object","properties":{"speed":{"type":"number"}}}}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert_eq!(meta.id, "drive");
assert_eq!(meta.config_schema["type"], "object");
}
#[test]
fn a_configless_participant_still_carries_its_id() {
let json = br#"{"id":"joypad","config_schema":{"type":"null"}}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert_eq!(meta.id, "joypad");
assert_eq!(meta.config_schema["type"], "null");
}
#[test]
fn malformed_json_is_a_clear_error() {
let err = parse_participant_metadata(b"not json").unwrap_err();
assert!(err.to_string().contains("expected"));
}
#[test]
fn missing_config_schema_is_rejected() {
let err = parse_participant_metadata(br#"{"id":"drive"}"#).unwrap_err();
assert!(err.to_string().contains("config_schema"));
}
#[test]
fn missing_id_is_rejected() {
let err = parse_participant_metadata(br#"{"config_schema":{"type":"null"}}"#).unwrap_err();
assert!(err.to_string().contains("id"));
}
#[test]
fn a_stale_section_with_a_contract_inventory_is_rejected() {
let json = br#"{"id":"drive","contracts":[],"config_schema":{"type":"null"}}"#;
let err = parse_participant_metadata(json).unwrap_err();
assert!(err.to_string().contains("contracts"), "{err}");
}
}