mindtask/model/
concept.rs1use serde::{Deserialize, Serialize};
4
5use super::id::ConceptId;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct Concept {
13 pub id: ConceptId,
15 pub name: String,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub description: Option<String>,
20 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub parent: Option<ConceptId>,
23}
24
25#[cfg(test)]
26mod tests {
27 use super::*;
28
29 #[test]
30 fn concept_serde_roundtrip() {
31 let concept = Concept {
32 id: ConceptId(1),
33 name: "Backend".to_string(),
34 description: Some("Server-side code".to_string()),
35 parent: None,
36 };
37 let json = serde_json::to_string_pretty(&concept).unwrap();
38 let parsed: Concept = serde_json::from_str(&json).unwrap();
39 assert_eq!(parsed.id, concept.id);
40 assert_eq!(parsed.name, concept.name);
41 assert_eq!(parsed.description, concept.description);
42 assert_eq!(parsed.parent, concept.parent);
43 }
44
45 #[test]
46 fn concept_skips_none_fields() {
47 let concept = Concept {
48 id: ConceptId(1),
49 name: "Root".to_string(),
50 description: None,
51 parent: None,
52 };
53 let json = serde_json::to_string(&concept).unwrap();
54 assert!(!json.contains("description"));
55 assert!(!json.contains("parent"));
56 }
57
58 #[test]
59 fn concept_with_parent() {
60 let concept = Concept {
61 id: ConceptId(2),
62 name: "Child".to_string(),
63 description: None,
64 parent: Some(ConceptId(1)),
65 };
66 let json = serde_json::to_string(&concept).unwrap();
67 assert!(json.contains("\"parent\":1"));
68 let parsed: Concept = serde_json::from_str(&json).unwrap();
69 assert_eq!(parsed.parent, Some(ConceptId(1)));
70 }
71}