1use crate::errors::ProjectionError;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
33pub struct NetRelation {
34 pub id: String,
36
37 pub from_netelement_id: String,
39
40 pub to_netelement_id: String,
42
43 pub position_on_a: u8,
45
46 pub position_on_b: u8,
48
49 pub navigable_forward: bool,
51
52 pub navigable_backward: bool,
54}
55
56impl NetRelation {
57 pub fn new(
59 id: String,
60 from_netelement_id: String,
61 to_netelement_id: String,
62 position_on_a: u8,
63 position_on_b: u8,
64 navigable_forward: bool,
65 navigable_backward: bool,
66 ) -> Result<Self, ProjectionError> {
67 let relation = Self {
68 id,
69 from_netelement_id,
70 to_netelement_id,
71 position_on_a,
72 position_on_b,
73 navigable_forward,
74 navigable_backward,
75 };
76
77 relation.validate()?;
78 Ok(relation)
79 }
80
81 pub fn validate(&self) -> Result<(), ProjectionError> {
83 if self.id.is_empty() {
85 return Err(ProjectionError::InvalidNetRelation(
86 "NetRelation ID must not be empty".to_string(),
87 ));
88 }
89
90 if self.from_netelement_id.is_empty() {
92 return Err(ProjectionError::InvalidNetRelation(
93 "from_netelement_id must not be empty".to_string(),
94 ));
95 }
96
97 if self.to_netelement_id.is_empty() {
98 return Err(ProjectionError::InvalidNetRelation(
99 "to_netelement_id must not be empty".to_string(),
100 ));
101 }
102
103 if self.position_on_a > 1 {
105 return Err(ProjectionError::InvalidNetRelation(format!(
106 "position_on_a must be 0 or 1, got {}",
107 self.position_on_a
108 )));
109 }
110
111 if self.position_on_b > 1 {
112 return Err(ProjectionError::InvalidNetRelation(format!(
113 "position_on_b must be 0 or 1, got {}",
114 self.position_on_b
115 )));
116 }
117
118 if self.from_netelement_id == self.to_netelement_id {
120 return Err(ProjectionError::InvalidNetRelation(format!(
121 "NetRelation cannot connect netelement to itself: {}",
122 self.from_netelement_id
123 )));
124 }
125
126 Ok(())
127 }
128
129 pub fn is_navigable_forward(&self) -> bool {
131 self.navigable_forward
132 }
133
134 pub fn is_navigable_backward(&self) -> bool {
136 self.navigable_backward
137 }
138
139 pub fn is_bidirectional(&self) -> bool {
141 self.navigable_forward && self.navigable_backward
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn test_valid_bidirectional() {
151 let relation = NetRelation::new(
152 "NR001".to_string(),
153 "NE_A".to_string(),
154 "NE_B".to_string(),
155 1,
156 0,
157 true,
158 true,
159 );
160
161 assert!(relation.is_ok());
162 let rel = relation.unwrap();
163 assert!(rel.is_bidirectional());
164 assert!(rel.is_navigable_forward());
165 assert!(rel.is_navigable_backward());
166 }
167
168 #[test]
169 fn test_valid_unidirectional() {
170 let relation = NetRelation::new(
171 "NR002".to_string(),
172 "NE_A".to_string(),
173 "NE_B".to_string(),
174 1,
175 0,
176 true,
177 false,
178 );
179
180 assert!(relation.is_ok());
181 let rel = relation.unwrap();
182 assert!(!rel.is_bidirectional());
183 assert!(rel.is_navigable_forward());
184 assert!(!rel.is_navigable_backward());
185 }
186
187 #[test]
188 fn test_invalid_position_on_a() {
189 let relation = NetRelation::new(
190 "NR003".to_string(),
191 "NE_A".to_string(),
192 "NE_B".to_string(),
193 2, 0,
195 true,
196 false,
197 );
198
199 assert!(relation.is_err());
200 }
201
202 #[test]
203 fn test_invalid_position_on_b() {
204 let relation = NetRelation::new(
205 "NR004".to_string(),
206 "NE_A".to_string(),
207 "NE_B".to_string(),
208 1,
209 5, true,
211 false,
212 );
213
214 assert!(relation.is_err());
215 }
216
217 #[test]
218 fn test_self_reference() {
219 let relation = NetRelation::new(
220 "NR005".to_string(),
221 "NE_A".to_string(),
222 "NE_A".to_string(), 1,
224 0,
225 true,
226 false,
227 );
228
229 assert!(relation.is_err());
230 }
231
232 #[test]
233 fn test_empty_id() {
234 let relation = NetRelation::new(
235 "".to_string(), "NE_A".to_string(),
237 "NE_B".to_string(),
238 1,
239 0,
240 true,
241 false,
242 );
243
244 assert!(relation.is_err());
245 }
246
247 #[test]
248 fn test_empty_from_id() {
249 let relation = NetRelation::new(
250 "NR006".to_string(),
251 "".to_string(), "NE_B".to_string(),
253 1,
254 0,
255 true,
256 false,
257 );
258
259 assert!(relation.is_err());
260 }
261
262 #[test]
263 fn test_empty_to_id() {
264 let relation = NetRelation::new(
265 "NR007".to_string(),
266 "NE_A".to_string(),
267 "".to_string(), 1,
269 0,
270 true,
271 false,
272 );
273
274 assert!(relation.is_err());
275 }
276}