pflow_tokenmodel/
validate.rs1use std::collections::HashSet;
4
5use crate::error::{Error, Result};
6use crate::schema::Schema;
7
8impl Schema {
9 pub fn validate(&self) -> Result<()> {
11 let mut state_ids = HashSet::new();
12 let mut action_ids = HashSet::new();
13
14 for st in &self.states {
15 if st.id.is_empty() {
16 return Err(Error::EmptyId);
17 }
18 if !state_ids.insert(st.id.clone()) {
19 return Err(Error::DuplicateId(st.id.clone()));
20 }
21 }
22
23 for a in &self.actions {
24 if a.id.is_empty() {
25 return Err(Error::EmptyId);
26 }
27 if !action_ids.insert(a.id.clone()) {
28 return Err(Error::DuplicateId(a.id.clone()));
29 }
30 }
31
32 for arc in &self.arcs {
33 let source_is_state = state_ids.contains(&arc.source);
34 let source_is_action = action_ids.contains(&arc.source);
35 let target_is_state = state_ids.contains(&arc.target);
36 let target_is_action = action_ids.contains(&arc.target);
37
38 if !source_is_state && !source_is_action {
39 return Err(Error::InvalidArcSource(arc.source.clone()));
40 }
41 if !target_is_state && !target_is_action {
42 return Err(Error::InvalidArcTarget(arc.target.clone()));
43 }
44 if (source_is_state && target_is_state) || (source_is_action && target_is_action) {
45 return Err(Error::InvalidArcConnection);
46 }
47 }
48
49 Ok(())
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use crate::schema::*;
56
57 #[test]
58 fn test_valid_schema() {
59 let mut s = Schema::new("test");
60 s.add_token_state("p1", 1);
61 s.add_action(Action {
62 id: "t1".into(),
63 guard: String::new(),
64 event_id: String::new(),
65 event_bindings: None,
66 });
67 s.add_arc(Arc {
68 source: "p1".into(),
69 target: "t1".into(),
70 keys: vec![],
71 value: String::new(),
72 });
73 assert!(s.validate().is_ok());
74 }
75
76 #[test]
77 fn test_empty_id() {
78 let mut s = Schema::new("test");
79 s.add_state(State {
80 id: String::new(),
81 kind: Kind::Token,
82 initial: None,
83 typ: String::new(),
84 exported: false,
85 });
86 assert!(s.validate().is_err());
87 }
88
89 #[test]
90 fn test_duplicate_id() {
91 let mut s = Schema::new("test");
92 s.add_token_state("p1", 1);
93 s.add_token_state("p1", 2);
94 assert!(s.validate().is_err());
95 }
96
97 #[test]
98 fn test_invalid_arc_source() {
99 let mut s = Schema::new("test");
100 s.add_token_state("p1", 1);
101 s.add_action(Action {
102 id: "t1".into(),
103 guard: String::new(),
104 event_id: String::new(),
105 event_bindings: None,
106 });
107 s.add_arc(Arc {
108 source: "missing".into(),
109 target: "t1".into(),
110 keys: vec![],
111 value: String::new(),
112 });
113 assert!(s.validate().is_err());
114 }
115
116 #[test]
117 fn test_state_to_state_arc() {
118 let mut s = Schema::new("test");
119 s.add_token_state("p1", 1);
120 s.add_token_state("p2", 0);
121 s.add_arc(Arc {
122 source: "p1".into(),
123 target: "p2".into(),
124 keys: vec![],
125 value: String::new(),
126 });
127 assert!(s.validate().is_err());
128 }
129}