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 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 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 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 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 fn delete_edge() { let (mut graph, [v0, v1], 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(v0, v1), "expected vertices to be adjacent before delete" ); assert_eq!( graph.degree(v0), 1, "unexpected vertex degree before delete" ); assert_eq!( graph.degree(v1), 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(v0, v1), "unexpected adjacency after delete" ); assert_eq!(graph.degree(v0), 0, "unexpected vertex degree after delete"); assert_eq!(graph.degree(v1), 0, "unexpected vertex degree after delete"); } pub 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 fn delete_edge_multiple() { const K: usize = 2; let (mut graph, [v0, v1], 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(v0, v1), "expected vertices to be adjacent before delete" ); assert_eq!( graph.degree(v0), K, "unexpected vertex degree before delete" ); assert_eq!( graph.degree(v1), 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(v0, v1), "expected vertices to be adjacent after delete" ); assert_eq!( graph.degree(v0), K - 1, "unexpected vertex degree after delete" ); assert_eq!( graph.degree(v1), K - 1, "unexpected vertex degree after delete" ); } pub 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 fn vertices_after_delete() where G::Vertex: Debug, { let (mut graph, vertices, _, _) = G::standard(); let del = vertices[2]; graph.delete_vertex(del); 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, del, "deleted vertex {del:?} appeared in iterator"); } for &v in vertices.iter().filter(|&&u| u != del) { assert!( graph.vertices().any(|u| u == v), "expected vertex {v:?} missing from iterator after delete" ); } } pub fn incident_vertices_after_delete_edge() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, _, edges, _) = G::standard(); let del = edges[2].0; graph.delete_edge(del); for &(f, v0, v1) in edges.iter().filter(|&&(f, _, _)| f != del) { let (u0, u1) = graph.incident_vertices(f); assert!( (u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0), "unexpected incident vertices {u0:?} and {u1:?} for edge {f:?} after delete" ); } } pub 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 fn incident_edges_after_delete_edge() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, edges, incidences) = G::standard(); let del = edges[2].0; graph.delete_edge(del); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { let mut expected = incs .iter() .filter_map(|x| (x.edge != del).then_some(x.edge)) .collect(); assert_incident_edges_after_delete(&graph, v, &mut expected); } } pub fn incident_edges_after_delete_vertex() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, _, incidences) = G::standard(); let del = vertices[2]; graph.delete_vertex(del); for (&v, incs) in vertices.iter().zip(&incidences).filter(|&(&u, _)| u != del) { let mut expected = incs .iter() .filter_map(|x| (x.vertex != del).then_some(x.edge)) .collect(); assert_incident_edges_after_delete(&graph, v, &mut expected); } } pub fn incidences_after_delete_vertex() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, _, incidences) = G::standard(); let del = vertices[2]; graph.delete_vertex(del); for (&v, incs) in vertices.iter().zip(&incidences).filter(|&(&u, _)| u != del) { let remaining = incs.iter().filter(|x| x.vertex != del).cloned().collect(); assert_vertex_incidences(&graph, v, remaining); } } pub fn incidences_after_delete_edge() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, edges, incidences) = G::standard(); let del = edges[2].0; graph.delete_edge(del); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { let remaining = incs.iter().filter(|x| x.edge != del).cloned().collect(); assert_vertex_incidences(&graph, v, remaining); } } pub fn incidence_cursor_after_delete_vertex() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, _, incidences) = G::standard(); let del = vertices[2]; graph.delete_vertex(del); for (&v, incs) in vertices.iter().zip(&incidences).filter(|&(&u, _)| u != del) { let remaining = incs.iter().filter(|x| x.vertex != del).cloned().collect(); assert_vertex_incidence_cursor(&graph, v, remaining); } } pub fn incidence_cursor_after_delete_edge() where G::Vertex: Debug, G::Edge: Debug, { let (mut graph, vertices, edges, incidences) = G::standard(); let del = edges[2].0; graph.delete_edge(del); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { let remaining = incs.iter().filter(|x| x.edge != del).cloned().collect(); assert_vertex_incidence_cursor(&graph, v, 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 {v:?} after delete" ); 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 after delete" ) }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incidences {expected:?} of vertex {v:?} not matched by iterator after delete" ); } 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) .unwrap_or_else(|| { panic!( "unexpected incidence {incidence:?} of vertex {v:?} from cursor after delete" ) }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incidences {expected:?} of vertex {v:?} not matched by cursor after delete" ); } fn assert_incident_edges_after_delete( graph: &G, v: G::Vertex, expected: &mut Vec, ) where G::Vertex: Debug, G::Edge: Debug, { assert_eq!( graph.incident_edges(v).count(), expected.len(), "unexpected incident edge count for vertex {v:?} after delete" ); 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:?} after delete") }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incident edges {expected:?} of vertex {v:?} not matched after delete" ); }