diff --git a/src/testing/fixtures.rs b/src/testing/fixtures.rs index f60dcf3..048d088 100644 --- a/src/testing/fixtures.rs +++ b/src/testing/fixtures.rs @@ -338,3 +338,143 @@ where } path } + +/// Asserts that the two graphs are isomorphic. +/// +/// `vertices` must contain all vertices of the `original` graph, and `vertex_map` must for any +/// vertex in the `original` graph return the corresponding vertex in the `other` graph. +/// +/// `edges` must contain all edges and their endpoints of the `original` graph, and `edge_map` must +/// for any edge in the `original` graph return the corresponding edge in the `other` graph. +pub fn assert_isomorphic( + original: &G, + other: &H, + vertices: &[G::Vertex], + vertex_map: impl Fn(G::Vertex) -> H::Vertex, + edges: &[(G::Edge, G::Vertex, G::Vertex)], + edge_map: impl Fn(G::Edge) -> H::Edge, +) where + G::Vertex: Debug, + G::Edge: Debug, + H::Vertex: Debug, + H::Edge: Debug, +{ + assert_eq!( + original.vertex_count(), + vertices.len(), + "precondition: all vertices of the original must be provided" + ); + assert_eq!( + original.edge_count(), + edges.len(), + "precondition: all edges of the original must be provided" + ); + assert_eq!( + other.vertex_count(), + original.vertex_count(), + "other graph should have the same vertex count as the original" + ); + assert_eq!( + other.edge_count(), + original.edge_count(), + "other graph should have the same edge count as the original" + ); + for &v in vertices.iter() { + assert_eq!( + other.degree(vertex_map(v)), + original.degree(v), + "vertex {v:?} should have the same degree in the other graph as in the original" + ); + let mut expected: Vec<_> = original.incidences(v).collect(); + for incidence in other.incidences(vertex_map(v)) { + let pos = expected + .iter() + .position(|x| { + vertex_map(x.vertex) == incidence.vertex && edge_map(x.edge) == incidence.edge + }) + .expect(&format!( + "unexpected incidence {incidence:?} of vertex {v:?} in the other graph" + )); + expected.swap_remove(pos); + } + assert!( + expected.is_empty(), + "expected incidences {expected:?} of vertex {v:?} are missing in the other graph" + ); + } + for &(e, u, v) in edges.iter() { + assert_eq!( + other.incident_vertices(edge_map(e)), + (vertex_map(u), vertex_map(v)), + "edge {e:?} should have the same incident vertices in the other graph as in the original" + ); + } +} + +/// Asserts that mutation of the two graphs happens independently. +/// +/// `vertices` must contain all vertices of the `original` graph, which must not be empty, and +/// `vertex_map` must for any vertex in the `original` graph return the corresponding vertex in the +/// `other` graph. +pub fn assert_mutation_independent( + original: &mut G, + other: &mut H, + vertices: &[G::Vertex], + vertex_map: impl Fn(G::Vertex) -> H::Vertex, +) { + let edge_count = original.edge_count(); + assert_eq!( + original.vertex_count(), + vertices.len(), + "precondition: all vertices of the original must be provided" + ); + assert!( + !vertices.is_empty(), + "precondition: at least one vertex must be provided" + ); + let u = other.add_vertex(); + other.add_edge(vertex_map(vertices[0]), u); + assert_eq!( + other.vertex_count(), + vertices.len() + 1, + "precondition: vertex count of other graph" + ); + assert_eq!( + other.edge_count(), + edge_count + 1, + "precondition: edge count of other graph" + ); + assert_eq!( + original.vertex_count(), + vertices.len(), + "mutating the other graph should not affect the vertex count of the original" + ); + assert_eq!( + original.edge_count(), + edge_count, + "mutating the other graph should not affect the edge count of the original" + ); + + let v = original.add_vertex(); + original.add_edge(vertices[0], v); + assert_eq!( + original.vertex_count(), + vertices.len() + 1, + "precondition: vertex count of original" + ); + assert_eq!( + original.edge_count(), + edge_count + 1, + "precondition: edge count of original" + ); + assert_eq!( + other.vertex_count(), + vertices.len() + 1, + "mutating the original should not affect the vertex count of the other graph" + ); + assert_eq!( + other.edge_count(), + edge_count + 1, + "mutating the original should not affect the edge count of the other graph" + ); +} diff --git a/src/testing/graph_topology_addition_clone_testing.rs b/src/testing/graph_topology_addition_clone_testing.rs index b476dfe..2f360eb 100644 --- a/src/testing/graph_topology_addition_clone_testing.rs +++ b/src/testing/graph_topology_addition_clone_testing.rs @@ -1,3 +1,4 @@ +use crate::testing::fixtures; use crate::testing::fixtures::MakeTestGraph; use crate::traits::GraphTopologyAddition; @@ -6,7 +7,7 @@ use crate::traits::GraphTopologyAddition; macro_rules! graph_topology_addition_clone_tests { ($T:ty) => { $crate::graph_topology_addition_clone_tests!(@wrap $T, - clone_independent, + clone_mutation_independent, ); }; @@ -20,37 +21,8 @@ macro_rules! graph_topology_addition_clone_tests { }; } -pub fn clone_independent() { - let (mut graph, [u, v], _) = G::single_edge(); +pub fn clone_mutation_independent() { + let (mut graph, vertices, _) = G::single_edge(); let mut clone = graph.clone(); - - let w = clone.add_vertex(); - clone.add_edge(u, w); - assert_eq!(clone.vertex_count(), 3, "precondition: vertex count of clone"); - assert_eq!(clone.edge_count(), 2, "precondition: edge count of clone"); - assert_eq!( - graph.vertex_count(), - 2, - "mutating the clone should not affect the vertex count of the original" - ); - assert_eq!( - graph.edge_count(), - 1, - "mutating the clone should not affect the edge count of the original" - ); - - let x = graph.add_vertex(); - graph.add_edge(v, x); - assert_eq!(graph.vertex_count(), 3, "precondition: vertex count of original"); - assert_eq!(graph.edge_count(), 2, "precondition: edge count of original"); - assert_eq!( - clone.vertex_count(), - 3, - "mutating the original should not affect the vertex count of the clone" - ); - assert_eq!( - clone.edge_count(), - 2, - "mutating the original should not affect the edge count of the clone" - ); + fixtures::assert_mutation_independent(&mut graph, &mut clone, &vertices, |v| v); } diff --git a/src/testing/graph_topology_clone_testing.rs b/src/testing/graph_topology_clone_testing.rs index 12b9606..b4ffd1e 100644 --- a/src/testing/graph_topology_clone_testing.rs +++ b/src/testing/graph_topology_clone_testing.rs @@ -1,5 +1,6 @@ use std::fmt::Debug; +use crate::testing::fixtures; use crate::testing::fixtures::MakeTestGraph; #[doc(hidden)] @@ -7,7 +8,6 @@ use crate::testing::fixtures::MakeTestGraph; macro_rules! graph_topology_clone_tests { ($T:ty) => { $crate::graph_topology_clone_tests!(@wrap $T, - clone_preserves_vertex_and_edge_count, clone_handles_interchangeable, ); }; @@ -22,21 +22,6 @@ macro_rules! graph_topology_clone_tests { }; } -pub fn clone_preserves_vertex_and_edge_count() { - let (graph, ..) = G::standard(); - let clone = graph.clone(); - assert_eq!( - clone.vertex_count(), - graph.vertex_count(), - "clone should have the same vertex count as the original" - ); - assert_eq!( - clone.edge_count(), - graph.edge_count(), - "clone should have the same edge count as the original" - ); -} - /// Queries the clone using vertex and edge handles obtained from the original graph, and asserts /// that the results are identical to querying the original with those same handles. This is only /// meaningful because Vertex and Edge handles are not tied to a particular graph instance. @@ -47,32 +32,5 @@ where { let (graph, vertices, edges, _) = G::standard(); let clone = graph.clone(); - for &v in vertices.iter() { - assert_eq!( - clone.degree(v), - graph.degree(v), - "vertex {v:?} should have the same degree in the clone as in the original" - ); - let mut expected: Vec<_> = graph.incidences(v).collect(); - for incidence in clone.incidences(v) { - let pos = expected - .iter() - .position(|x| *x == incidence) - .expect(&format!( - "unexpected incidence {incidence:?} of vertex {v:?} in the clone" - )); - expected.swap_remove(pos); - } - assert!( - expected.is_empty(), - "expected incidences {expected:?} of vertex {v:?} are missing in the clone" - ); - } - for &(e, u, v) in edges.iter() { - assert_eq!( - clone.incident_vertices(e), - (u, v), - "edge {e:?} should have the same incident vertices in the clone as in the original" - ); - } + fixtures::assert_isomorphic(&graph, &clone, &vertices, |v| v, &edges, |e| e); }