Skip to content

Commit cfa8385

Browse files
committed
parametrized test
Signed-off-by: Pritam Singh <[email protected]>
1 parent c70e8ec commit cfa8385

File tree

1 file changed

+130
-57
lines changed

1 file changed

+130
-57
lines changed

src/graph/detect_cycle.rs

Lines changed: 130 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ pub trait DetectCycle {
1111
fn undirected_graph_detect_cycle_dfs<'a>(
1212
graph: &'a UndirectedGraph,
1313
visited_node: &mut HashSet<&'a String>,
14-
parent: &'a String,
14+
parent: Option<&'a String>,
1515
u: &'a String,
1616
) -> bool {
1717
visited_node.insert(u);
1818
for (v, _) in graph.adjacency_table().get(u).unwrap() {
19-
if v == parent {
19+
if matches!(parent, Some(parent) if v == parent) {
2020
continue;
2121
}
22-
if visited_node.contains(v) || undirected_graph_detect_cycle_dfs(graph, visited_node, u, v)
22+
if visited_node.contains(v)
23+
|| undirected_graph_detect_cycle_dfs(graph, visited_node, Some(u), v)
2324
{
2425
return true;
2526
}
@@ -36,19 +37,19 @@ fn undirected_graph_detect_cycle_bfs<'a>(
3637
visited_node.insert(u);
3738

3839
// Initialize the queue for BFS, storing (current node, parent node) tuples
39-
let mut queue = VecDeque::<(&String, &String)>::new();
40-
queue.push_back((u, u));
40+
let mut queue = VecDeque::<(&String, Option<&String>)>::new();
41+
queue.push_back((u, None));
4142

4243
while let Some((u, parent)) = queue.pop_front() {
4344
for (v, _) in graph.adjacency_table().get(u).unwrap() {
44-
if v == parent {
45+
if matches!(parent, Some(parent) if v == parent) {
4546
continue;
4647
}
4748
if visited_node.contains(v) {
4849
return true;
4950
}
5051
visited_node.insert(v);
51-
queue.push_back((v, u));
52+
queue.push_back((v, Some(u)));
5253
}
5354
}
5455
false
@@ -60,7 +61,7 @@ impl DetectCycle for UndirectedGraph {
6061
let adj = self.adjacency_table();
6162
for u in adj.keys() {
6263
if !visited_node.contains(u)
63-
&& undirected_graph_detect_cycle_dfs(self, &mut visited_node, u, u)
64+
&& undirected_graph_detect_cycle_dfs(self, &mut visited_node, None, u)
6465
{
6566
return true;
6667
}
@@ -166,56 +167,128 @@ impl DetectCycle for DirectedGraph {
166167

167168
#[cfg(test)]
168169
mod test {
169-
use crate::data_structures::{graph::Graph, DirectedGraph, UndirectedGraph};
170-
171170
use super::DetectCycle;
172-
173-
#[test]
174-
fn test_detect_cycle_in_undirected_graph() {
175-
let mut graph_with_cycle = UndirectedGraph::new();
176-
177-
graph_with_cycle.add_edge(("a", "b", 1));
178-
graph_with_cycle.add_edge(("a", "c", 1));
179-
graph_with_cycle.add_edge(("b", "c", 1));
180-
graph_with_cycle.add_edge(("b", "d", 1));
181-
graph_with_cycle.add_edge(("c", "d", 1));
182-
183-
assert!(graph_with_cycle.detect_cycle_dfs());
184-
assert!(graph_with_cycle.detect_cycle_bfs());
185-
186-
let mut graph_without_cycle = UndirectedGraph::new();
187-
188-
graph_without_cycle.add_edge(("a", "b", 1));
189-
graph_without_cycle.add_edge(("a", "c", 1));
190-
graph_without_cycle.add_edge(("b", "d", 1));
191-
graph_without_cycle.add_edge(("c", "e", 1));
192-
193-
assert!(!graph_without_cycle.detect_cycle_dfs());
194-
assert!(!graph_without_cycle.detect_cycle_bfs());
171+
use crate::data_structures::{graph::Graph, DirectedGraph, UndirectedGraph};
172+
fn get_undirected_single_node_with_loop() -> UndirectedGraph {
173+
let mut res = UndirectedGraph::new();
174+
res.add_edge(("a", "a", 1));
175+
res
195176
}
196-
197-
#[test]
198-
fn test_detect_cycle_in_directed_graph() {
199-
let mut graph_with_cycle = DirectedGraph::new();
200-
201-
graph_with_cycle.add_edge(("b", "a", 1));
202-
graph_with_cycle.add_edge(("c", "a", 1));
203-
graph_with_cycle.add_edge(("b", "c", 1));
204-
graph_with_cycle.add_edge(("c", "d", 1));
205-
graph_with_cycle.add_edge(("d", "b", 1));
206-
207-
assert!(graph_with_cycle.detect_cycle_dfs());
208-
assert!(graph_with_cycle.detect_cycle_bfs());
209-
210-
let mut graph_without_cycle = DirectedGraph::new();
211-
212-
graph_without_cycle.add_edge(("b", "a", 1));
213-
graph_without_cycle.add_edge(("c", "a", 1));
214-
graph_without_cycle.add_edge(("b", "c", 1));
215-
graph_without_cycle.add_edge(("c", "d", 1));
216-
graph_without_cycle.add_edge(("b", "d", 1));
217-
218-
assert!(!graph_without_cycle.detect_cycle_dfs());
219-
assert!(!graph_without_cycle.detect_cycle_bfs());
177+
fn get_directed_single_node_with_loop() -> DirectedGraph {
178+
let mut res = DirectedGraph::new();
179+
res.add_edge(("a", "a", 1));
180+
res
181+
}
182+
fn get_undirected_two_nodes_connected() -> UndirectedGraph {
183+
let mut res = UndirectedGraph::new();
184+
res.add_edge(("a", "b", 1));
185+
res
186+
}
187+
fn get_directed_two_nodes_connected() -> DirectedGraph {
188+
let mut res = DirectedGraph::new();
189+
res.add_edge(("a", "b", 1));
190+
res.add_edge(("b", "a", 1));
191+
res
192+
}
193+
fn get_directed_two_nodes() -> DirectedGraph {
194+
let mut res = DirectedGraph::new();
195+
res.add_edge(("a", "b", 1));
196+
res
197+
}
198+
fn get_undirected_triangle() -> UndirectedGraph {
199+
let mut res = UndirectedGraph::new();
200+
res.add_edge(("a", "b", 1));
201+
res.add_edge(("b", "c", 1));
202+
res.add_edge(("c", "a", 1));
203+
res
204+
}
205+
fn get_directed_triangle() -> DirectedGraph {
206+
let mut res = DirectedGraph::new();
207+
res.add_edge(("a", "b", 1));
208+
res.add_edge(("b", "c", 1));
209+
res.add_edge(("c", "a", 1));
210+
res
211+
}
212+
fn get_undirected_triangle_with_tail() -> UndirectedGraph {
213+
let mut res = get_undirected_triangle();
214+
res.add_edge(("c", "d", 1));
215+
res.add_edge(("d", "e", 1));
216+
res.add_edge(("e", "f", 1));
217+
res.add_edge(("g", "h", 1));
218+
res
219+
}
220+
fn get_directed_triangle_with_tail() -> DirectedGraph {
221+
let mut res = get_directed_triangle();
222+
res.add_edge(("c", "d", 1));
223+
res.add_edge(("d", "e", 1));
224+
res.add_edge(("e", "f", 1));
225+
res.add_edge(("g", "h", 1));
226+
res
227+
}
228+
fn get_undirected_graph_with_cycle() -> UndirectedGraph {
229+
let mut res = UndirectedGraph::new();
230+
res.add_edge(("a", "b", 1));
231+
res.add_edge(("a", "c", 1));
232+
res.add_edge(("b", "c", 1));
233+
res.add_edge(("b", "d", 1));
234+
res.add_edge(("c", "d", 1));
235+
res
236+
}
237+
fn get_undirected_graph_without_cycle() -> UndirectedGraph {
238+
let mut res = UndirectedGraph::new();
239+
res.add_edge(("a", "b", 1));
240+
res.add_edge(("a", "c", 1));
241+
res.add_edge(("b", "d", 1));
242+
res.add_edge(("c", "e", 1));
243+
res
244+
}
245+
fn get_directed_graph_with_cycle() -> DirectedGraph {
246+
let mut res = DirectedGraph::new();
247+
res.add_edge(("b", "a", 1));
248+
res.add_edge(("c", "a", 1));
249+
res.add_edge(("b", "c", 1));
250+
res.add_edge(("c", "d", 1));
251+
res.add_edge(("d", "b", 1));
252+
res
253+
}
254+
fn get_directed_graph_without_cycle() -> DirectedGraph {
255+
let mut res = DirectedGraph::new();
256+
res.add_edge(("b", "a", 1));
257+
res.add_edge(("c", "a", 1));
258+
res.add_edge(("b", "c", 1));
259+
res.add_edge(("c", "d", 1));
260+
res.add_edge(("b", "d", 1));
261+
res
262+
}
263+
macro_rules! test_detect_cycle {
264+
($($name:ident: $test_case:expr,)*) => {
265+
$(
266+
#[test]
267+
fn $name() {
268+
let (graph, has_cycle) = $test_case;
269+
println!("detect_cycle_dfs: {}", graph.detect_cycle_dfs());
270+
println!("detect_cycle_bfs: {}", graph.detect_cycle_bfs());
271+
assert_eq!(graph.detect_cycle_dfs(), has_cycle);
272+
assert_eq!(graph.detect_cycle_bfs(), has_cycle);
273+
}
274+
)*
275+
};
276+
}
277+
test_detect_cycle! {
278+
undirected_empty: (UndirectedGraph::new(), false),
279+
directed_empty: (DirectedGraph::new(), false),
280+
undirected_single_node_with_loop: (get_undirected_single_node_with_loop(), true),
281+
directed_single_node_with_loop: (get_directed_single_node_with_loop(), true),
282+
undirected_two_nodes_connected: (get_undirected_two_nodes_connected(), false),
283+
directed_two_nodes_connected: (get_directed_two_nodes_connected(), true),
284+
directed_two_nodes: (get_directed_two_nodes(), false),
285+
undirected_triangle: (get_undirected_triangle(), true),
286+
undirected_triangle_with_tail: (get_undirected_triangle_with_tail(), true),
287+
directed_triangle: (get_directed_triangle(), true),
288+
directed_triangle_with_tail: (get_directed_triangle_with_tail(), true),
289+
undirected_graph_with_cycle: (get_undirected_graph_with_cycle(), true),
290+
undirected_graph_without_cycle: (get_undirected_graph_without_cycle(), false),
291+
directed_graph_with_cycle: (get_directed_graph_with_cycle(), true),
292+
directed_graph_without_cycle: (get_directed_graph_without_cycle(), false),
220293
}
221294
}

0 commit comments

Comments
 (0)