use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReputationSection {
#[serde(skip_serializing_if = "Option::is_none")]
pub total_interactions: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub endorsement_count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trust_score: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uptime_30d: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uptime_90d: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub first_active: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub endorser_dids: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serde_round_trip() {
let rep = ReputationSection {
total_interactions: Some(10_000),
endorsement_count: Some(42),
trust_score: Some("0.87".to_string()),
uptime_30d: Some("99.9%".to_string()),
uptime_90d: Some("99.5%".to_string()),
first_active: Some("2026-01-01T00:00:00Z".to_string()),
endorser_dids: vec!["did:oas:prod:hmr:alice".to_string()],
};
let json = serde_json::to_string(&rep).unwrap_or_default();
let parsed: ReputationSection = serde_json::from_str(&json).unwrap_or_else(|_| rep.clone());
assert_eq!(rep, parsed);
}
#[test]
fn minimal_section_deserializes() {
let json = r#"{}"#;
let rep: Result<ReputationSection, _> = serde_json::from_str(json);
assert!(rep.is_ok());
}
#[test]
fn optional_fields_omitted() {
let rep = ReputationSection {
total_interactions: None,
endorsement_count: None,
trust_score: None,
uptime_30d: None,
uptime_90d: None,
first_active: None,
endorser_dids: vec![],
};
let json = serde_json::to_string(&rep).unwrap_or_default();
assert_eq!(json, "{}");
}
}