use wolf_graph::prelude::*;
use fuid::{Fuid, fuid};
use indoc::indoc;
use wolf_graph_dot::prelude::*;
#[test]
fn test_dot_graph() {
let graph = make_graph();
let dot = graph.dot_format();
assert_eq!(&dot, indoc! {r#"
digraph G {
A [label="A"]
B [label="B"]
C [label="C"]
D [label="D"]
E [label="E"]
F [label="F"]
G [label="G"]
H [label="H"]
I [label="I"]
J [label="J"]
K [label="K"]
A -> C [label="AC"]
A -> D [label="AD"]
A -> E [label="AE"]
B -> A [label="BA"]
B -> C [label="BC"]
B -> G [label="BG"]
C -> D [label="CD"]
E -> D [label="ED"]
F -> D [label="FD"]
F -> E [label="FE"]
G -> I [label="GI"]
H -> J [label="HJ"]
I -> B [label="IB"]
I -> C [label="IC"]
I -> K [label="IK"]
J -> A [label="JA"]
J -> E [label="JE"]
J -> F [label="JF"]
}
"#}.trim());
}
#[test]
fn test_dot_dag() {
let graph = make_dag();
let dot = graph.dot_format();
assert_eq!(&dot, indoc! {r#"
digraph G {
A [label="A"]
B [label="B"]
C [label="C"]
D [label="D"]
E [label="E"]
F [label="F"]
G [label="G"]
H [label="H"]
I [label="I"]
J [label="J"]
K [label="K"]
A -> C [label="AC"]
A -> D [label="AD"]
A -> E [label="AE"]
B -> A [label="BA"]
B -> C [label="BC"]
B -> G [label="BG"]
C -> D [label="CD"]
E -> D [label="ED"]
F -> D [label="FD"]
F -> E [label="FE"]
I -> G [label="GI"]
H -> J [label="HJ"]
B -> I [label="IB"]
I -> C [label="IC"]
I -> K [label="IK"]
J -> A [label="JA"]
J -> E [label="JE"]
J -> F [label="JF"]
}
"#}.trim());
}
#[test]
fn test_dot_tree() {
let graph = make_tree();
let dot = graph.dot_format();
assert_eq!(&dot, indoc! {r#"
digraph G {
A [label="A"]
B [label="B"]
C [label="C"]
D [label="D"]
E [label="E"]
F [label="F"]
G [label="G"]
H [label="H"]
I [label="I"]
J [label="J"]
K [label="K"]
L [label="L"]
M [label="M"]
N [label="N"]
O [label="O"]
A -> B [label="AB"]
A -> C [label="AC"]
A -> D [label="AD"]
B -> I [label="BI"]
C -> H [label="CH"]
D -> E [label="DE"]
D -> F [label="DF"]
D -> G [label="DG"]
E -> M [label="EM"]
E -> N [label="EN"]
E -> O [label="EO"]
F -> L [label="FL"]
H -> J [label="HJ"]
H -> K [label="HK"]
}
"#}.trim());
}
#[test]
fn test_dot_attributes() {
let mut graph = make_dag();
graph.set_data(TestGraphData::new(fuid!("E0QxdoG9E5W2BeYPPFbah")));
graph.add_node(nid!("Z")).unwrap();
graph.add_edge(eid!("AZ"), nid!("A"), nid!("Z")).unwrap();
graph.with_edge_data(eid!("AZ"), &|data| data.label = "AZ".to_string()).unwrap();
graph.with_node_data(nid!("Z"), &|data| {
data.label = "Zebra".to_string();
data.is_pentagon = true;
}).unwrap();
graph.with_node_data(nid!("A"), &|data| data.is_red = true).unwrap();
graph.with_node_data(nid!("J"), &|data| data.is_filled = true).unwrap();
graph.with_edge_data(eid!("AZ"), &|data| {
data.label = "Green".to_string();
data.is_green = true;
}).unwrap();
graph.with_edge_data(eid!("JA"), &|data| data.is_bold = true).unwrap();
graph.with_edge_data(eid!("AC"), &|data| data.is_bidirectional = true).unwrap();
graph.with_edge_data(eid!("BA"), &|data| data.is_bold = true).unwrap();
graph.with_edge_data(eid!("IK"), &|data| data.is_special_arrowhead = true).unwrap();
graph.with_edge_data(eid!("IC"), &|data| {
data.is_bidirectional = true;
data.is_special_arrowtail = true;
}).unwrap();
let dot = graph.dot_format();
assert_eq!(&dot, indoc! {r#"
digraph E0QxdoG9E5W2BeYPPFbah {
A [label="A" color="red"]
B [label="B"]
C [label="C"]
D [label="D"]
E [label="E"]
F [label="F"]
G [label="G"]
H [label="H"]
I [label="I"]
J [label="J" style="filled"]
K [label="K"]
Z [label="Zebra" shape="pentagon"]
A -> C [label="AC" dir="both"]
A -> D [label="AD"]
A -> E [label="AE"]
A -> Z [label="Green" color="green"]
B -> A [label="BA" style="bold"]
B -> C [label="BC"]
B -> G [label="BG"]
C -> D [label="CD"]
E -> D [label="ED"]
F -> D [label="FD"]
F -> E [label="FE"]
I -> G [label="GI"]
H -> J [label="HJ"]
B -> I [label="IB"]
I -> C [label="IC" dir="both" arrowtail="invodot"]
I -> K [label="IK" arrowhead="box"]
J -> A [label="JA" style="bold"]
J -> E [label="JE"]
J -> F [label="JF"]
}
"#}.trim());
}
#[derive(Clone)]
struct TestGraphData {
id: Fuid,
}
impl Default for TestGraphData {
fn default() -> Self {
Self { id: fuid!("G") }
}
}
impl TestGraphData {
fn new(id: Fuid) -> Self {
Self { id }
}
}
#[derive(Clone)]
struct TestNodeData {
label: String,
is_red: bool,
is_filled: bool,
is_pentagon: bool,
}
impl Default for TestNodeData {
fn default() -> Self {
Self {
label: "".to_string(),
is_red: false,
is_filled: false,
is_pentagon: false,
}
}
}
impl TestNodeData {
fn new(label: &str, is_red: bool, is_filled: bool, is_pentagon: bool) -> Self {
Self {
label: label.to_string(),
is_red,
is_filled,
is_pentagon,
}
}
}
#[derive(Clone)]
struct TestEdgeData {
label: String,
is_green: bool,
is_bold: bool,
is_bidirectional: bool,
is_special_arrowhead: bool,
is_special_arrowtail: bool,
}
impl Default for TestEdgeData {
fn default() -> Self {
Self {
label: "".to_string(),
is_green: false,
is_bold: false,
is_bidirectional: false,
is_special_arrowhead: false,
is_special_arrowtail: false,
}
}
}
impl TestEdgeData {
fn new(
label: &str,
is_green: bool,
is_bold: bool,
is_bidirectional: bool,
is_special_arrowhead: bool,
is_special_arrowtail: bool,
) -> Self {
Self {
label: label.to_string(),
is_green,
is_bold,
is_bidirectional,
is_special_arrowhead,
is_special_arrowtail,
}
}
}
fn make_test_graph(edges: &[(EdgeID, NodeID, NodeID)]) -> TestGraph {
let mut graph = TestGraph::new();
for edge in edges {
let (edge, source, target) = edge;
if !graph.has_node(source) {
graph.add_node_with_data(source, TestNodeData::new(&source.to_string(), false, false, false)).unwrap();
}
if !graph.has_node(target) {
graph.add_node_with_data(target, TestNodeData::new(&target.to_string(), false, false, false)).unwrap();
}
graph.add_edge_with_data(edge, source, target, TestEdgeData::new(&edge.to_string(), false, false, false, false, false)).unwrap();
}
graph
}
fn make_graph() -> TestGraph {
make_test_graph(&graph_edges())
}
fn make_dag() -> TestGraph {
make_test_graph(&dag_edges())
}
fn make_tree() -> TestGraph {
make_test_graph(&tree_edges())
}
type TestGraph = Graph<TestGraphData, TestNodeData, TestEdgeData>;
impl DotEncodable<TestGraphData, TestNodeData, TestEdgeData> for TestGraph
{
fn dot_graph_attributes(&self) -> Option<GraphAttributes> {
Some(GraphAttributes::new(Some(self.data().id.to_string())))
}
fn dot_node_attributes(&self, node: &NodeID) -> Option<NodeAttributes> {
let data = self.node_data(node).unwrap();
let color = if data.is_red { Some(Color::RED) } else { None };
let style = if data.is_filled { Some(NodeStyle::Filled) } else { None };
let shape = if data.is_pentagon { Some(NodeShape::Pentagon) } else { None };
Some(NodeAttributes::new(Some(data.label.clone()), color, style, shape))
}
fn dot_edge_attributes(&self, edge: &EdgeID) -> Option<EdgeAttributes> {
let data = self.edge_data(edge).unwrap();
let color = if data.is_green { Some(Color::GREEN) } else { None };
let style = if data.is_bold { Some(EdgeStyle::Bold) } else { None };
let arrow_direction = if data.is_bidirectional { Some(ArrowDirection::Both) } else { None };
let arrow_head = if data.is_special_arrowhead { Some(ArrowType::BOX) } else { None };
let arrow_tail = if data.is_special_arrowtail { Some(ArrowType::INVODOT) } else { None };
Some(EdgeAttributes::new(
Some(data.label.clone()),
color,
style,
None,
arrow_direction,
arrow_head,
arrow_tail,
))
}
}
pub fn graph_edges() -> Vec<(EdgeID, NodeID, NodeID)> {
let v = vec![
("AC", "A", "C"),
("AD", "A", "D"),
("AE", "A", "E"),
("BA", "B", "A"),
("BC", "B", "C"),
("BG", "B", "G"),
("CD", "C", "D"),
("ED", "E", "D"),
("FD", "F", "D"),
("FE", "F", "E"),
("HJ", "H", "J"),
("IC", "I", "C"),
("IK", "I", "K"),
("JA", "J", "A"),
("JE", "J", "E"),
("JF", "J", "F"),
("GI", "G", "I"), ("IB", "I", "B"), ];
v.into_iter().map(|(a, b, c)| (eid!(a), nid!(b), nid!(c))).collect()
}
pub fn dag_edges() -> Vec<(EdgeID, NodeID, NodeID)> {
let v = vec![
("AC", "A", "C"),
("AD", "A", "D"),
("AE", "A", "E"),
("BA", "B", "A"),
("BC", "B", "C"),
("BG", "B", "G"),
("CD", "C", "D"),
("ED", "E", "D"),
("FD", "F", "D"),
("FE", "F", "E"),
("HJ", "H", "J"),
("IC", "I", "C"),
("IK", "I", "K"),
("JA", "J", "A"),
("JE", "J", "E"),
("JF", "J", "F"),
("GI", "I", "G"),
("IB", "B", "I"),
];
v.into_iter().map(|(a, b, c)| (eid!(a), nid!(b), nid!(c))).collect()
}
pub fn tree_edges() -> Vec<(EdgeID, NodeID, NodeID)> {
let v = vec![
("AB", "A", "B"),
("AC", "A", "C"),
("AD", "A", "D"),
("DE", "D", "E"),
("DF", "D", "F"),
("DG", "D", "G"),
("CH", "C", "H"),
("BI", "B", "I"),
("HJ", "H", "J"),
("HK", "H", "K"),
("FL", "F", "L"),
("EM", "E", "M"),
("EN", "E", "N"),
("EO", "E", "O"),
];
v.into_iter().map(|(a, b, c)| (eid!(a), nid!(b), nid!(c))).collect()
}