Files
grapherity/src/testing/graph_topology_testing.rs
T

774 lines
22 KiB
Rust

use std::fmt::Debug;
use crate::testing::fixtures::MakeTestGraph;
use crate::traits::{Incidence, IncidenceCursor};
#[doc(hidden)]
#[macro_export]
macro_rules! graph_topology_tests {
($T:ty) => {
$crate::graph_topology_tests!(@wrap $T,
vertex_count_empty,
vertex_count,
vertex_map,
edge_count_empty,
edge_count,
edge_map,
degree_zero,
degree,
loop_edge,
multiple_edges,
are_adjacent_vertex_self,
are_adjacent_single_edge,
are_adjacent,
vertices_empty,
vertices,
adjacent_vertices_empty,
adjacent_vertices,
adjacent_vertices_loop_edge,
adjacent_vertices_multiple_edges,
incident_vertices_single_edge,
incident_vertices_loop_edge,
incident_vertices_multiple_edges,
incident_vertices,
edges_empty,
edges,
incident_edges_empty,
incident_edges,
incident_edges_loop_edge,
incident_edges_multiple_edges,
incidences_empty,
incidences,
incidences_edge_consistency,
incidences_loop_edge,
incidences_multiple_edges,
incidence_cursor_empty,
incidence_cursor,
incidence_cursor_loop_edge,
incidence_cursor_multiple_edges,
incidence_cursor_copy,
incident_vertices_incidences_consistency,
incident_edges_incidences_consistency,
);
};
(@wrap $T:ty, $($name:ident),* $(,)?) => {
$(
#[test]
fn $name() {
$crate::testing::graph_topology_testing::$name::<$T>();
}
)*
};
}
pub fn vertex_count_empty<G: MakeTestGraph>() {
let graph = G::empty();
assert_eq!(graph.vertex_count(), 0, "unexpected vertex count");
}
pub fn vertex_count<G: MakeTestGraph>() {
let (graph, _, _, _) = G::standard();
assert_eq!(graph.vertex_count(), 10, "unexpected vertex count");
}
pub fn vertex_map<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, vertices, _, _) = G::standard();
let mut map = graph.vertex_map(88);
for (i, &v) in vertices.iter().enumerate() {
assert_eq!(
map[v], 88,
"unexpected value from default map read for vertex {v:?}"
);
map[v] = i;
}
for (i, &v) in vertices.iter().enumerate() {
assert_eq!(map[v], i, "unexpected value after write for vertex {v:?}");
}
}
pub fn edge_count_empty<G: MakeTestGraph>() {
let graph = G::empty();
assert_eq!(graph.edge_count(), 0, "unexpected edge count");
}
pub fn edge_count<G: MakeTestGraph>() {
let (graph, _, _, _) = G::standard();
assert_eq!(graph.edge_count(), 18, "unexpected edge count");
}
pub fn edge_map<G: MakeTestGraph>()
where
G::Edge: Debug,
{
let (graph, _, edges, _) = G::standard();
let mut map = graph.edge_map(99);
for (i, &(e, _, _)) in edges.iter().enumerate() {
assert_eq!(
map[e], 99,
"unexpected value from default map read for edge {e:?}"
);
map[e] = i;
}
for (i, &(e, _, _)) in edges.iter().enumerate() {
assert_eq!(map[e], i, "unexpected value after write for edge {e:?}");
}
}
pub fn degree_zero<G: MakeTestGraph>() {
let (graph, v) = G::single_vertex();
assert_eq!(graph.degree(v), 0, "unexpected non-zero degree");
}
pub fn degree<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, vertices, _, _) = G::standard();
let expected = [2, 5, 7, 2, 7, 2, 3, 3, 2, 3];
assert_eq!(vertices.len(), expected.len());
for (&v, &exp) in vertices.iter().zip(&expected) {
assert_eq!(graph.degree(v), exp, "unexpected degree of {v:?}");
}
}
pub fn loop_edge<G: MakeTestGraph>() {
let (graph, v, _) = G::loop_edge();
assert_eq!(graph.vertex_count(), 1, "unexpected vertex count");
assert_eq!(graph.edge_count(), 1, "unexpected edge count");
assert_eq!(graph.degree(v), 2, "unexpected degree");
assert!(
graph.are_adjacent(v, v),
"vertex with loop edge should be adjacent to itself"
);
}
pub fn multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
const K: usize = 3;
let (graph, [v0, v1], _) = G::multiple_edges::<K>();
assert_eq!(graph.vertex_count(), 2, "unexpected vertex count");
assert_eq!(graph.edge_count(), K, "unexpected edge count");
assert_eq!(graph.degree(v0), K, "unexpected degree of vertex {v0:?}");
assert_eq!(graph.degree(v1), K, "unexpected degree of vertex {v1:?}",);
assert!(graph.are_adjacent(v0, v1), "should be adjacent");
}
pub fn are_adjacent_vertex_self<G: MakeTestGraph>() {
let (graph, v) = G::single_vertex();
assert!(
!graph.are_adjacent(v, v),
"should not be adjacent to itself"
);
}
pub fn are_adjacent_single_edge<G: MakeTestGraph>() {
let (graph, [v0, v1], _) = G::single_edge();
assert!(graph.are_adjacent(v0, v1), "should be adjacent");
assert!(graph.are_adjacent(v1, v0), "should be adjacent");
}
pub fn are_adjacent<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, vertices, _, _) = G::standard();
assert!(
graph.are_adjacent(vertices[0], vertices[1]),
"expected {:?} and {:?} to be adjacent",
vertices[0],
vertices[1]
);
assert!(
graph.are_adjacent(vertices[9], vertices[5]),
"expected {:?} and {:?} to be adjacent",
vertices[9],
vertices[5]
);
assert!(
!graph.are_adjacent(vertices[9], vertices[3]),
"unexpected adjacency of {:?} and {:?}",
vertices[9],
vertices[3]
);
for (i, &v) in vertices.iter().enumerate() {
let exp = matches!(i, 1 | 2 | 4 | 5 | 6);
assert_eq!(
graph.are_adjacent(vertices[2], v),
exp,
"unexpected adjacency of {:?} and {v:?}",
vertices[2]
);
assert_eq!(
graph.are_adjacent(v, vertices[2]),
exp,
"unexpected adjacency of {v:?} and {:?}",
vertices[2]
);
}
}
pub fn vertices_empty<G: MakeTestGraph>() {
let graph = G::empty();
assert_eq!(
graph.vertices().count(),
0,
"vertex iterator of empty graph should have no elements"
);
}
pub fn vertices<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, vertices, _, _) = G::standard();
assert_eq!(graph.vertices().count(), 10, "unexpected vertex count");
for v in graph.vertices() {
assert_eq!(
vertices.iter().filter(|&x| *x == v).count(),
1,
"unexpected vertex {v:?} from iterator"
);
}
}
pub fn adjacent_vertices_empty<G: MakeTestGraph>() {
let (graph, v) = G::single_vertex();
assert_eq!(
graph.adjacent_vertices(v).count(),
0,
"adjacent vertex iterator of vertex with degree 0 should have no elements"
);
}
pub fn adjacent_vertices<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, vertices, _, _) = G::standard();
assert_eq!(
graph.adjacent_vertices(vertices[4]).count(),
7,
"unexpected adjacency count"
);
let mut expected_adjacency = vec![
vertices[1],
vertices[2],
vertices[2],
vertices[4],
vertices[4],
vertices[7],
vertices[8],
];
for v in graph.adjacent_vertices(vertices[4]) {
let i = expected_adjacency
.iter()
.position(|w| *w == v)
.unwrap_or_else(|| {
panic!(
"unexpected adjacent vertex {v:?} of {:?} from iterator",
vertices[4]
)
});
expected_adjacency.swap_remove(i);
}
assert_eq!(
expected_adjacency.len(),
0,
"expected adjacent vertices {expected_adjacency:?} of {:?} were not matched by iterator",
vertices[4]
);
}
pub fn adjacent_vertices_loop_edge<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
let (graph, v, _) = G::loop_edge();
let mut iter = graph.adjacent_vertices(v);
assert_eq!(iter.next(), Some(v), "vertex should be adjacent to itself");
assert_eq!(
iter.next(),
Some(v),
"vertex should be adjacent to itself twice"
);
assert_eq!(
iter.next(),
None,
"too many adjacent vertices from iterator"
);
}
pub fn adjacent_vertices_multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
{
const K: usize = 3;
let (graph, vertices, _) = G::multiple_edges::<K>();
for (i, &v) in vertices.iter().enumerate() {
let mut iter = graph.adjacent_vertices(v);
for j in 0..K {
assert_eq!(
iter.next(),
Some(vertices[1 - i]),
"unexpected adjacent vertex {j} of vertex {v:?}"
);
}
assert_eq!(
iter.next(),
None,
"too many adjacent vertices of vertex {v:?} from iterator"
);
}
}
pub fn incident_vertices_single_edge<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, [v0, v1], e) = G::single_edge();
let (u0, u1) = graph.incident_vertices(e);
assert!(
(u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0),
"unexpected incident vertices {u0:?} and {u1:?} for edge {e:?}"
);
}
pub fn incident_vertices_loop_edge<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, v, e) = G::loop_edge();
assert_eq!(
graph.incident_vertices(e),
(v, v),
"unexpected incident vertices for loop edge {e:?}"
);
}
pub fn incident_vertices_multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, [v0, v1], edges) = G::multiple_edges::<2>();
assert_ne!(edges[0], edges[1], "edges should be distinct");
for (i, &e) in edges.iter().enumerate() {
let (u0, u1) = graph.incident_vertices(e);
assert!(
(u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0),
"unexpected incident vertices {u0:?} and {u1:?} for multi-edge {e:?} (index {i})"
);
}
}
pub fn incident_vertices<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, _, edges, _) = G::standard();
for &(e, v0, v1) in edges.iter() {
let (u0, u1) = graph.incident_vertices(e);
assert!(
(u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0),
"unexpected incident vertices {u0:?} and {u1:?} for edge {e:?}"
);
}
}
pub fn edges_empty<G: MakeTestGraph>() {
let graph = G::empty();
assert_eq!(
graph.edges().count(),
0,
"edge iterator of empty graph should have no elements"
);
}
pub fn edges<G: MakeTestGraph>()
where
G::Edge: Debug,
{
let (graph, _, edges, _) = G::standard();
assert_eq!(graph.edges().count(), 18, "unexpected edge count");
for e in graph.edges() {
assert_eq!(
edges.iter().filter(|&&(f, _, _)| f == e).count(),
1,
"unexpected edge {e:?} from iterator"
);
}
}
pub fn incident_edges_empty<G: MakeTestGraph>() {
let (graph, v) = G::single_vertex();
assert_eq!(
graph.incident_edges(v).count(),
0,
"incident edge iterator of vertex with degree 0 should have no elements"
);
}
pub fn incident_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, vertices, _, incidences) = G::standard();
assert_eq!(vertices.len(), incidences.len());
for (&v, incs) in vertices.iter().zip(&incidences) {
assert_eq!(
graph.incident_edges(v).count(),
incs.len(),
"unexpected incident edge count for vertex {v:?}"
);
let mut expected: Vec<_> = incs.iter().map(|x| x.edge).collect();
for e in graph.incident_edges(v) {
let pos = expected.iter().position(|&f| f == e).unwrap_or_else(|| {
panic!("unexpected incident edge {e:?} of vertex {v:?} from iterator")
});
expected.swap_remove(pos);
}
assert!(
expected.is_empty(),
"expected incident edges {expected:?} of vertex {v:?} were not matched by iterator"
);
}
}
pub fn incident_edges_loop_edge<G: MakeTestGraph>()
where
G::Edge: Debug,
{
let (graph, v, e) = G::loop_edge();
let mut iter = graph.incident_edges(v);
assert_eq!(
iter.next(),
Some(e),
"loop edge should appear in incident edges"
);
assert_eq!(
iter.next(),
Some(e),
"loop edge should appear twice in incident edges"
);
assert_eq!(iter.next(), None, "too many incident edges from iterator");
}
pub fn incident_edges_multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
const K: usize = 3;
let (graph, vertices, edges) = G::multiple_edges::<K>();
for &v in &vertices {
let mut expected = edges.to_vec();
for e in graph.incident_edges(v) {
let pos = expected
.iter()
.position(|&f| f == e)
.unwrap_or_else(|| panic!("unexpected incident edge {e:?} of vertex {v:?}"));
expected.swap_remove(pos);
}
assert!(
expected.is_empty(),
"expected incident edges {expected:?} of vertex {v:?} were not matched by iterator"
);
}
}
pub fn incidences_empty<G: MakeTestGraph>() {
let (graph, v) = G::single_vertex();
assert_eq!(
graph.incidences(v).count(),
0,
"incidence iterator of vertex with degree 0 should have no elements"
);
}
pub fn incidences<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, vertices, _, incidences) = G::standard();
assert_eq!(vertices.len(), incidences.len());
for (&v, incs) in vertices.iter().zip(&incidences) {
assert_eq!(
graph.incidences(v).count(),
incs.len(),
"unexpected incidence count for vertex {v:?}"
);
let mut expected = incs.clone();
for incidence in graph.incidences(v) {
let pos = expected
.iter()
.position(|&x| x == incidence)
.unwrap_or_else(|| {
panic!("unexpected incidence {incidence:?} of vertex {v:?} from iterator")
});
expected.swap_remove(pos);
}
assert!(
expected.is_empty(),
"expected incidences {expected:?} of vertex {v:?} were not matched by iterator"
);
}
}
pub fn incidences_edge_consistency<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, _, _, _) = G::standard();
for u in graph.vertices() {
for incidence in graph.incidences(u) {
if u == incidence.vertex {
assert_eq!(
graph
.incidences(u)
.filter(|x| x.edge == incidence.edge)
.count(),
2,
"loop edge {:?} should appear exactly twice in incidences of vertex {u:?}",
incidence.edge
);
} else {
assert!(
graph
.incidences(incidence.vertex)
.any(|x| x.vertex == u && x.edge == incidence.edge),
"edge {:?} from incidences of vertex {u:?} missing in incidences of \
adjacent vertex {:?}",
incidence.edge,
incidence.vertex
);
}
}
}
}
pub fn incidences_loop_edge<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, v, e) = G::loop_edge();
let mut iter = graph.incidences(v);
assert_eq!(
iter.next(),
Some(Incidence { vertex: v, edge: e }),
"vertex should be adjacent to itself"
);
assert_eq!(
iter.next(),
Some(Incidence { vertex: v, edge: e }),
"vertex should be adjacent to itself twice"
);
assert_eq!(
iter.next(),
None,
"too many adjacent vertices from iterator"
);
}
pub fn incidences_multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
const K: usize = 3;
let (graph, vertices, edges) = G::multiple_edges::<K>();
for (i, &v) in vertices.iter().enumerate() {
let mut iter = graph.incidences(v);
for j in 0..K {
let current = iter.next().unwrap_or_else(|| {
panic!("incidence {j} missing, expected {K} incidences for vertex {v:?}")
});
assert_eq!(
current.vertex,
vertices[1 - i],
"unexpected adjacent vertex of vertex {v:?} in incidence {j}"
);
assert_eq!(
edges.iter().filter(|&&e| e == current.edge).count(),
1,
"unexpected incident edge {:?} of vertex {v:?}",
current.edge
);
}
assert_eq!(
iter.next(),
None,
"too many adjacent vertices of {v:?} from iterator"
);
}
}
pub fn incidence_cursor_empty<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, v) = G::single_vertex();
let mut cursor = graph.incidence_cursor(v);
assert_eq!(
cursor.next(&graph),
None,
"incidence cursor of vertex with degree 0 should immediately be exhausted"
);
}
pub fn incidence_cursor<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, vertices, _, incidences) = G::standard();
assert_eq!(vertices.len(), incidences.len());
for (&v, incs) in vertices.iter().zip(&incidences) {
let mut expected = incs.clone();
let mut cursor = graph.incidence_cursor(v);
while let Some(incidence) = cursor.next(&graph) {
let pos = expected
.iter()
.position(|&x| x == incidence)
.unwrap_or_else(|| {
panic!("unexpected incidence {incidence:?} of vertex {v:?} from cursor")
});
expected.swap_remove(pos);
}
assert!(
expected.is_empty(),
"expected incidences {expected:?} of vertex {v:?} were not matched by cursor"
);
}
}
pub fn incidence_cursor_loop_edge<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, v, e) = G::loop_edge();
let mut cursor = graph.incidence_cursor(v);
assert_eq!(
cursor.next(&graph),
Some(Incidence { vertex: v, edge: e }),
"vertex should be adjacent to itself"
);
assert_eq!(
cursor.next(&graph),
Some(Incidence { vertex: v, edge: e }),
"vertex should be adjacent to itself twice"
);
assert_eq!(cursor.next(&graph), None, "too many incidences from cursor");
}
pub fn incidence_cursor_multiple_edges<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
const K: usize = 3;
let (graph, vertices, edges) = G::multiple_edges::<K>();
for (i, &v) in vertices.iter().enumerate() {
let mut cursor = graph.incidence_cursor(v);
for j in 0..K {
let current = cursor.next(&graph).unwrap_or_else(|| {
panic!("incidence {j} missing, expected {K} incidences for vertex {v:?}")
});
assert_eq!(
current.vertex,
vertices[1 - i],
"unexpected adjacent vertex of vertex {v:?} in incidence {j}"
);
assert_eq!(
edges.iter().filter(|&&e| e == current.edge).count(),
1,
"unexpected incident edge {:?} of vertex {v:?}",
current.edge
);
}
assert_eq!(
cursor.next(&graph),
None,
"too many incidences of {v:?} from cursor"
);
}
}
pub fn incidence_cursor_copy<G: MakeTestGraph>() {
let (graph, [_, v, _], _) = G::two_edge_path();
let mut c1 = graph.incidence_cursor(v);
assert!(c1.next(&graph).is_some(), "expected first incidence");
let mut c2 = c1;
assert!(
c1.next(&graph).is_some(),
"expected second incidence from original cursor"
);
assert!(
c1.next(&graph).is_none(),
"expected original cursor to be exhausted"
);
assert!(
c2.next(&graph).is_some(),
"expected second incidence from copied cursor"
);
assert!(
c2.next(&graph).is_none(),
"expected copied cursor to be exhausted"
);
}
pub fn incident_vertices_incidences_consistency<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, _, _, _) = G::standard();
for u in graph.vertices() {
for incidence in graph.incidences(u) {
let (w1, w2) = graph.incident_vertices(incidence.edge);
assert!(
(w1 == u && w2 == incidence.vertex) || (w1 == incidence.vertex && w2 == u),
"edge endpoints {w1:?} and {w2:?} are inconsistent with incidence \
({:?}, {:?}) of vertex {u:?}",
incidence.vertex,
incidence.edge
);
}
}
}
pub fn incident_edges_incidences_consistency<G: MakeTestGraph>()
where
G::Vertex: Debug,
G::Edge: Debug,
{
let (graph, _, _, _) = G::standard();
for u in graph.vertices() {
let mut expected: Vec<_> = graph.incidences(u).map(|x| x.edge).collect();
for e in graph.incident_edges(u) {
let pos = expected.iter().position(|&f| f == e).unwrap_or_else(|| {
panic!("incident edge {e:?} of vertex {u:?} missing from incidences")
});
expected.swap_remove(pos);
}
assert!(
expected.is_empty(),
"incidence edges {expected:?} of vertex {u:?} not matched by incident_edges"
);
}
}