Skip to content

Commit 22ed64c

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

File tree

1 file changed

+129
-57
lines changed

1 file changed

+129
-57
lines changed

src/graph/detect_cycle.rs

Lines changed: 129 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ 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) || undirected_graph_detect_cycle_dfs(graph, visited_node, Some(u), v)
2323
{
2424
return true;
2525
}
@@ -36,19 +36,19 @@ fn undirected_graph_detect_cycle_bfs<'a>(
3636
visited_node.insert(u);
3737

3838
// 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));
39+
let mut queue = VecDeque::<(&String, Option<&String>)>::new();
40+
queue.push_back((u, None));
4141

4242
while let Some((u, parent)) = queue.pop_front() {
4343
for (v, _) in graph.adjacency_table().get(u).unwrap() {
44-
if v == parent {
44+
if matches!(parent, Some(parent) if v == parent) {
4545
continue;
4646
}
4747
if visited_node.contains(v) {
4848
return true;
4949
}
5050
visited_node.insert(v);
51-
queue.push_back((v, u));
51+
queue.push_back((v, Some(u)));
5252
}
5353
}
5454
false
@@ -60,7 +60,7 @@ impl DetectCycle for UndirectedGraph {
6060
let adj = self.adjacency_table();
6161
for u in adj.keys() {
6262
if !visited_node.contains(u)
63-
&& undirected_graph_detect_cycle_dfs(self, &mut visited_node, u, u)
63+
&& undirected_graph_detect_cycle_dfs(self, &mut visited_node, None, u)
6464
{
6565
return true;
6666
}
@@ -167,55 +167,127 @@ impl DetectCycle for DirectedGraph {
167167
#[cfg(test)]
168168
mod test {
169169
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+
fn get_undirected_single_node_with_loop() -> UndirectedGraph {
172+
let mut res = UndirectedGraph::new();
173+
res.add_edge(("a", "a", 1));
174+
res
195175
}
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());
176+
fn get_directed_single_node_with_loop() -> DirectedGraph {
177+
let mut res = DirectedGraph::new();
178+
res.add_edge(("a", "a", 1));
179+
res
220180
}
221-
}
181+
fn get_undirected_two_nodes_connected() -> UndirectedGraph {
182+
let mut res = UndirectedGraph::new();
183+
res.add_edge(("a", "b", 1));
184+
res
185+
}
186+
fn get_directed_two_nodes_connected() -> DirectedGraph {
187+
let mut res = DirectedGraph::new();
188+
res.add_edge(("a", "b", 1));
189+
res.add_edge(("b", "a", 1));
190+
res
191+
}
192+
fn get_directed_two_nodes() -> DirectedGraph {
193+
let mut res = DirectedGraph::new();
194+
res.add_edge(("a", "b", 1));
195+
res
196+
}
197+
fn get_undirected_triangle() -> UndirectedGraph {
198+
let mut res = UndirectedGraph::new();
199+
res.add_edge(("a", "b", 1));
200+
res.add_edge(("b", "c", 1));
201+
res.add_edge(("c", "a", 1));
202+
res
203+
}
204+
fn get_directed_triangle() -> DirectedGraph {
205+
let mut res = DirectedGraph::new();
206+
res.add_edge(("a", "b", 1));
207+
res.add_edge(("b", "c", 1));
208+
res.add_edge(("c", "a", 1));
209+
res
210+
}
211+
fn get_undirected_triangle_with_tail() -> UndirectedGraph {
212+
let mut res = get_undirected_triangle();
213+
res.add_edge(("c", "d", 1));
214+
res.add_edge(("d", "e", 1));
215+
res.add_edge(("e", "f", 1));
216+
res.add_edge(("g", "h", 1));
217+
res
218+
}
219+
fn get_directed_triangle_with_tail() -> DirectedGraph {
220+
let mut res = get_directed_triangle();
221+
res.add_edge(("c", "d", 1));
222+
res.add_edge(("d", "e", 1));
223+
res.add_edge(("e", "f", 1));
224+
res.add_edge(("g", "h", 1));
225+
res
226+
}
227+
fn get_undirected_graph_with_cycle() -> UndirectedGraph {
228+
let mut res = UndirectedGraph::new();
229+
res.add_edge(("a", "b", 1));
230+
res.add_edge(("a", "c", 1));
231+
res.add_edge(("b", "c", 1));
232+
res.add_edge(("b", "d", 1));
233+
res.add_edge(("c", "d", 1));
234+
res
235+
}
236+
fn get_undirected_graph_without_cycle() -> UndirectedGraph {
237+
let mut res = UndirectedGraph::new();
238+
res.add_edge(("a", "b", 1));
239+
res.add_edge(("a", "c", 1));
240+
res.add_edge(("b", "d", 1));
241+
res.add_edge(("c", "e", 1));
242+
res
243+
}
244+
fn get_directed_graph_with_cycle() -> DirectedGraph {
245+
let mut res = DirectedGraph::new();
246+
res.add_edge(("b", "a", 1));
247+
res.add_edge(("c", "a", 1));
248+
res.add_edge(("b", "c", 1));
249+
res.add_edge(("c", "d", 1));
250+
res.add_edge(("d", "b", 1));
251+
res
252+
}
253+
fn get_directed_graph_without_cycle() -> DirectedGraph {
254+
let mut res = DirectedGraph::new();
255+
res.add_edge(("b", "a", 1));
256+
res.add_edge(("c", "a", 1));
257+
res.add_edge(("b", "c", 1));
258+
res.add_edge(("c", "d", 1));
259+
res.add_edge(("b", "d", 1));
260+
res
261+
}
262+
macro_rules! test_detect_cycle {
263+
($($name:ident: $test_case:expr,)*) => {
264+
$(
265+
#[test]
266+
fn $name() {
267+
let (graph, has_cycle) = $test_case;
268+
println!("detect_cycle_dfs: {}", graph.detect_cycle_dfs());
269+
println!("detect_cycle_bfs: {}", graph.detect_cycle_bfs());
270+
assert_eq!(graph.detect_cycle_dfs(), has_cycle);
271+
assert_eq!(graph.detect_cycle_bfs(), has_cycle);
272+
}
273+
)*
274+
};
275+
}
276+
test_detect_cycle! {
277+
undirected_empty: (UndirectedGraph::new(), false),
278+
directed_empty: (DirectedGraph::new(), false),
279+
undirected_single_node_with_loop: (get_undirected_single_node_with_loop(), true),
280+
directed_single_node_with_loop: (get_directed_single_node_with_loop(), true),
281+
undirected_two_nodes_connected: (get_undirected_two_nodes_connected(), false),
282+
directed_two_nodes_connected: (get_directed_two_nodes_connected(), true),
283+
directed_two_nodes: (get_directed_two_nodes(), false),
284+
undirected_triangle: (get_undirected_triangle(), true),
285+
undirected_triangle_with_tail: (get_undirected_triangle_with_tail(), true),
286+
directed_triangle: (get_directed_triangle(), true),
287+
directed_triangle_with_tail: (get_directed_triangle_with_tail(), true),
288+
undirected_graph_with_cycle: (get_undirected_graph_with_cycle(), true),
289+
undirected_graph_without_cycle: (get_undirected_graph_without_cycle(), false),
290+
directed_graph_with_cycle: (get_directed_graph_with_cycle(), true),
291+
directed_graph_without_cycle: (get_directed_graph_without_cycle(), false),
292+
}
293+
}

0 commit comments

Comments
 (0)