use crate::errors::ProjectionError;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NetRelation {
pub id: String,
pub from_netelement_id: String,
pub to_netelement_id: String,
pub position_on_a: u8,
pub position_on_b: u8,
pub navigable_forward: bool,
pub navigable_backward: bool,
}
impl NetRelation {
pub fn new(
id: String,
from_netelement_id: String,
to_netelement_id: String,
position_on_a: u8,
position_on_b: u8,
navigable_forward: bool,
navigable_backward: bool,
) -> Result<Self, ProjectionError> {
let relation = Self {
id,
from_netelement_id,
to_netelement_id,
position_on_a,
position_on_b,
navigable_forward,
navigable_backward,
};
relation.validate()?;
Ok(relation)
}
pub fn validate(&self) -> Result<(), ProjectionError> {
if self.id.is_empty() {
return Err(ProjectionError::InvalidNetRelation(
"NetRelation ID must not be empty".to_string(),
));
}
if self.from_netelement_id.is_empty() {
return Err(ProjectionError::InvalidNetRelation(
"from_netelement_id must not be empty".to_string(),
));
}
if self.to_netelement_id.is_empty() {
return Err(ProjectionError::InvalidNetRelation(
"to_netelement_id must not be empty".to_string(),
));
}
if self.position_on_a > 1 {
return Err(ProjectionError::InvalidNetRelation(format!(
"position_on_a must be 0 or 1, got {}",
self.position_on_a
)));
}
if self.position_on_b > 1 {
return Err(ProjectionError::InvalidNetRelation(format!(
"position_on_b must be 0 or 1, got {}",
self.position_on_b
)));
}
if self.from_netelement_id == self.to_netelement_id {
return Err(ProjectionError::InvalidNetRelation(format!(
"NetRelation cannot connect netelement to itself: {}",
self.from_netelement_id
)));
}
Ok(())
}
pub fn is_navigable_forward(&self) -> bool {
self.navigable_forward
}
pub fn is_navigable_backward(&self) -> bool {
self.navigable_backward
}
pub fn is_bidirectional(&self) -> bool {
self.navigable_forward && self.navigable_backward
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_bidirectional() {
let relation = NetRelation::new(
"NR001".to_string(),
"NE_A".to_string(),
"NE_B".to_string(),
1,
0,
true,
true,
);
assert!(relation.is_ok());
let rel = relation.unwrap();
assert!(rel.is_bidirectional());
assert!(rel.is_navigable_forward());
assert!(rel.is_navigable_backward());
}
#[test]
fn test_valid_unidirectional() {
let relation = NetRelation::new(
"NR002".to_string(),
"NE_A".to_string(),
"NE_B".to_string(),
1,
0,
true,
false,
);
assert!(relation.is_ok());
let rel = relation.unwrap();
assert!(!rel.is_bidirectional());
assert!(rel.is_navigable_forward());
assert!(!rel.is_navigable_backward());
}
#[test]
fn test_invalid_position_on_a() {
let relation = NetRelation::new(
"NR003".to_string(),
"NE_A".to_string(),
"NE_B".to_string(),
2, 0,
true,
false,
);
assert!(relation.is_err());
}
#[test]
fn test_invalid_position_on_b() {
let relation = NetRelation::new(
"NR004".to_string(),
"NE_A".to_string(),
"NE_B".to_string(),
1,
5, true,
false,
);
assert!(relation.is_err());
}
#[test]
fn test_self_reference() {
let relation = NetRelation::new(
"NR005".to_string(),
"NE_A".to_string(),
"NE_A".to_string(), 1,
0,
true,
false,
);
assert!(relation.is_err());
}
#[test]
fn test_empty_id() {
let relation = NetRelation::new(
"".to_string(), "NE_A".to_string(),
"NE_B".to_string(),
1,
0,
true,
false,
);
assert!(relation.is_err());
}
#[test]
fn test_empty_from_id() {
let relation = NetRelation::new(
"NR006".to_string(),
"".to_string(), "NE_B".to_string(),
1,
0,
true,
false,
);
assert!(relation.is_err());
}
#[test]
fn test_empty_to_id() {
let relation = NetRelation::new(
"NR007".to_string(),
"NE_A".to_string(),
"".to_string(), 1,
0,
true,
false,
);
assert!(relation.is_err());
}
}