use crate::Sodg;
use rstest::rstest;
use std::collections::HashMap;
impl Sodg {
pub fn empty() -> Self {
let mut g = Sodg {
vertices: HashMap::new(),
next_v: 0,
alerts: vec![],
alerts_active: true,
};
g.alert_on(|g, vx| {
let mut errors = Vec::new();
for v in vx.iter() {
for e in g.vertices.get(v).unwrap().edges.iter() {
if !g.vertices.contains_key(&e.to) {
errors.push(format!("Edge ν{}.{} arrives to lost ν{}", v, e.a, e.to));
}
}
}
errors
});
g.alert_on(|g, vx| {
let mut errors = Vec::new();
for v in vx.iter() {
for e in g.vertices.get(v).unwrap().edges.iter() {
if e.to == *v {
errors.push(format!("Edge ν{}.{} arrives to ν{} (loop)", v, e.a, e.to));
}
}
}
errors
});
g.alert_on(|g, vx| {
let mut errors = Vec::new();
for v in vx.iter() {
for e in g.vertices.get(v).unwrap().edges.iter() {
if e.a.is_empty() {
errors.push(format!("Edge from ν{} to ν{} has empty label", v, e.to));
}
}
}
errors
});
g.alert_on(|g, vx| {
let mut errors = Vec::new();
for v in vx.iter() {
for e in g.vertices.get(v).unwrap().edges.iter() {
if !g.vertices.contains_key(&e.to) {
errors.push(format!(
"Edge ν{}.{} points to ν{}, which doesn't exist",
v, e.a, e.to
));
}
}
}
errors
});
g.alert_on(|g, vx| {
let mut errors = Vec::new();
for v in vx.iter() {
for e in g.vertices.get(v).unwrap().edges.iter() {
if e.a.is_empty() {
errors.push(format!(
"Edge label from ν{} to ν{} is an empty string",
v, e.to
));
}
if e.a.contains(' ') {
errors.push(format!(
"Edge label from ν{} to ν{} has prohibited spaces",
v, e.to
));
}
if e.a.split('/').count() > 2 {
errors.push(format!(
"Edge label from ν{} to ν{} has more than one slash",
v, e.to
));
}
}
}
errors
});
g
}
}
#[cfg(test)]
use anyhow::Result;
#[test]
fn makes_an_empty_sodg() -> Result<()> {
let mut g = Sodg::empty();
g.add(0)?;
assert_eq!(1, g.vertices.len());
Ok(())
}
#[test]
fn prohibits_loops() -> Result<()> {
let mut g = Sodg::empty();
g.alerts_off();
g.add(0)?;
g.bind(0, 0, "foo")?;
assert!(g.alerts_on().is_err());
Ok(())
}
#[test]
fn prohibits_empty_labels() -> Result<()> {
let mut g = Sodg::empty();
g.alerts_off();
g.add(0)?;
g.add(1)?;
g.bind(0, 1, "")?;
assert!(g.alerts_on().is_err());
Ok(())
}
#[test]
fn prohibits_orphan_edges() -> Result<()> {
let mut g = Sodg::empty();
g.alerts_off();
g.add(0)?;
assert!(g.bind(0, 1, "foo").is_err());
Ok(())
}
#[rstest]
#[case("")]
#[case("with spaces")]
#[case("with/two/slashes")]
fn prohibits_labels_of_broken_format(#[case] a: &str) {
let mut g = Sodg::empty();
g.alerts_off();
g.add(0).unwrap();
g.add(1).unwrap();
g.bind(0, 1, a).unwrap();
assert!(g.alerts_on().is_err());
}