From 0ff830ef48713e019959b9ede950648cf625f2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Mon, 31 Aug 2026 19:49:42 +0200 Subject: [PATCH] Refactor graph trait tests to minimize macro code, and split into separate files per macro The tests only declare a list of tests in the macro, no longer the test functions themselves. This allows better tooling support (e.g. IDE and rustfmt). --- src/testing.rs | 3 + ...raph_topology_addition_deletion_testing.rs | 62 + .../graph_topology_addition_testing.rs | 152 ++ .../graph_topology_deletion_testing.rs | 542 +++++ src/testing/graph_topology_testing.rs | 2017 +++++++---------- 5 files changed, 1528 insertions(+), 1248 deletions(-) create mode 100644 src/testing/graph_topology_addition_deletion_testing.rs create mode 100644 src/testing/graph_topology_addition_testing.rs create mode 100644 src/testing/graph_topology_deletion_testing.rs diff --git a/src/testing.rs b/src/testing.rs index 64c099c..d730642 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,4 +1,7 @@ //! Test fixture and test macros for graph topology and algorithm implementations. pub mod fixtures; +pub(crate) mod graph_topology_addition_deletion_testing; +pub(crate) mod graph_topology_addition_testing; +pub(crate) mod graph_topology_deletion_testing; pub(crate) mod graph_topology_testing; diff --git a/src/testing/graph_topology_addition_deletion_testing.rs b/src/testing/graph_topology_addition_deletion_testing.rs new file mode 100644 index 0000000..14fb7be --- /dev/null +++ b/src/testing/graph_topology_addition_deletion_testing.rs @@ -0,0 +1,62 @@ +use std::fmt::Debug; + +use crate::testing::fixtures::MakeTestGraph; +use crate::traits::{GraphTopologyAddition, GraphTopologyDeletion}; + +#[doc(hidden)] +#[macro_export] +macro_rules! graph_topology_addition_deletion_tests { + ($T:ty) => { + $crate::graph_topology_addition_deletion_tests!(@wrap $T, + delete_vertex_add_vertex, + delete_edge_add_edge, + ); + }; + + (@wrap $T:ty, $($name:ident),* $(,)?) => { + $( + #[test] + fn $name() { + $crate::testing::graph_topology_addition_deletion_testing::$name::<$T>(); + } + )* + }; +} + +pub(crate) fn delete_vertex_add_vertex() +where + G::Vertex: Debug, +{ + let (mut graph, v) = G::single_vertex(); + graph.delete_vertex(v); + assert_eq!( + graph.vertex_count(), + 0, + "unexpected vertex count after delete" + ); + assert_ne!( + graph.add_vertex(), + v, + "unexpected duplicate vertex after delete" + ); + assert_eq!( + graph.vertex_count(), + 1, + "unexpected vertex count after re-add" + ); +} + +pub(crate) fn delete_edge_add_edge() +where + G::Edge: Debug, +{ + let (mut graph, vertices, e) = G::single_edge(); + graph.delete_edge(e); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); + assert_ne!( + graph.add_edge(vertices[0], vertices[1]), + e, + "unexpected duplicate edge after re-add" + ); + assert_eq!(graph.edge_count(), 1, "unexpected edge count after re-add"); +} diff --git a/src/testing/graph_topology_addition_testing.rs b/src/testing/graph_topology_addition_testing.rs new file mode 100644 index 0000000..386fa8d --- /dev/null +++ b/src/testing/graph_topology_addition_testing.rs @@ -0,0 +1,152 @@ +use std::fmt::Debug; + +use crate::traits::GraphTopologyAddition; + +#[doc(hidden)] +#[macro_export] +macro_rules! graph_topology_addition_tests { + ($T:ty) => { + $crate::graph_topology_addition_tests!(@wrap $T, + reserve_vertices_increases_capacity, + reserve_vertices_prevents_reallocation_on_add, + reserve_vertices_does_not_affect_edge_capacity, + reserve_edges_increases_capacity, + reserve_edges_prevents_reallocation_on_add, + reserve_edges_does_not_affect_vertex_capacity, + add_vertex, + add_edge, + vertex_map_new_vertex, + edge_map_new_edge, + ); + }; + + (@wrap $T:ty, $($name:ident),* $(,)?) => { + $( + #[test] + fn $name() { + $crate::testing::graph_topology_addition_testing::$name::<$T>(); + } + )* + }; +} + +pub(crate) fn reserve_vertices_increases_capacity() { + let mut graph = G::default(); + let capacity_before = graph.vertex_capacity(); + graph.reserve_vertices(capacity_before + 10); + assert!( + graph.vertex_capacity() > capacity_before, + "expected sufficient capacity increase after reserve" + ); +} + +pub(crate) fn reserve_vertices_prevents_reallocation_on_add() { + let mut graph = G::default(); + graph.reserve_vertices(10); + let capacity_before = graph.vertex_capacity(); + for _ in 0..10 { + graph.add_vertex(); + } + assert_eq!( + graph.vertex_capacity(), + capacity_before, + "writes within reserved capacity should not reallocate" + ); +} + +pub(crate) fn reserve_vertices_does_not_affect_edge_capacity() { + let mut graph = G::default(); + let capacity_before = graph.edge_capacity(); + graph.reserve_vertices(10); + assert_eq!( + graph.edge_capacity(), + capacity_before, + "reserve_vertices must not change edge capacity" + ); +} + +pub(crate) fn reserve_edges_increases_capacity() { + let mut graph = G::default(); + let capacity_before = graph.edge_capacity(); + graph.reserve_edges(capacity_before + 10); + assert!( + graph.edge_capacity() > capacity_before, + "expected sufficient capacity increase after reserve" + ); +} + +pub(crate) fn reserve_edges_prevents_reallocation_on_add() { + let mut graph = G::default(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + graph.reserve_edges(10); + let capacity_before = graph.edge_capacity(); + for _ in 0..10 { + graph.add_edge(v1, v2); + } + assert_eq!( + graph.edge_capacity(), + capacity_before, + "writes within reserved capacity should not reallocate" + ); +} + +pub(crate) fn reserve_edges_does_not_affect_vertex_capacity() { + let mut graph = G::default(); + let capacity_before = graph.vertex_capacity(); + graph.reserve_edges(10); + assert_eq!( + graph.vertex_capacity(), + capacity_before, + "reserve_edges must not change vertex capacity" + ); +} + +pub(crate) fn add_vertex() +where + G::Vertex: Debug, +{ + let mut graph = G::default(); + let v = graph.add_vertex(); + assert_ne!(graph.add_vertex(), v, "unexpected duplicate vertex"); +} + +pub(crate) fn add_edge() +where + G::Edge: Debug, +{ + let mut graph = G::default(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + let e = graph.add_edge(v1, v2); + assert_ne!(graph.add_edge(v1, v2), e, "unexpected duplicate edge"); +} + +pub(crate) fn vertex_map_new_vertex() { + let mut graph = G::default(); + let mut map = graph.vertex_map(27); + let v = graph.add_vertex(); + assert_eq!( + map[v], 27, + "unexpected value from default map read for new vertex" + ); + map[v] = 9; + assert_eq!( + map[v], 9, + "unexpected value from map read after write for new vertex" + ); +} + +pub(crate) fn edge_map_new_edge() { + let mut graph = G::default(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + let mut map = graph.edge_map(28); + let e = graph.add_edge(v1, v2); + assert_eq!(map[e], 28); + map[e] = 8; + assert_eq!( + map[e], 8, + "unexpected value from map read after write for new edge" + ); +} diff --git a/src/testing/graph_topology_deletion_testing.rs b/src/testing/graph_topology_deletion_testing.rs new file mode 100644 index 0000000..d530df7 --- /dev/null +++ b/src/testing/graph_topology_deletion_testing.rs @@ -0,0 +1,542 @@ +use std::fmt::Debug; + +use crate::testing::fixtures::MakeTestGraph; +use crate::traits::{ + GraphTopology, GraphTopologyAddition, GraphTopologyDeletion, Incidence, IncidenceCursor, +}; + +#[doc(hidden)] +#[macro_export] +macro_rules! graph_topology_deletion_tests { + ($T:ty) => { + $crate::graph_topology_deletion_tests!(@wrap $T, + delete_vertex, + delete_vertex_loop, + delete_vertex_invalid_index, + delete_vertex_connected, + delete_edge, + delete_edge_loop, + delete_edge_multiple, + delete_edge_invalid_index, + vertices_after_delete, + incident_vertices_after_delete_edge, + edges_after_delete, + incident_edges_after_delete_edge, + incident_edges_after_delete_vertex, + incidences_after_delete_vertex, + incidences_after_delete_edge, + incidence_cursor_after_delete_vertex, + incidence_cursor_after_delete_edge, + ); + }; + + (@wrap $T:ty, $($name:ident),* $(,)?) => { + $( + #[test] + fn $name() { + $crate::testing::graph_topology_deletion_testing::$name::<$T>(); + } + )* + }; +} + +pub(crate) fn delete_vertex() { + let (mut graph, v) = G::single_vertex(); + assert_eq!( + graph.vertex_count(), + 1, + "unexpected vertex count before delete" + ); + graph.delete_vertex(v); + assert_eq!( + graph.vertex_count(), + 0, + "unexpected vertex count after delete" + ); +} + +pub(crate) fn delete_vertex_loop() { + let (mut graph, v, _) = G::loop_edge(); + assert_eq!( + graph.vertex_count(), + 1, + "unexpected vertex count before delete" + ); + assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); + assert!( + graph.are_adjacent(v, v), + "expected vertex to be self-adjacent before delete" + ); + assert_eq!(graph.degree(v), 2, "unexpected vertex degree before delete"); + graph.delete_vertex(v); + assert_eq!( + graph.vertex_count(), + 0, + "unexpected vertex count after delete" + ); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); +} + +pub(crate) fn delete_vertex_invalid_index() { + let (mut graph, v) = G::single_vertex(); + graph.delete_vertex(v); + let result = + std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || graph.delete_vertex(v))); + assert!(result.is_err(), "second deletion should panic"); +} + +pub(crate) fn delete_vertex_connected() +where + G::Vertex: Debug, +{ + let (mut graph, vertices, _, _) = G::standard(); + assert_eq!( + graph.vertex_count(), + 10, + "unexpected vertex count before delete" + ); + assert_eq!( + graph.edge_count(), + 18, + "unexpected edge count before delete" + ); + graph.delete_vertex(vertices[2]); + assert_eq!( + graph.vertex_count(), + 9, + "unexpected vertex count after delete" + ); + assert_eq!(graph.edge_count(), 12, "unexpected edge count after delete"); + let expected_edges = [ + (vertices[0], vertices[1]), + (vertices[1], vertices[3]), + (vertices[1], vertices[4]), + (vertices[3], vertices[6]), + (vertices[4], vertices[4]), + (vertices[4], vertices[7]), + (vertices[4], vertices[8]), + (vertices[5], vertices[9]), + (vertices[6], vertices[9]), + (vertices[7], vertices[8]), + (vertices[7], vertices[9]), + ]; + for (v, u) in expected_edges { + assert!( + graph.are_adjacent(v, u), + "expected {v:?} and {u:?} to be adjacent after delete" + ); + } + for v in [vertices[1], vertices[4], vertices[5], vertices[6]] { + assert!( + !graph.adjacent_vertices(v).any(|u| u == vertices[2]), + "unexpected adjacency of {v:?} to deleted vertex {:?}", + vertices[2] + ); + } +} + +pub(crate) fn delete_edge() { + let (mut graph, vertices, e) = G::single_edge(); + assert_eq!( + graph.vertex_count(), + 2, + "unexpected vertex count before delete" + ); + assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); + assert!( + graph.are_adjacent(vertices[0], vertices[1]), + "expected vertices to be adjacent before delete" + ); + assert_eq!( + graph.degree(vertices[0]), + 1, + "unexpected vertex degree before delete" + ); + assert_eq!( + graph.degree(vertices[1]), + 1, + "unexpected vertex degree before delete" + ); + graph.delete_edge(e); + assert_eq!( + graph.vertex_count(), + 2, + "unexpected vertex count after delete" + ); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); + assert!( + !graph.are_adjacent(vertices[0], vertices[1]), + "unexpected adjacency after delete" + ); + assert_eq!( + graph.degree(vertices[0]), + 0, + "unexpected vertex degree after delete" + ); + assert_eq!( + graph.degree(vertices[1]), + 0, + "unexpected vertex degree after delete" + ); +} + +pub(crate) fn delete_edge_loop() { + let (mut graph, v, e) = G::loop_edge(); + assert_eq!( + graph.vertex_count(), + 1, + "unexpected vertex count before delete" + ); + assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); + assert!( + graph.are_adjacent(v, v), + "expected vertex to be self-adjacent before delete" + ); + assert_eq!(graph.degree(v), 2, "unexpected vertex degree before delete"); + graph.delete_edge(e); + assert_eq!( + graph.vertex_count(), + 1, + "unexpected vertex count after delete" + ); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); + assert!( + !graph.are_adjacent(v, v), + "unexpected adjacency after delete" + ); + assert_eq!(graph.degree(v), 0, "unexpected vertex degree after delete"); +} + +pub(crate) fn delete_edge_multiple() { + const K: usize = 2; + let (mut graph, vertices, edges) = G::multiple_edges::(); + assert_eq!( + graph.vertex_count(), + 2, + "unexpected vertex count before delete" + ); + assert_eq!(graph.edge_count(), K, "unexpected edge count before delete"); + assert!( + graph.are_adjacent(vertices[0], vertices[1]), + "expected vertices to be adjacent before delete" + ); + assert_eq!( + graph.degree(vertices[0]), + K, + "unexpected vertex degree before delete" + ); + assert_eq!( + graph.degree(vertices[1]), + K, + "unexpected vertex degree before delete" + ); + graph.delete_edge(edges[0]); + assert_eq!( + graph.vertex_count(), + 2, + "unexpected vertex count after delete" + ); + assert_eq!( + graph.edge_count(), + K - 1, + "unexpected edge count after delete" + ); + assert!( + graph.are_adjacent(vertices[0], vertices[1]), + "expected vertices to be adjacent after delete" + ); + assert_eq!( + graph.degree(vertices[0]), + K - 1, + "unexpected vertex degree after delete" + ); + assert_eq!( + graph.degree(vertices[1]), + K - 1, + "unexpected vertex degree after delete" + ); +} + +pub(crate) fn delete_edge_invalid_index() { + let (mut graph, _, e) = G::single_edge(); + graph.delete_edge(e); + let result = + std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || graph.delete_edge(e))); + assert!(result.is_err(), "second deletion should panic"); +} + +pub(crate) fn vertices_after_delete() +where + G::Vertex: Debug, +{ + let (mut graph, vertices, _, _) = G::standard(); + graph.delete_vertex(vertices[2]); + assert_eq!( + graph.vertex_count(), + 9, + "unexpected vertex count after delete" + ); + assert_eq!( + graph.vertices().count(), + 9, + "unexpected vertex iterator count after delete" + ); + for v in graph.vertices() { + assert_ne!( + v, vertices[2], + "deleted vertex {:?} appeared in iterator", + vertices[2] + ); + } + for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { + assert!( + graph.vertices().any(|v| v == vertices[i]), + "expected vertex {:?} missing from iterator after delete", + vertices[i] + ); + } +} + +pub(crate) fn incident_vertices_after_delete_edge< + G: GraphTopologyDeletion + GraphTopologyAddition, +>() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, _, edges, _) = G::standard(); + let e = edges[2].0; + graph.delete_edge(e); + for &(f, v1, v2) in edges.iter().filter(|&&(f, _, _)| f != e) { + let (u1, u2) = graph.incident_vertices(f); + assert!( + (u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1), + "unexpected incident vertices {u1:?} and {u2:?} for edge {f:?} after delete" + ); + } +} + +pub(crate) fn edges_after_delete() +where + G::Edge: Debug, +{ + let (mut graph, vertices, edges, _) = G::standard(); + graph.delete_vertex(vertices[2]); + assert_eq!(graph.edge_count(), 12, "unexpected edge count after delete"); + assert_eq!( + graph.edges().count(), + 12, + "unexpected edge iterator count after delete" + ); + for i in [2, 5, 6, 7, 8, 9] { + assert!( + !graph.edges().any(|e| e == edges[i].0), + "deleted edge {:?} appeared in iterator", + edges[i].0 + ); + } + for i in [0, 1, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17] { + assert!( + graph.edges().any(|e| e == edges[i].0), + "expected edge {:?} missing from iterator after delete", + edges[i].0 + ); + } +} + +pub(crate) fn incident_edges_after_delete_edge() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, edges, incidences) = G::standard(); + graph.delete_edge(edges[2].0); + for i in 0..10 { + let mut expected: Vec<_> = incidences[i] + .iter() + .filter_map(|x| (x.edge != edges[2].0).then_some(x.edge)) + .collect(); + assert_eq!( + graph.incident_edges(vertices[i]).count(), + expected.len(), + "unexpected incident edge count for vertex {:?} after delete", + vertices[i] + ); + for e in graph.incident_edges(vertices[i]) { + let pos = expected.iter().position(|f| *f == e).expect(&format!( + "unexpected incident edge {e:?} of vertex {:?} after delete", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incident edges {:?} of vertex {:?} not matched after delete", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incident_edges_after_delete_vertex() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, _, incidences) = G::standard(); + graph.delete_vertex(vertices[2]); + for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { + let mut expected: Vec<_> = incidences[i] + .iter() + .filter_map(|x| (x.vertex != vertices[2]).then_some(x.edge)) + .collect(); + assert_eq!( + graph.incident_edges(vertices[i]).count(), + expected.len(), + "unexpected incident edge count for vertex {:?} after delete", + vertices[i] + ); + for e in graph.incident_edges(vertices[i]) { + let pos = expected.iter().position(|f| *f == e).expect(&format!( + "unexpected incident edge {e:?} of vertex {:?} after delete", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incident edges {:?} of vertex {:?} not matched after delete", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incidences_after_delete_vertex() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, _, incidences) = G::standard(); + graph.delete_vertex(vertices[2]); + for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { + let remaining = incidences[i] + .iter() + .filter(|x| x.vertex != vertices[2]) + .cloned() + .collect(); + assert_vertex_incidences(&graph, vertices[i], remaining); + } +} + +pub(crate) fn incidences_after_delete_edge() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, edges, incidences) = G::standard(); + graph.delete_edge(edges[2].0); + for i in 0..10 { + let remaining = incidences[i] + .iter() + .filter(|x| x.edge != edges[2].0) + .cloned() + .collect(); + assert_vertex_incidences(&graph, vertices[i], remaining); + } +} + +pub(crate) fn incidence_cursor_after_delete_vertex< + G: GraphTopologyDeletion + GraphTopologyAddition, +>() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, _, incidences) = G::standard(); + graph.delete_vertex(vertices[2]); + for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { + let remaining = incidences[i] + .iter() + .filter(|x| x.vertex != vertices[2]) + .cloned() + .collect(); + assert_vertex_incidence_cursor(&graph, vertices[i], remaining); + } +} + +pub(crate) fn incidence_cursor_after_delete_edge() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (mut graph, vertices, edges, incidences) = G::standard(); + graph.delete_edge(edges[2].0); + for i in 0..10 { + let remaining = incidences[i] + .iter() + .filter(|x| x.edge != edges[2].0) + .cloned() + .collect(); + assert_vertex_incidence_cursor(&graph, vertices[i], remaining); + } +} + +fn assert_vertex_incidences( + graph: &G, + v: G::Vertex, + mut expected: Vec>, +) where + G::Vertex: Debug, + G::Edge: Debug, +{ + assert_eq!( + graph.incidences(v).count(), + expected.len(), + "unexpected incidence count for vertex {:?} after delete", + v + ); + for incidence in graph.incidences(v) { + let pos = expected + .iter() + .position(|x| *x == incidence) + .expect(&format!( + "unexpected incidence {incidence:?} of vertex {:?} from iterator after delete", + v + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incidences {:?} of vertex {:?} not matched by iterator after delete", + expected, + v + ); +} + +fn assert_vertex_incidence_cursor( + graph: &G, + v: G::Vertex, + mut expected: Vec>, +) where + G::Vertex: Debug, + G::Edge: Debug, +{ + let mut cursor = graph.incidence_cursor(v); + while let Some(incidence) = cursor.next(graph) { + let pos = expected + .iter() + .position(|x| *x == incidence) + .expect(&format!( + "unexpected incidence {incidence:?} of vertex {:?} from cursor after delete", + v + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incidences {:?} of vertex {:?} not matched by cursor after delete", + expected, + v + ); +} diff --git a/src/testing/graph_topology_testing.rs b/src/testing/graph_topology_testing.rs index dd414b7..1d45f83 100644 --- a/src/testing/graph_topology_testing.rs +++ b/src/testing/graph_topology_testing.rs @@ -1,1285 +1,806 @@ +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) => { - #[test] - fn vertex_count_empty() { - use $crate::traits::GraphTopology; - let graph: $T = $crate::testing::fixtures::MakeTestGraph::empty(); - assert_eq!(graph.vertex_count(), 0, "unexpected vertex count"); - } + $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, + ); + }; - #[test] - fn vertex_count() { - use $crate::traits::GraphTopology; - let (graph, _, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - assert_eq!(graph.vertex_count(), 10, "unexpected vertex count"); - } - - #[test] - fn vertex_map() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - let mut map = graph.vertex_map(27); - assert_eq!(map[v], 27, "unexpected value from default map read"); - map[v] = 9; - assert_eq!(map[v], 9, "unexpected value from map after write"); - } - - #[test] - fn edge_count_empty() { - use $crate::traits::GraphTopology; - let graph: $T = $crate::testing::fixtures::MakeTestGraph::empty(); - assert_eq!(graph.edge_count(), 0, "unexpected edge count"); - } - - #[test] - fn edge_count() { - use $crate::traits::GraphTopology; - let (graph, _, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - assert_eq!(graph.edge_count(), 18, "unexpected edge count"); - } - - #[test] - fn edge_map() { - use $crate::traits::GraphTopology; - let (graph, _, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::single_edge(); - let mut map = graph.edge_map(28); - assert_eq!(map[e], 28, "unexpected value from default map read"); - map[e] = 8; - assert_eq!(map[e], 8, "unexpected value from map after write"); - } - - #[test] - fn degree_zero() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert_eq!(graph.degree(v), 0, "unexpected non-zero degree"); - } - - #[test] - fn degree() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - let expected_degrees = [2, 5, 7, 2, 7, 2, 3, 3, 2, 3]; - for i in 0..graph.vertex_count() { - assert_eq!( - graph.degree(vertices[i]), - expected_degrees[i], - "unexpected degree of {:?}", - vertices[i] - ); + (@wrap $T:ty, $($name:ident),* $(,)?) => { + $( + #[test] + fn $name() { + $crate::testing::graph_topology_testing::$name::<$T>(); } - } + )* + }; +} - #[test] - fn loop_edge() { - use $crate::traits::GraphTopology; - let (graph, v, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::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(crate) fn vertex_count_empty() { + let graph = G::empty(); + assert_eq!(graph.vertex_count(), 0, "unexpected vertex count"); +} - #[test] - fn multiple_edges() { - use $crate::traits::GraphTopology; - const K: usize = 3; - let (graph, vertices, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - assert_eq!(graph.vertex_count(), 2, "unexpected vertex count"); - assert_eq!(graph.edge_count(), K, "unexpected edge count"); - assert_eq!(graph.degree(vertices[0]), K, "unexpected degree of vertex {:?}", vertices[0]); - assert_eq!(graph.degree(vertices[1]), K, "unexpected degree of vertex {:?}", vertices[1]); - assert!(graph.are_adjacent(vertices[0], vertices[1]), "should be adjacent"); - } +pub(crate) fn vertex_count() { + let (graph, _, _, _) = G::standard(); + assert_eq!(graph.vertex_count(), 10, "unexpected vertex count"); +} - #[test] - fn are_adjacent_vertex_self() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert!(!graph.are_adjacent(v, v), "should not be adjacent to itself"); - } +pub(crate) fn vertex_map() { + let (graph, v) = G::single_vertex(); + let mut map = graph.vertex_map(27); + assert_eq!(map[v], 27, "unexpected value from default map read"); + map[v] = 9; + assert_eq!(map[v], 9, "unexpected value from map after write"); +} - #[test] - fn are_adjacent_single_edge() { - use $crate::traits::GraphTopology; - let (graph, vertices, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::single_edge(); - assert!(graph.are_adjacent(vertices[0], vertices[1]), "should be adjacent"); - assert!(graph.are_adjacent(vertices[1], vertices[0]), "should be adjacent"); - } +pub(crate) fn edge_count_empty() { + let graph = G::empty(); + assert_eq!(graph.edge_count(), 0, "unexpected edge count"); +} - #[test] - fn are_adjacent() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::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] - ); +pub(crate) fn edge_count() { + let (graph, _, _, _) = G::standard(); + assert_eq!(graph.edge_count(), 18, "unexpected edge count"); +} - for i in 0..graph.vertex_count() { - let exp = match i { - 1 | 2 | 4 | 5 | 6 => true, - _ => false, - }; - assert_eq!( - graph.are_adjacent(vertices[2], vertices[i]), - exp, - "unexpected adjacency of {:?} and {:?}", - vertices[2], - vertices[i] - ); - assert_eq!( - graph.are_adjacent(vertices[i], vertices[2]), - exp, - "unexpected adjacency of {:?} and {:?}", - vertices[i], - vertices[2] - ); - } - } +pub(crate) fn edge_map() { + let (graph, _, e) = G::single_edge(); + let mut map = graph.edge_map(28); + assert_eq!(map[e], 28, "unexpected value from default map read"); + map[e] = 8; + assert_eq!(map[e], 8, "unexpected value from map after write"); +} - #[test] - fn vertices_empty() { - use $crate::traits::GraphTopology; - let graph: $T = $crate::testing::fixtures::MakeTestGraph::empty(); - assert_eq!( - graph.vertices().count(), - 0, - "vertex iterator of empty graph should have no elements" - ); - } +pub(crate) fn degree_zero() { + let (graph, v) = G::single_vertex(); + assert_eq!(graph.degree(v), 0, "unexpected non-zero degree"); +} - #[test] - fn vertices() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - assert_eq!(graph.vertices().count(), 10, "unexpected vertex count"); +pub(crate) fn degree() +where + G::Vertex: Debug, +{ + let (graph, vertices, _, _) = G::standard(); + let expected_degrees = [2, 5, 7, 2, 7, 2, 3, 3, 2, 3]; + for i in 0..graph.vertex_count() { + assert_eq!( + graph.degree(vertices[i]), + expected_degrees[i], + "unexpected degree of {:?}", + vertices[i] + ); + } +} - // Expects each vertex to appear exactly once. - for v in graph.vertices() { - assert_eq!( - vertices.iter().filter(|&x| *x == v).count(), - 1, - "unexpected vertex {v:?} from iterator" - ); - } - } +pub(crate) fn loop_edge() { + 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" + ); +} - #[test] - fn adjacent_vertices_empty() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert_eq!( - graph.adjacent_vertices(v).count(), - 0, - "adjacent vertex iterator of vertex with degree 0 should have no elements" - ); - } +pub(crate) fn multiple_edges() +where + G::Vertex: Debug, +{ + const K: usize = 3; + let (graph, vertices, _) = G::multiple_edges::(); + assert_eq!(graph.vertex_count(), 2, "unexpected vertex count"); + assert_eq!(graph.edge_count(), K, "unexpected edge count"); + assert_eq!( + graph.degree(vertices[0]), + K, + "unexpected degree of vertex {:?}", + vertices[0] + ); + assert_eq!( + graph.degree(vertices[1]), + K, + "unexpected degree of vertex {:?}", + vertices[1] + ); + assert!( + graph.are_adjacent(vertices[0], vertices[1]), + "should be adjacent" + ); +} - #[test] - fn adjacent_vertices() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - // Checks adjacency of vertex 4. - 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) - .expect(&format!( - "unexpected adjacent vertex {v:?} of {:?} from iterator", - vertices[4] - )); - expected_adjacency.swap_remove(i); - } - assert_eq!( - expected_adjacency.len(), - 0, - "expected adjacent vertices {:?} of {:?} were not matched by iterator", - expected_adjacency, +pub(crate) fn are_adjacent_vertex_self() { + let (graph, v) = G::single_vertex(); + assert!( + !graph.are_adjacent(v, v), + "should not be adjacent to itself" + ); +} + +pub(crate) fn are_adjacent_single_edge() { + let (graph, vertices, _) = G::single_edge(); + assert!( + graph.are_adjacent(vertices[0], vertices[1]), + "should be adjacent" + ); + assert!( + graph.are_adjacent(vertices[1], vertices[0]), + "should be adjacent" + ); +} + +pub(crate) fn are_adjacent() +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 in 0..graph.vertex_count() { + let exp = match i { + 1 | 2 | 4 | 5 | 6 => true, + _ => false, + }; + assert_eq!( + graph.are_adjacent(vertices[2], vertices[i]), + exp, + "unexpected adjacency of {:?} and {:?}", + vertices[2], + vertices[i] + ); + assert_eq!( + graph.are_adjacent(vertices[i], vertices[2]), + exp, + "unexpected adjacency of {:?} and {:?}", + vertices[i], + vertices[2] + ); + } +} + +pub(crate) fn vertices_empty() { + let graph = G::empty(); + assert_eq!( + graph.vertices().count(), + 0, + "vertex iterator of empty graph should have no elements" + ); +} + +pub(crate) fn vertices() +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(crate) fn adjacent_vertices_empty() { + 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(crate) fn adjacent_vertices() +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) + .expect(&format!( + "unexpected adjacent vertex {v:?} of {:?} from iterator", vertices[4] - ); - } + )); + expected_adjacency.swap_remove(i); + } + assert_eq!( + expected_adjacency.len(), + 0, + "expected adjacent vertices {:?} of {:?} were not matched by iterator", + expected_adjacency, + vertices[4] + ); +} - #[test] - fn adjacent_vertices_loop_edge() { - use $crate::traits::GraphTopology; - let (graph, v, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::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(crate) fn adjacent_vertices_loop_edge() +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" + ); +} - #[test] - fn adjacent_vertices_multiple_edges() { - use $crate::traits::GraphTopology; - const K: usize = 3; - let (graph, vertices, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - for i in 0..2 { - let mut iter = graph.adjacent_vertices(vertices[i]); - for j in 0..K { - assert_eq!( - iter.next(), - Some(vertices[1 - i]), - "unexpected adjacent vertex {j} of vertex {:?}", - vertices[i] - ); - } - assert_eq!( - iter.next(), - None, - "too many adjacent vertices of vertex {:?} from iterator", - vertices[i] - ); - } - } - - #[test] - fn incident_vertices_single_edge() { - use $crate::traits::GraphTopology; - let (graph, vertices, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::single_edge(); - let (u, v) = graph.incident_vertices(e); - assert!( - (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), - "unexpected incident vertices {u:?} and {v:?} for edge {e:?}" - ); - } - - #[test] - fn incident_vertices_loop_edge() { - use $crate::traits::GraphTopology; - let (graph, v, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::loop_edge(); - assert_eq!( - graph.incident_vertices(e), - (v, v), - "unexpected incident vertices for loop edge {e:?}" - ); - } - - #[test] - fn incident_vertices_multiple_edges() { - use $crate::traits::GraphTopology; - let (graph, vertices, edges): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::<2>(); - assert_ne!(edges[0], edges[1], "edges should be distinct"); - let (u, v) = graph.incident_vertices(edges[0]); - assert!( - (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), - "unexpected incident vertices {u:?} and {v:?} for first multi-edge {:?}", - edges[0] - ); - let (u, v) = graph.incident_vertices(edges[1]); - assert!( - (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), - "unexpected incident vertices {u:?} and {v:?} for second multi-edge {:?}", - edges[1] - ); - } - - #[test] - fn incident_vertices() { - use $crate::traits::GraphTopology; - let (graph, _, edges, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - for &(e, v1, v2) in edges.iter() { - let (u1, u2) = graph.incident_vertices(e); - assert!( - (u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1), - "unexpected incident vertices {u1:?} and {u2:?} for edge {e:?}" - ); - } - } - - #[test] - fn edges_empty() { - use $crate::traits::GraphTopology; - let graph: $T = $crate::testing::fixtures::MakeTestGraph::empty(); - assert_eq!( - graph.edges().count(), - 0, - "edge iterator of empty graph should have no elements" - ); - } - - #[test] - fn edges() { - use $crate::traits::GraphTopology; - let (graph, _, edges, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - assert_eq!(graph.edges().count(), 18, "unexpected edge count"); - - // Expects each edge to appear exactly once. - for e in graph.edges() { - assert_eq!( - edges.iter().filter(|&&(f, _, _)| f == e).count(), - 1, - "unexpected edge {e:?} from iterator" - ); - } - } - - #[test] - fn incident_edges_empty() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert_eq!( - graph.incident_edges(v).count(), - 0, - "incident edge iterator of vertex with degree 0 should have no elements" - ); - } - - #[test] - fn incident_edges() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - for i in 0..10 { - assert_eq!( - graph.incident_edges(vertices[i]).count(), - incidences[i].len(), - "unexpected incident edge count for vertex {:?}", - vertices[i] - ); - let mut expected: Vec<_> = incidences[i].iter().map(|x| x.edge).collect(); - for e in graph.incident_edges(vertices[i]) { - let pos = expected - .iter() - .position(|f| *f == e) - .expect(&format!( - "unexpected incident edge {e:?} of vertex {:?} from iterator", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incident edges {:?} of vertex {:?} were not matched by iterator", - expected, - vertices[i] - ); - } - } - - #[test] - fn incident_edges_loop_edge() { - use $crate::traits::GraphTopology; - let (graph, v, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::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"); - } - - #[test] - fn incident_edges_multiple_edges() { - use $crate::traits::GraphTopology; - const K: usize = 3; - let (graph, vertices, edges): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - for i in 0..2 { - let mut expected = edges.to_vec(); - for e in graph.incident_edges(vertices[i]) { - let pos = expected - .iter() - .position(|f| *f == e) - .expect(&format!( - "unexpected incident edge {e:?} of vertex {:?}", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incident edges {:?} of vertex {:?} were not matched by iterator", - expected, - vertices[i] - ); - } - } - - #[test] - fn incidences_empty() { - use $crate::traits::GraphTopology; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert_eq!( - graph.incidences(v).count(), - 0, - "incidence iterator of vertex with degree 0 should have no elements" - ); - } - - #[test] - fn incidences() { - use $crate::traits::GraphTopology; - let (graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - for i in 0..10 { - assert_eq!( - graph.incidences(vertices[i]).count(), - incidences[i].len(), - "unexpected incidence count for vertex {:?}", - vertices[i] - ); - let mut expected = incidences[i].clone(); - for incidence in graph.incidences(vertices[i]) { - let pos = expected - .iter() - .position(|x| *x == incidence) - .expect(&format!( - "unexpected incidence {incidence:?} of vertex {:?} from iterator", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incidences {:?} of vertex {:?} were not matched by iterator", - expected, - vertices[i] - ); - } - } - - #[test] - fn incidences_edge_consistency() { - use $crate::traits::GraphTopology; - // For each incidence (v, e) of u, the same edge e must appear in the incidences of v. - // For loop edges (u == v), the edge must appear exactly twice in the incidences of u. - let (graph, _, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::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 - ); - } - } - } - } - - #[test] - fn incidences_loop_edge() { - use $crate::traits::{GraphTopology, Incidence}; - let (graph, v, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::loop_edge(); - let mut iter = graph.incidences(v); +pub(crate) fn adjacent_vertices_multiple_edges() +where + G::Vertex: Debug, +{ + const K: usize = 3; + let (graph, vertices, _) = G::multiple_edges::(); + for i in 0..2 { + let mut iter = graph.adjacent_vertices(vertices[i]); + for j in 0..K { 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"); - } - - #[test] - fn incidences_multiple_edges() { - use $crate::traits::GraphTopology; - const K: usize = 3; - let (graph, vertices, edges): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - for i in 0..2 { - let mut iter = graph.incidences(vertices[i]); - for j in 0..K { - let current = iter.next().expect(&format!( - "incidence {j} missing, expected {K} incidences for vertex {:?}", - vertices[i] - )); - assert_eq!( - current.vertex, - vertices[1 - i], - "unexpected adjacent vertex of vertex {:?} in incidence {j}", - vertices[i] - ); - assert_eq!( - edges.iter().filter(|e| **e == current.edge).count(), - 1, - "unexpected incident edge {:?} of vertex {:?}", - current.edge, - vertices[i], - ); - } - assert_eq!( - iter.next(), - None, - "too many adjacent vertices of {:?} from iterator", - vertices[i] - ); - } - } - - #[test] - fn incidence_cursor_empty() { - use $crate::traits::{GraphTopology, IncidenceCursor}; - let (graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::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" + Some(vertices[1 - i]), + "unexpected adjacent vertex {j} of vertex {:?}", + vertices[i] ); } - - #[test] - fn incidence_cursor() { - use $crate::traits::{GraphTopology, IncidenceCursor}; - let (graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - for i in 0..10 { - let mut expected = incidences[i].clone(); - let mut cursor = graph.incidence_cursor(vertices[i]); - while let Some(incidence) = cursor.next(&graph) { - let pos = expected - .iter() - .position(|x| *x == incidence) - .expect(&format!( - "unexpected incidence {incidence:?} of vertex {:?} from cursor", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incidences {:?} of vertex {:?} were not matched by cursor", - expected, - vertices[i] - ); - } - } - - #[test] - fn incidence_cursor_loop_edge() { - use $crate::traits::{GraphTopology, Incidence, IncidenceCursor}; - let (graph, v, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::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"); - } - - #[test] - fn incidence_cursor_multiple_edges() { - use $crate::traits::{GraphTopology, IncidenceCursor}; - const K: usize = 3; - let (graph, vertices, edges): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - for i in 0..2 { - let mut cursor = graph.incidence_cursor(vertices[i]); - for j in 0..K { - let current = cursor.next(&graph).expect(&format!( - "incidence {j} missing, expected {K} incidences for vertex {:?}", - vertices[i] - )); - assert_eq!( - current.vertex, - vertices[1 - i], - "unexpected adjacent vertex of vertex {:?} in incidence {j}", - vertices[i] - ); - assert_eq!( - edges.iter().filter(|e| **e == current.edge).count(), - 1, - "unexpected incident edge {:?} of vertex {:?}", - current.edge, - vertices[i], - ); - } - assert_eq!( - cursor.next(&graph), - None, - "too many incidences of {:?} from cursor", - vertices[i] - ); - } - } - - #[test] - fn incidence_cursor_copy() { - use $crate::traits::{GraphTopology, IncidenceCursor}; - let (graph, vertices, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::two_edge_path(); - // Traverses incidences of the middle vertex. - let mut c1 = graph.incidence_cursor(vertices[1]); - assert!(c1.next(&graph).is_some(), "expected first incidence"); - // Copies cursor mid-traversal. - let mut c2 = c1; - // Continues iteration with original cursor. - assert!(c1.next(&graph).is_some(), "expected second incidence from original cursor"); - assert!(c1.next(&graph).is_none(), "expected original cursor to be exhausted"); - // Replays from the copy point with the copied cursor. - assert!(c2.next(&graph).is_some(), "expected second incidence from copied cursor"); - assert!(c2.next(&graph).is_none(), "expected copied cursor to be exhausted"); - } - - #[test] - fn incident_vertices_incidences_consistency() { - use $crate::traits::GraphTopology; - let (graph, _, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::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 - ); - } - } - } - - #[test] - fn incident_edges_incidences_consistency() { - use $crate::traits::GraphTopology; - let (graph, _, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::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) - .expect(&format!( - "incident edge {e:?} of vertex {u:?} missing from incidences" - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "incidence edges {:?} of vertex {u:?} not matched by incident_edges", - expected - ); - } - } - }; + assert_eq!( + iter.next(), + None, + "too many adjacent vertices of vertex {:?} from iterator", + vertices[i] + ); + } } -#[doc(hidden)] -#[macro_export] -macro_rules! graph_topology_addition_tests { - ($T:ty) => { - #[test] - fn reserve_vertices_increases_capacity() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let capacity_before = graph.vertex_capacity(); - graph.reserve_vertices(capacity_before + 10); - assert!( - graph.vertex_capacity() > capacity_before, - "expected sufficient capacity increase after reserve" - ); - } - - #[test] - fn reserve_vertices_prevents_reallocation_on_add() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - graph.reserve_vertices(10); - let capacity_before = graph.vertex_capacity(); - for _ in 0..10 { - graph.add_vertex(); - } - assert_eq!( - graph.vertex_capacity(), - capacity_before, - "writes within reserved capacity should not reallocate" - ); - } - - #[test] - fn reserve_vertices_does_not_affect_edge_capacity() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let capacity_before = graph.edge_capacity(); - graph.reserve_vertices(10); - assert_eq!( - graph.edge_capacity(), - capacity_before, - "reserve_vertices must not change edge capacity" - ); - } - - #[test] - fn reserve_edges_increases_capacity() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let capacity_before = graph.edge_capacity(); - graph.reserve_edges(capacity_before + 10); - assert!( - graph.edge_capacity() > capacity_before, - "expected sufficient capacity increase after reserve" - ); - } - - #[test] - fn reserve_edges_prevents_reallocation_on_add() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let v1 = graph.add_vertex(); - let v2 = graph.add_vertex(); - graph.reserve_edges(10); - let capacity_before = graph.edge_capacity(); - for _ in 0..10 { - graph.add_edge(v1, v2); - } - assert_eq!( - graph.edge_capacity(), - capacity_before, - "writes within reserved capacity should not reallocate" - ); - } - - #[test] - fn reserve_edges_does_not_affect_vertex_capacity() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let capacity_before = graph.vertex_capacity(); - graph.reserve_edges(10); - assert_eq!( - graph.vertex_capacity(), - capacity_before, - "reserve_edges must not change vertex capacity" - ); - } - - #[test] - fn add_vertex() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let v = graph.add_vertex(); - assert_ne!(graph.add_vertex(), v, "unexpected duplicate vertex"); - } - - #[test] - fn add_edge() { - use $crate::traits::GraphTopologyAddition; - let mut graph = <$T>::default(); - let v1 = graph.add_vertex(); - let v2 = graph.add_vertex(); - let e = graph.add_edge(v1, v2); - assert_ne!(graph.add_edge(v1, v2), e, "unexpected duplicate edge"); - } - - #[test] - fn vertex_map_new_vertex() { - use $crate::traits::{GraphTopology, GraphTopologyAddition}; - let mut graph = <$T>::default(); - let mut map = graph.vertex_map(27); - let v = graph.add_vertex(); - assert_eq!( - map[v], 27, - "unexpected value from default map read for new vertex" - ); - map[v] = 9; - assert_eq!( - map[v], 9, - "unexpected value from map read after write for new vertex" - ); - } - - #[test] - fn edge_map_new_edge() { - use $crate::traits::{GraphTopology, GraphTopologyAddition}; - let mut graph = <$T>::default(); - let v1 = graph.add_vertex(); - let v2 = graph.add_vertex(); - let mut map = graph.edge_map(28); - let e = graph.add_edge(v1, v2); - assert_eq!(map[e], 28,); - map[e] = 8; - assert_eq!( - map[e], 8, - "unexpected value from map read after write for new edge" - ); - } - }; +pub(crate) fn incident_vertices_single_edge() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, vertices, e) = G::single_edge(); + let (u, v) = graph.incident_vertices(e); + assert!( + (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), + "unexpected incident vertices {u:?} and {v:?} for edge {e:?}" + ); } -#[doc(hidden)] -#[macro_export] -macro_rules! graph_topology_deletion_tests { - ($T:ty) => { - #[test] - fn delete_vertex() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - assert_eq!(graph.vertex_count(), 1, "unexpected vertex count before delete"); - graph.delete_vertex(v); - assert_eq!(graph.vertex_count(), 0, "unexpected vertex count after delete"); - } - - #[test] - fn delete_vertex_loop() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, v, _): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::loop_edge(); - assert_eq!(graph.vertex_count(), 1, "unexpected vertex count before delete"); - assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); - assert!( - graph.are_adjacent(v, v), - "expected vertex to be self-adjacent before delete" - ); - assert_eq!(graph.degree(v), 2, "unexpected vertex degree before delete"); - graph.delete_vertex(v); - assert_eq!(graph.vertex_count(), 0, "unexpected vertex count after delete"); - assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); - } - - #[test] - fn delete_vertex_invalid_index() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - graph.delete_vertex(v); - let result = std::panic::catch_unwind(move || graph.delete_vertex(v)); - assert!(result.is_err(), "second deletion should panic"); - } - - #[test] - fn delete_vertex_connected() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - assert_eq!(graph.vertex_count(), 10, "unexpected vertex count before delete"); - assert_eq!(graph.edge_count(), 18, "unexpected edge count before delete"); - graph.delete_vertex(vertices[2]); - assert_eq!(graph.vertex_count(), 9, "unexpected vertex count after delete"); - assert_eq!(graph.edge_count(), 12, "unexpected edge count after delete"); - let expected_edges = [ - (vertices[0], vertices[1]), - (vertices[1], vertices[3]), - (vertices[1], vertices[4]), - (vertices[3], vertices[6]), - (vertices[4], vertices[4]), - (vertices[4], vertices[7]), - (vertices[4], vertices[8]), - (vertices[5], vertices[9]), - (vertices[6], vertices[9]), - (vertices[7], vertices[8]), - (vertices[7], vertices[9]), - ]; - for (v, u) in expected_edges { - assert!( - graph.are_adjacent(v, u), - "expected {v:?} and {u:?} to be adjacent after delete" - ); - } - for v in [vertices[1], vertices[4], vertices[5], vertices[6]] { - assert!( - !graph.adjacent_vertices(v).any(|u| u == vertices[2]), - "unexpected adjacency of {v:?} to deleted vertex {:?}", - vertices[2] - ); - } - } - - #[test] - fn delete_edge() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::single_edge(); - assert_eq!(graph.vertex_count(), 2, "unexpected vertex count before delete"); - assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); - assert!( - graph.are_adjacent(vertices[0], vertices[1]), - "expected vertices to be adjacent before delete" - ); - assert_eq!(graph.degree(vertices[0]), 1, "unexpected vertex degree before delete"); - assert_eq!(graph.degree(vertices[1]), 1, "unexpected vertex degree before delete"); - graph.delete_edge(e); - assert_eq!(graph.vertex_count(), 2, "unexpected vertex count after delete"); - assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); - assert!( - !graph.are_adjacent(vertices[0], vertices[1]), - "unexpected adjacency after delete" - ); - assert_eq!(graph.degree(vertices[0]), 0, "unexpected vertex degree after delete"); - assert_eq!(graph.degree(vertices[1]), 0, "unexpected vertex degree after delete"); - } - - #[test] - fn delete_edge_loop() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, v, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::loop_edge(); - assert_eq!(graph.vertex_count(), 1, "unexpected vertex count before delete"); - assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); - assert!(graph.are_adjacent(v, v), "expected vertex to be self-adjacent before delete"); - assert_eq!(graph.degree(v), 2, "unexpected vertex degree before delete"); - graph.delete_edge(e); - assert_eq!(graph.vertex_count(), 1, "unexpected vertex count after delete"); - assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); - assert!(!graph.are_adjacent(v, v), "unexpected adjacency after delete"); - assert_eq!(graph.degree(v), 0, "unexpected vertex degree after delete"); - } - - #[test] - fn delete_edge_multiple() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - const K: usize = 2; - let (mut graph, vertices, edges): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::multiple_edges::(); - assert_eq!(graph.vertex_count(), 2, "unexpected vertex count before delete"); - assert_eq!(graph.edge_count(), K, "unexpected edge count before delete"); - assert!( - graph.are_adjacent(vertices[0], vertices[1]), - "expected vertices to be adjacent before delete" - ); - assert_eq!(graph.degree(vertices[0]), K, "unexpected vertex degree before delete"); - assert_eq!(graph.degree(vertices[1]), K, "unexpected vertex degree before delete"); - graph.delete_edge(edges[0]); - assert_eq!(graph.vertex_count(), 2, "unexpected vertex count after delete"); - assert_eq!(graph.edge_count(), K - 1, "unexpected edge count after delete"); - assert!( - graph.are_adjacent(vertices[0], vertices[1]), - "expected vertices to be adjacent after delete" - ); - assert_eq!(graph.degree(vertices[0]), K - 1, "unexpected vertex degree after delete"); - assert_eq!(graph.degree(vertices[1]), K - 1, "unexpected vertex degree after delete"); - } - - #[test] - fn delete_edge_invalid_index() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, _, e): ($T, _, _) = $crate::testing::fixtures::MakeTestGraph::single_edge(); - graph.delete_edge(e); - let result = std::panic::catch_unwind(move || graph.delete_edge(e)); - assert!(result.is_err(), "second deletion should panic"); - } - - #[test] - fn vertices_after_delete() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, _, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_vertex(vertices[2]); - assert_eq!(graph.vertex_count(), 9, "unexpected vertex count after delete"); - assert_eq!( - graph.vertices().count(), - 9, - "unexpected vertex iterator count after delete" - ); - for v in graph.vertices() { - assert_ne!( - v, vertices[2], - "deleted vertex {:?} appeared in iterator", - vertices[2] - ); - } - for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { - assert!( - graph.vertices().any(|v| v == vertices[i]), - "expected vertex {:?} missing from iterator after delete", - vertices[i] - ); - } - } - - #[test] - fn incident_vertices_after_delete_edge() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, _, edges, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - let e = edges[2].0; - graph.delete_edge(e); - for &(f, v1, v2) in edges.iter().filter(|&&(f, _, _)| f != e) { - let (u1, u2) = graph.incident_vertices(f); - assert!( - (u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1), - "unexpected incident vertices {u1:?} and {u2:?} for edge {f:?} after delete" - ); - } - } - - #[test] - fn edges_after_delete() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, edges, _): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_vertex(vertices[2]); - assert_eq!(graph.edge_count(), 12, "unexpected edge count after delete"); - assert_eq!(graph.edges().count(), 12, "unexpected edge iterator count after delete"); - for i in [2, 5, 6, 7, 8, 9] { - assert!( - !graph.edges().any(|e| e == edges[i].0), - "deleted edge {:?} appeared in iterator", - edges[i].0 - ); - } - for i in [0, 1, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17] { - assert!( - graph.edges().any(|e| e == edges[i].0), - "expected edge {:?} missing from iterator after delete", - edges[i].0 - ); - } - } - - #[test] - fn incident_edges_after_delete_edge() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, edges, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_edge(edges[2].0); - for i in 0..10 { - let mut expected: Vec<_> = incidences[i] - .iter() - .filter_map(|x| (x.edge != edges[2].0).then_some(x.edge)) - .collect(); - assert_eq!( - graph.incident_edges(vertices[i]).count(), - expected.len(), - "unexpected incident edge count for vertex {:?} after delete", - vertices[i] - ); - for e in graph.incident_edges(vertices[i]) { - let pos = expected.iter().position(|f| *f == e).expect(&format!( - "unexpected incident edge {e:?} of vertex {:?} after delete", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incident edges {:?} of vertex {:?} not matched after delete", - expected, - vertices[i] - ); - } - } - - #[test] - fn incident_edges_after_delete_vertex() { - use $crate::traits::{GraphTopology, GraphTopologyDeletion}; - let (mut graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_vertex(vertices[2]); - for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { - let mut expected: Vec<_> = incidences[i] - .iter() - .filter_map(|x| (x.vertex != vertices[2]).then_some(x.edge)) - .collect(); - assert_eq!( - graph.incident_edges(vertices[i]).count(), - expected.len(), - "unexpected incident edge count for vertex {:?} after delete", - vertices[i] - ); - for e in graph.incident_edges(vertices[i]) { - let pos = expected.iter().position(|f| *f == e).expect(&format!( - "unexpected incident edge {e:?} of vertex {:?} after delete", - vertices[i] - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incident edges {:?} of vertex {:?} not matched after delete", - expected, - vertices[i] - ); - } - } - - #[test] - fn incidences_after_delete_vertex() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_vertex(vertices[2]); - for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { - let remaining = incidences[i] - .iter() - .filter(|x| x.vertex != vertices[2]) - .cloned() - .collect(); - assert_vertex_incidences(&graph, vertices[i], remaining); - } - } - - #[test] - fn incidences_after_delete_edge() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, vertices, edges, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - // Deletes the edge from vertices[1] to vertices[2]. - graph.delete_edge(edges[2].0); - for i in 0..10 { - let remaining = incidences[i] - .iter() - .filter(|x| x.edge != edges[2].0) - .cloned() - .collect(); - assert_vertex_incidences(&graph, vertices[i], remaining); - } - } - - // TODO: Move out of macro. - fn assert_vertex_incidences( - graph: &$T, - v: <$T as $crate::traits::GraphTopology>::Vertex, - mut expected: Vec<$crate::traits::Incidence< - <$T as $crate::traits::GraphTopology>::Vertex, - <$T as $crate::traits::GraphTopology>::Edge, - >>, - ) { - use $crate::traits::GraphTopology; - assert_eq!( - graph.incidences(v).count(), - expected.len(), - "unexpected incidence count for vertex {:?} after delete", - v - ); - for incidence in graph.incidences(v) { - let pos = expected - .iter() - .position(|x| *x == incidence) - .expect(&format!( - "unexpected incidence {incidence:?} of vertex {:?} from iterator after delete", - v - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incidences {:?} of vertex {:?} not matched by iterator after delete", - expected, - v - ); - } - - #[test] - fn incidence_cursor_after_delete_vertex() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, vertices, _, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - graph.delete_vertex(vertices[2]); - for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] { - let remaining = incidences[i] - .iter() - .filter(|x| x.vertex != vertices[2]) - .cloned() - .collect(); - assert_vertex_incidence_cursor(&graph, vertices[i], remaining); - } - } - - #[test] - fn incidence_cursor_after_delete_edge() { - use $crate::traits::GraphTopologyDeletion; - let (mut graph, vertices, edges, incidences): ($T, _, _, _) = $crate::testing::fixtures::MakeTestGraph::standard(); - // Deletes the edge from vertices[1] to vertices[2]. - graph.delete_edge(edges[2].0); - for i in 0..10 { - let remaining = incidences[i] - .iter() - .filter(|x| x.edge != edges[2].0) - .cloned() - .collect(); - assert_vertex_incidence_cursor(&graph, vertices[i], remaining); - } - } - - // TODO: Move out of macro. - fn assert_vertex_incidence_cursor( - graph: &$T, - v: <$T as $crate::traits::GraphTopology>::Vertex, - mut expected: Vec<$crate::traits::Incidence< - <$T as $crate::traits::GraphTopology>::Vertex, - <$T as $crate::traits::GraphTopology>::Edge, - >>, - ) { - use $crate::traits::{GraphTopology, IncidenceCursor}; - let mut cursor = graph.incidence_cursor(v); - while let Some(incidence) = cursor.next(graph) { - let pos = expected - .iter() - .position(|x| *x == incidence) - .expect(&format!( - "unexpected incidence {incidence:?} of vertex {:?} from cursor after delete", - v - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incidences {:?} of vertex {:?} not matched by cursor after delete", - expected, - v - ); - } - }; +pub(crate) fn incident_vertices_loop_edge() +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:?}" + ); } -#[doc(hidden)] -#[macro_export] -macro_rules! graph_topology_addition_deletion_tests { - ($T:ty) => { - #[test] - fn delete_vertex_add_vertex() { - use $crate::traits::{GraphTopology, GraphTopologyAddition, GraphTopologyDeletion}; - let (mut graph, v): ($T, _) = $crate::testing::fixtures::MakeTestGraph::single_vertex(); - graph.delete_vertex(v); +pub(crate) fn incident_vertices_multiple_edges() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, vertices, edges) = G::multiple_edges::<2>(); + assert_ne!(edges[0], edges[1], "edges should be distinct"); + let (u, v) = graph.incident_vertices(edges[0]); + assert!( + (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), + "unexpected incident vertices {u:?} and {v:?} for first multi-edge {:?}", + edges[0] + ); + let (u, v) = graph.incident_vertices(edges[1]); + assert!( + (u == vertices[0] && v == vertices[1]) || (u == vertices[1] && v == vertices[0]), + "unexpected incident vertices {u:?} and {v:?} for second multi-edge {:?}", + edges[1] + ); +} + +pub(crate) fn incident_vertices() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, _, edges, _) = G::standard(); + for &(e, v1, v2) in edges.iter() { + let (u1, u2) = graph.incident_vertices(e); + assert!( + (u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1), + "unexpected incident vertices {u1:?} and {u2:?} for edge {e:?}" + ); + } +} + +pub(crate) fn edges_empty() { + let graph = G::empty(); + assert_eq!( + graph.edges().count(), + 0, + "edge iterator of empty graph should have no elements" + ); +} + +pub(crate) fn edges() +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(crate) fn incident_edges_empty() { + 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(crate) fn incident_edges() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, vertices, _, incidences) = G::standard(); + for i in 0..10 { + assert_eq!( + graph.incident_edges(vertices[i]).count(), + incidences[i].len(), + "unexpected incident edge count for vertex {:?}", + vertices[i] + ); + let mut expected: Vec<_> = incidences[i].iter().map(|x| x.edge).collect(); + for e in graph.incident_edges(vertices[i]) { + let pos = expected.iter().position(|f| *f == e).expect(&format!( + "unexpected incident edge {e:?} of vertex {:?} from iterator", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incident edges {:?} of vertex {:?} were not matched by iterator", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incident_edges_loop_edge() +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(crate) fn incident_edges_multiple_edges() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + const K: usize = 3; + let (graph, vertices, edges) = G::multiple_edges::(); + for i in 0..2 { + let mut expected = edges.to_vec(); + for e in graph.incident_edges(vertices[i]) { + let pos = expected.iter().position(|f| *f == e).expect(&format!( + "unexpected incident edge {e:?} of vertex {:?}", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incident edges {:?} of vertex {:?} were not matched by iterator", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incidences_empty() { + 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(crate) fn incidences() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, vertices, _, incidences) = G::standard(); + for i in 0..10 { + assert_eq!( + graph.incidences(vertices[i]).count(), + incidences[i].len(), + "unexpected incidence count for vertex {:?}", + vertices[i] + ); + let mut expected = incidences[i].clone(); + for incidence in graph.incidences(vertices[i]) { + let pos = expected + .iter() + .position(|x| *x == incidence) + .expect(&format!( + "unexpected incidence {incidence:?} of vertex {:?} from iterator", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incidences {:?} of vertex {:?} were not matched by iterator", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incidences_edge_consistency() +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(crate) fn incidences_loop_edge() +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(crate) fn incidences_multiple_edges() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + const K: usize = 3; + let (graph, vertices, edges) = G::multiple_edges::(); + for i in 0..2 { + let mut iter = graph.incidences(vertices[i]); + for j in 0..K { + let current = iter.next().expect(&format!( + "incidence {j} missing, expected {K} incidences for vertex {:?}", + vertices[i] + )); assert_eq!( - graph.vertex_count(), - 0, - "unexpected vertex count after delete" - ); - assert_ne!( - graph.add_vertex(), - v, - "unexpected duplicate vertex after delete" + current.vertex, + vertices[1 - i], + "unexpected adjacent vertex of vertex {:?} in incidence {j}", + vertices[i] ); assert_eq!( - graph.vertex_count(), + edges.iter().filter(|e| **e == current.edge).count(), 1, - "unexpected vertex count after re-add" + "unexpected incident edge {:?} of vertex {:?}", + current.edge, + vertices[i], ); } - - #[test] - fn delete_edge_add_edge() { - use $crate::traits::{GraphTopology, GraphTopologyAddition, GraphTopologyDeletion}; - let (mut graph, vertices, e): ($T, _, _) = - $crate::testing::fixtures::MakeTestGraph::single_edge(); - graph.delete_edge(e); - assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); - assert_ne!( - graph.add_edge(vertices[0], vertices[1]), - e, - "unexpected duplicate edge after re-add" - ); - assert_eq!(graph.edge_count(), 1, "unexpected edge count after re-add"); - } - }; + assert_eq!( + iter.next(), + None, + "too many adjacent vertices of {:?} from iterator", + vertices[i] + ); + } +} + +pub(crate) fn incidence_cursor_empty() +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(crate) fn incidence_cursor() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + let (graph, vertices, _, incidences) = G::standard(); + for i in 0..10 { + let mut expected = incidences[i].clone(); + let mut cursor = graph.incidence_cursor(vertices[i]); + while let Some(incidence) = cursor.next(&graph) { + let pos = expected + .iter() + .position(|x| *x == incidence) + .expect(&format!( + "unexpected incidence {incidence:?} of vertex {:?} from cursor", + vertices[i] + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incidences {:?} of vertex {:?} were not matched by cursor", + expected, + vertices[i] + ); + } +} + +pub(crate) fn incidence_cursor_loop_edge() +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(crate) fn incidence_cursor_multiple_edges() +where + G::Vertex: Debug, + G::Edge: Debug, +{ + const K: usize = 3; + let (graph, vertices, edges) = G::multiple_edges::(); + for i in 0..2 { + let mut cursor = graph.incidence_cursor(vertices[i]); + for j in 0..K { + let current = cursor.next(&graph).expect(&format!( + "incidence {j} missing, expected {K} incidences for vertex {:?}", + vertices[i] + )); + assert_eq!( + current.vertex, + vertices[1 - i], + "unexpected adjacent vertex of vertex {:?} in incidence {j}", + vertices[i] + ); + assert_eq!( + edges.iter().filter(|e| **e == current.edge).count(), + 1, + "unexpected incident edge {:?} of vertex {:?}", + current.edge, + vertices[i], + ); + } + assert_eq!( + cursor.next(&graph), + None, + "too many incidences of {:?} from cursor", + vertices[i] + ); + } +} + +pub(crate) fn incidence_cursor_copy() { + let (graph, vertices, _) = G::two_edge_path(); + let mut c1 = graph.incidence_cursor(vertices[1]); + 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(crate) fn incident_vertices_incidences_consistency() +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(crate) fn incident_edges_incidences_consistency() +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).expect(&format!( + "incident edge {e:?} of vertex {u:?} missing from incidences" + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "incidence edges {:?} of vertex {u:?} not matched by incident_edges", + expected + ); + } }