dot_graph 0.2.1

A library for generating Graphviz DOT language files.
Documentation

#[cfg(test)]
mod tests {
    use dot_graph::{Graph, Kind, Node, Edge, Style, Arrow, ArrowShape, Side, Subgraph};

    // All of the tests use raw-strings as the format for the expected outputs,
    // so that you can cut-and-paste the content into a .dot file yourself to
    // see what the graphviz visualizer would produce.

    #[test]
    fn empty_graph() {
        let graph = Graph::new("empty_graph", Kind::Digraph);
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph empty_graph {
}
"#);
    }

    #[test]
    fn single_node() {
        let mut graph = Graph::new("single_node", Kind::Digraph);
        let node = Node::new("N0");
        graph.add_node(node);
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph single_node {
    N0[label="N0"];
}
"#);
    }

    #[test]
    fn single_node_with_style() {
        let mut graph = Graph::new("single_node", Kind::Digraph);
        let node = Node::new("N0").style(Style::Dashed);
        graph.add_node(node);
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph single_node {
    N0[label="N0"][style="dashed"];
}
"#);
    }

    #[test]
    fn single_edge() {
        let mut graph = Graph::new("single_edge", Kind::Digraph);
        graph.add_node(Node::new("N0"));
        graph.add_node(Node::new("N1"));
        graph.add_edge(Edge::new("N0", "N1", "E"));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph single_edge {
    N0[label="N0"];
    N1[label="N1"];
    N0 -> N1[label="E"];
}
"#);
    }

    #[test]
    fn single_edge_with_style() {
        let mut graph = Graph::new("single_edge", Kind::Digraph);
        graph.add_node(Node::new("N0"));
        graph.add_node(Node::new("N1"));
        let e = Edge::new("N0", "N1", "E").style(Style::Bold).color(Some("red"));
        graph.add_edge(e);
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph single_edge {
    N0[label="N0"];
    N1[label="N1"];
    N0 -> N1[label="E"][style="bold"][color="red"];
}
"#);
    }

    #[test]
    fn test_some_labelled() {
        let mut graph = Graph::new("test_some_labelled", Kind::Digraph);
        graph.add_node(Node::new("N0").label("A"));
        graph.add_node(Node::new("N1").style(Style::Dotted));
        graph.add_edge(Edge::new("N0", "N1", "A-1"));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph test_some_labelled {
    N0[label="A"];
    N1[label="N1"][style="dotted"];
    N0 -> N1[label="A-1"];
}
"#);
    }

    #[test]
    fn single_cyclic_node() {
        let mut graph = Graph::new("single_cyclic_node", Kind::Digraph);
        graph.add_node(Node::new("N0"));
        graph.add_edge(Edge::new("N0", "N0", "E"));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph single_cyclic_node {
    N0[label="N0"];
    N0 -> N0[label="E"];
}
"#);
    }

    #[test]
    fn hasse_diagram() {
        let mut graph = Graph::new("hasse_diagram", Kind::Digraph);
        graph.add_node(Node::new("N0").label("{x,y}"));
        graph.add_node(Node::new("N1").label("{x}"));
        graph.add_node(Node::new("N2").label("{y}"));
        graph.add_node(Node::new("N3").label("{}"));
        graph.add_edge(Edge::new("N0", "N1", "").color(Some("green")));
        graph.add_edge(Edge::new("N0", "N2", "").color(Some("blue")));
        graph.add_edge(Edge::new("N1", "N3", "").color(Some("red")));
        graph.add_edge(Edge::new("N2", "N3", "").color(Some("black")));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph hasse_diagram {
    N0[label="{x,y}"];
    N1[label="{x}"];
    N2[label="{y}"];
    N3[label="{}"];
    N0 -> N1[label=""][color="green"];
    N0 -> N2[label=""][color="blue"];
    N1 -> N3[label=""][color="red"];
    N2 -> N3[label=""][color="black"];
}
"#);
    }

    #[test]
    fn left_aligned_text() {
        let mut graph = Graph::new("syntax_tree", Kind::Digraph);
        let node_label = 
r#"if test {
\l    branch1
\l} else {
\l    branch2
\l}
\lafterward
\l"#;
        graph.add_node(Node::new("N0").label(node_label));
        graph.add_node(Node::new("N1").label("branch1"));
        graph.add_node(Node::new("N2").label("branch2"));
        graph.add_node(Node::new("N3").label("afterward"));
        graph.add_edge(Edge::new("N0", "N1", "then"));
        graph.add_edge(Edge::new("N0", "N2", "else"));
        graph.add_edge(Edge::new("N1", "N3", ";"));
        graph.add_edge(Edge::new("N2", "N3", ";"));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph syntax_tree {
    N0[label="if test {
\l    branch1
\l} else {
\l    branch2
\l}
\lafterward
\l"];
    N1[label="branch1"];
    N2[label="branch2"];
    N3[label="afterward"];
    N0 -> N1[label="then"];
    N0 -> N2[label="else"];
    N1 -> N3[label=";"];
    N2 -> N3[label=";"];
}
"#);
    }

    #[test]
    fn test_some_arrow() {
        let mut graph = Graph::new("test_some_labelled", Kind::Digraph);
        graph.add_node(Node::new("N0").label("A"));
        graph.add_node(Node::new("N1").style(Style::Dotted));
        graph.add_edge(Edge::new("N0", "N1", "A-1").end_arrow(Arrow::from_arrow(ArrowShape::crow())));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph test_some_labelled {
    N0[label="A"];
    N1[label="N1"][style="dotted"];
    N0 -> N1[label="A-1"][arrowhead="crow"];
}
"#);
    }

    #[test]
    fn test_some_arrows() {
        let mut graph = Graph::new("test_some_labelled", Kind::Digraph);
        graph.add_node(Node::new("N0").label("A"));
        graph.add_node(Node::new("N1").style(Style::Dotted));
        graph.add_edge(Edge::new("N0", "N1", "A-1").end_arrow(Arrow::from_arrow(ArrowShape::Crow(Side::Left))).start_arrow(Arrow::from_arrow(ArrowShape::tee())));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph test_some_labelled {
    N0[label="A"];
    N1[label="N1"][style="dotted"];
    N0 -> N1[label="A-1"][arrowhead="lcrow" arrowtail="tee" dir="both"];
}
"#);
    }

    #[test]
    fn invisible() {
        let mut graph = Graph::new("single_cyclic_node", Kind::Digraph);
        graph.add_node(Node::new("N0").style(Style::Invisible));
        graph.add_edge(Edge::new("N0", "N0", "E").style(Style::Invisible));
        assert_eq!(graph.to_dot_string().unwrap(),
                   r#"digraph single_cyclic_node {
    N0[label="N0"][style="invis"];
    N0 -> N0[label="E"][style="invis"];
}
"#);
    }

    #[test]
    fn default_style_graph() {
        let mut graph = Graph::new("g", Kind::Graph);
        graph.add_node(Node::new("N0"));
        graph.add_node(Node::new("N1"));
        graph.add_node(Node::new("N2"));
        graph.add_node(Node::new("N3"));
        graph.add_edge(Edge::new("N0", "N1", ""));
        graph.add_edge(Edge::new("N0", "N2", ""));
        graph.add_edge(Edge::new("N1", "N3", ""));
        graph.add_edge(Edge::new("N2", "N3", ""));
        assert_eq!(graph.to_dot_string().unwrap(),
r#"graph g {
    N0[label="N0"];
    N1[label="N1"];
    N2[label="N2"];
    N3[label="N3"];
    N0 -- N1[label=""];
    N0 -- N2[label=""];
    N1 -- N3[label=""];
    N2 -- N3[label=""];
}
"#);
    }

    #[test]
    fn test_subgraph() {
        let mut graph = Graph::new("di", Kind::Digraph);
        let mut c1 = Subgraph::new("cluster_0").label("");
        c1.add_node(Node::new("N0"));
        c1.add_node(Node::new("N1"));
        let mut c2 = Subgraph::new("cluster_1").label("");
        c2.add_node(Node::new("N2"));
        c2.add_node(Node::new("N3"));
        graph.add_subgraph(c1);
        graph.add_subgraph(c2);
        graph.add_edge(Edge::new("N0", "N1", ""));
        graph.add_edge(Edge::new("N0", "N2", ""));
        graph.add_edge(Edge::new("N1", "N3", ""));
        graph.add_edge(Edge::new("N2", "N3", ""));
        

        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph di {
    subgraph cluster_0 {
        label="";
        N0[label="N0"];
        N1[label="N1"];
    }
    subgraph cluster_1 {
        label="";
        N2[label="N2"];
        N3[label="N3"];
    }
    N0 -> N1[label=""];
    N0 -> N2[label=""];
    N1 -> N3[label=""];
    N2 -> N3[label=""];
}
"#);
    }

    #[test]
    fn test_subgraph_with_format() {
        let mut graph = Graph::new("G", Kind::Digraph);
        let mut c0 = Subgraph::new("cluster_0").label("process #1").style(Style::Filled).color(Some("lightgrey"));
        c0.add_node(Node::new("a0").style(Style::Filled).color(Some("white")));
        c0.add_node(Node::new("a1").style(Style::Filled).color(Some("white")));
        c0.add_node(Node::new("a2").style(Style::Filled).color(Some("white")));
        c0.add_node(Node::new("a3").style(Style::Filled).color(Some("white")));
        let mut c1 = Subgraph::new("cluster_1")
                                        .label("process #2")
                                        .color(Some("blue"));
        c1.add_node(Node::new("b0").style(Style::Filled));
        c1.add_node(Node::new("b1").style(Style::Filled));
        c1.add_node(Node::new("b2").style(Style::Filled));
        c1.add_node(Node::new("b3").style(Style::Filled));
        graph.add_subgraph(c0);
        graph.add_subgraph(c1);
        graph.add_node(Node::new("start").shape(Some("Mdiamond")));
        graph.add_node(Node::new("end").shape(Some("Msquare")));
        graph.add_edge(Edge::new("start", "a0", ""));
        graph.add_edge(Edge::new("a0", "a1", ""));
        graph.add_edge(Edge::new("a1", "a2", ""));
        graph.add_edge(Edge::new("a2", "a3", ""));
        graph.add_edge(Edge::new("start", "b0", ""));
        graph.add_edge(Edge::new("b0", "b1", ""));
        graph.add_edge(Edge::new("b1", "b2", ""));
        graph.add_edge(Edge::new("b2", "b3", ""));
        graph.add_edge(Edge::new("a1", "b3", ""));
        graph.add_edge(Edge::new("b2", "a3", ""));
        graph.add_edge(Edge::new("a3", "a0", ""));
        graph.add_edge(Edge::new("a3", "end", ""));
        graph.add_edge(Edge::new("b3", "end", ""));

        assert_eq!(graph.to_dot_string().unwrap(),
r#"digraph G {
    subgraph cluster_0 {
        label="process #1";
        style="filled";
        color="lightgrey";
        a0[label="a0"][style="filled"][color="white"];
        a1[label="a1"][style="filled"][color="white"];
        a2[label="a2"][style="filled"][color="white"];
        a3[label="a3"][style="filled"][color="white"];
    }
    subgraph cluster_1 {
        label="process #2";
        color="blue";
        b0[label="b0"][style="filled"];
        b1[label="b1"][style="filled"];
        b2[label="b2"][style="filled"];
        b3[label="b3"][style="filled"];
    }
    start[label="start"][shape="Mdiamond"];
    end[label="end"][shape="Msquare"];
    start -> a0[label=""];
    a0 -> a1[label=""];
    a1 -> a2[label=""];
    a2 -> a3[label=""];
    start -> b0[label=""];
    b0 -> b1[label=""];
    b1 -> b2[label=""];
    b2 -> b3[label=""];
    a1 -> b3[label=""];
    b2 -> a3[label=""];
    a3 -> a0[label=""];
    a3 -> end[label=""];
    b3 -> end[label=""];
}
"#);
    }

    #[test]
    #[should_panic]
    fn badly_formatted_id() {
        let mut graph = Graph::new("g", Kind::Graph);
        graph.add_node(Node::new("Weird { struct : ure } !!!"));
        let result = graph.to_dot_string();
        result.unwrap();
    }
}