use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IntentSlotTemplate {
#[serde(default)]
pub slots: Vec<String>,
#[serde(default)]
pub layout: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IntentModeTemplates {
#[serde(default)]
pub display: IntentSlotTemplate,
#[serde(default)]
pub input: IntentSlotTemplate,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ThemeTemplates {
#[serde(default)]
pub browse: Option<IntentModeTemplates>,
#[serde(default)]
pub focus: Option<IntentModeTemplates>,
#[serde(default)]
pub collect: Option<IntentModeTemplates>,
#[serde(default)]
pub process: Option<IntentModeTemplates>,
#[serde(default)]
pub summarize: Option<IntentModeTemplates>,
#[serde(default)]
pub analyze: Option<IntentModeTemplates>,
#[serde(default)]
pub track: Option<IntentModeTemplates>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn intent_slot_template_default_has_empty_slots_and_none_layout() {
let t = IntentSlotTemplate::default();
assert!(t.slots.is_empty());
assert!(t.layout.is_none());
}
#[test]
fn intent_mode_templates_default_has_empty_display_and_input() {
let t = IntentModeTemplates::default();
assert!(t.display.slots.is_empty());
assert!(t.display.layout.is_none());
assert!(t.input.slots.is_empty());
assert!(t.input.layout.is_none());
}
#[test]
fn theme_templates_deserializes_empty_json_to_all_none() {
let t: ThemeTemplates = serde_json::from_str("{}").unwrap();
assert!(t.browse.is_none());
assert!(t.focus.is_none());
assert!(t.collect.is_none());
assert!(t.process.is_none());
assert!(t.summarize.is_none());
assert!(t.analyze.is_none());
assert!(t.track.is_none());
}
#[test]
fn theme_templates_deserializes_partial_json_with_other_fields_none() {
let json = r#"{"browse": {"display": {"slots": ["title", "fields"]}}}"#;
let t: ThemeTemplates = serde_json::from_str(json).unwrap();
assert!(t.browse.is_some());
let browse = t.browse.unwrap();
assert_eq!(browse.display.slots, vec!["title", "fields"]);
assert!(browse.display.layout.is_none());
assert!(t.focus.is_none());
assert!(t.collect.is_none());
assert!(t.process.is_none());
assert!(t.summarize.is_none());
assert!(t.analyze.is_none());
assert!(t.track.is_none());
}
#[test]
fn theme_templates_deserializes_full_json_with_all_7_intents() {
let json = r#"{
"browse": {"display": {"slots": ["title"], "layout": "Table"}, "input": {"slots": ["fields"]}},
"focus": {"display": {"slots": ["title", "body"]}},
"collect": {"input": {"slots": ["fields", "actions"], "layout": "Form"}},
"process": {"display": {"slots": ["title", "actions"]}},
"summarize": {"display": {"slots": ["stats", "metadata"]}},
"analyze": {"display": {"slots": ["fields", "stats"]}},
"track": {"display": {"slots": ["title", "metadata", "pagination"]}}
}"#;
let t: ThemeTemplates = serde_json::from_str(json).unwrap();
assert!(t.browse.is_some());
assert!(t.focus.is_some());
assert!(t.collect.is_some());
assert!(t.process.is_some());
assert!(t.summarize.is_some());
assert!(t.analyze.is_some());
assert!(t.track.is_some());
let browse = t.browse.unwrap();
assert_eq!(browse.display.layout, Some("Table".to_string()));
assert_eq!(browse.display.slots, vec!["title"]);
assert_eq!(browse.input.slots, vec!["fields"]);
}
#[test]
fn theme_templates_serde_round_trip_preserves_all_fields() {
let original = ThemeTemplates {
browse: Some(IntentModeTemplates {
display: IntentSlotTemplate {
slots: vec!["title".to_string(), "fields".to_string()],
layout: Some("Table".to_string()),
},
input: IntentSlotTemplate::default(),
}),
focus: Some(IntentModeTemplates::default()),
collect: None,
process: None,
summarize: None,
analyze: None,
track: None,
};
let json = serde_json::to_string(&original).unwrap();
let restored: ThemeTemplates = serde_json::from_str(&json).unwrap();
assert!(restored.browse.is_some());
let browse = restored.browse.unwrap();
assert_eq!(browse.display.slots, vec!["title", "fields"]);
assert_eq!(browse.display.layout, Some("Table".to_string()));
assert!(restored.focus.is_some());
assert!(restored.collect.is_none());
}
}