#[doc(hidden)] #[macro_export] macro_rules! bfs_tests { ($T:ty) => { #[test] fn bfs_single_vertex() { use $crate::traits::GraphTopology; let mut graph = <$T>::new(); let v = graph.add_vertex(); let result = $crate::algorithms::bfs(&graph, v); assert_eq!( result.distances[v], Some(0), "unexpected distance of source vertex" ); assert_eq!( result.predecessors[v], None, "unexpected predecessor of source vertex" ); } #[test] fn bfs_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); let result = $crate::algorithms::bfs(&graph, vertices[0]); assert_eq!( result.distances[vertices[0]], Some(0), "unexpected distance of source vertex" ); assert_eq!( result.predecessors[vertices[0]], None, "unexpected predecessor of source vertex" ); for &v in &vertices[1..3] { assert_eq!( result.distances[v], None, "disconnected vertex {v:?} should have no distance" ); assert_eq!( result.predecessors[v], None, "disconnected vertex {v:?} should have no predecessor" ); } } #[test] fn bfs() { let (graph, vertices, _, _) = make_test_graph(); let result = $crate::algorithms::bfs(&graph, vertices[0]); assert_bfs_distances(&result.distances, &vertices); assert_bfs_predecessors(&result.predecessors, &vertices); } #[test] fn bfs_distances_single_vertex() { use $crate::traits::GraphTopology; let mut graph = <$T>::new(); let v = graph.add_vertex(); let distances = $crate::algorithms::bfs_distances(&graph, v); assert_eq!( distances[v], Some(0), "unexpected distance of source vertex" ); } #[test] fn bfs_distances_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); let distances = $crate::algorithms::bfs_distances(&graph, vertices[0]); assert_eq!( distances[vertices[0]], Some(0), "unexpected distance of source vertex" ); for &v in &vertices[1..3] { assert_eq!( distances[v], None, "disconnected vertex {v:?} should have no distance" ); } } #[test] fn bfs_distances() { let (graph, vertices, _, _) = make_test_graph(); let distances = $crate::algorithms::bfs_distances(&graph, vertices[0]); assert_bfs_distances(&distances, &vertices); } #[test] fn bfs_find_source() { use $crate::traits::GraphTopology; let mut graph = <$T>::new(); let v = graph.add_vertex(); assert_eq!( $crate::algorithms::bfs_find(&graph, v, v), Some(0), "source should be found at distance 0" ); } #[test] fn bfs_find_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); assert_eq!( $crate::algorithms::bfs_find(&graph, vertices[0], vertices[1]), None, "disconnected target should not be found" ); } #[test] fn bfs_find() { let (graph, vertices, _, _) = make_test_graph(); let expected_distances = [ Some(0), Some(1), Some(2), Some(2), Some(2), Some(3), Some(3), Some(3), Some(3), Some(4), ]; for i in 0..10 { assert_eq!( $crate::algorithms::bfs_find(&graph, vertices[0], vertices[i]), expected_distances[i], "unexpected distance from {:?} to {:?}", vertices[0], vertices[i] ); } } #[test] fn bfs_find_where_source_matches() { use $crate::traits::GraphTopology; let mut graph = <$T>::new(); let v = graph.add_vertex(); assert_eq!( $crate::algorithms::bfs_find_where(&graph, v, |u| u == v), Some((v, 0)), "source should match with distance 0" ); } #[test] fn bfs_find_where_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); assert_eq!( $crate::algorithms::bfs_find_where(&graph, vertices[0], |v| v == vertices[1]), None, "disconnected vertex {:?} should not be found", vertices[1] ); } #[test] fn bfs_find_where_no_match() { let (graph, vertices, _, _) = make_test_graph(); assert_eq!( $crate::algorithms::bfs_find_where(&graph, vertices[0], |_| false), None, "no vertex should match an always-false predicate" ); } #[test] fn bfs_find_where_nearest() { let (graph, vertices, _, _) = make_test_graph(); // vertices[5], vertices[6], vertices[7], vertices[8] are all at distance 3 from vertices[0]. // vertices[9] is at distance 4. Predicate matches vertices[7], vertices[8], vertices[9]. // BFS must return one of the distance-3 ones, not vertices[9]. let result = $crate::algorithms::bfs_find_where(&graph, vertices[0], |v| { v == vertices[7] || v == vertices[8] || v == vertices[9] }); assert!(result.is_some(), "expected a match"); let (found, distance) = result.unwrap(); assert_eq!( distance, 3, "unexpected distance to nearest matching vertex {found:?}", ); assert!( found == vertices[7] || found == vertices[8], "unexpected nearest match vertex {found:?}, should be {:?} or {:?}", vertices[7], vertices[8] ); } fn assert_bfs_distances( distances: &$crate::maps::VertexMap< <$T as $crate::traits::GraphTopology>::Vertex, Option, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { let expected = [ Some(0), Some(1), Some(2), Some(2), Some(2), Some(3), Some(3), Some(3), Some(3), Some(4), ]; for i in 0..10 { assert_eq!( distances[vertices[i]], expected[i], "unexpected BFS distance from {:?} to {:?}", vertices[0], vertices[i] ); } } fn assert_bfs_predecessors( predecessors: &$crate::maps::VertexMap< <$T as $crate::traits::GraphTopology>::Vertex, Option<<$T as $crate::traits::GraphTopology>::Vertex>, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { assert_eq!( predecessors[vertices[0]], None, "source should have no predecessor" ); // Each non-source vertex's predecessor must be adjacent and at distance one less. let expected_predecessors = [ vec![None], vec![Some(vertices[0])], vec![Some(vertices[1])], vec![Some(vertices[1])], vec![Some(vertices[1])], vec![Some(vertices[2])], vec![Some(vertices[2]), Some(vertices[3])], vec![Some(vertices[4])], vec![Some(vertices[4])], vec![Some(vertices[5]), Some(vertices[6]), Some(vertices[7])], ]; for i in 1..10 { assert!( expected_predecessors[i].contains(&predecessors[vertices[i]]), "unexpected predecessor {:?} of {:?}", predecessors[vertices[i]], vertices[i] ); } } }; }