#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::super::super::*;
fn create_cycle_graph() -> DependencyGraph {
let mut graph = DependencyGraph::new();
let n0 = graph.add_node(NodeData::test_node(0));
let n1 = graph.add_node(NodeData::test_node(1));
let n2 = graph.add_node(NodeData::test_node(2));
graph.add_edge(n0, n1, EdgeData::test_edge(1.0));
graph.add_edge(n1, n2, EdgeData::test_edge(1.0));
graph.add_edge(n2, n0, EdgeData::test_edge(1.0));
graph
}
fn create_star_graph() -> DependencyGraph {
let mut graph = DependencyGraph::new();
let hub = graph.add_node(NodeData::test_node(0));
for i in 1..5 {
let spoke = graph.add_node(NodeData::test_node(i));
graph.add_edge(hub, spoke, EdgeData::test_edge(1.0));
graph.add_edge(spoke, hub, EdgeData::test_edge(1.0));
}
graph
}
#[test]
fn test_pagerank_sum_preservation() {
let graph = create_cycle_graph();
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
let sum: f64 = ranks.iter().sum();
assert!(
(sum - 1.0).abs() < 1e-6,
"PageRank sum = {}, expected 1.0",
sum
);
}
#[test]
fn test_pagerank_convergence() {
let graph = create_star_graph();
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer {
tolerance: 1e-8, max_iterations: 1000,
..Default::default()
};
let ranks = pr.compute(&matrices);
let ranks2 = pr.compute(&matrices);
for i in 0..ranks.len() {
assert!(
(ranks[i] - ranks2[i]).abs() < 1e-7,
"PageRank not converged at node {}",
i
);
}
}
#[test]
fn test_pagerank_star_graph() {
let graph = create_star_graph();
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
for i in 1..ranks.len() {
assert!(
ranks[0] > ranks[i],
"Hub PageRank {} should be > spoke PageRank {}",
ranks[0],
ranks[i]
);
}
for i in 2..ranks.len() {
assert!(
(ranks[1] - ranks[i]).abs() < 1e-9,
"Spoke PageRanks should be equal: {} vs {}",
ranks[1],
ranks[i]
);
}
}
#[test]
fn test_pagerank_complete_graph() {
let mut graph = DiGraph::new();
let nodes: Vec<_> = (0..4)
.map(|i| graph.add_node(NodeData::test_node(i)))
.collect();
for i in 0..nodes.len() {
for j in 0..nodes.len() {
if i != j {
graph.add_edge(nodes[i], nodes[j], EdgeData::test_edge(1.0));
}
}
}
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
let expected = 1.0 / ranks.len() as f64;
for rank in ranks {
assert!(
(rank - expected).abs() < 1e-6,
"Expected {}, got {}",
expected,
rank
);
}
}
#[test]
fn test_pagerank_dangling_nodes() {
let mut graph = DiGraph::new();
let n0 = graph.add_node(NodeData::test_node(0));
let n1 = graph.add_node(NodeData::test_node(1));
let n2 = graph.add_node(NodeData::test_node(2));
graph.add_edge(n0, n1, EdgeData::test_edge(1.0));
graph.add_edge(n1, n2, EdgeData::test_edge(1.0));
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
let sum: f64 = ranks.iter().sum();
assert!((sum - 1.0).abs() < 1e-6);
for rank in &ranks {
assert!(!rank.is_nan(), "PageRank should not contain NaN");
assert!(*rank >= 0.0, "PageRank should be non-negative");
}
}
#[test]
fn test_pagerank_damping_factor() {
let graph = create_star_graph();
let matrices = GraphMatrices::from(&graph);
let pr_low = PageRankComputer::new().with_damping(0.5);
let ranks_low = pr_low.compute(&matrices);
let pr_high = PageRankComputer::new().with_damping(0.95);
let ranks_high = pr_high.compute(&matrices);
let hub_diff = (ranks_low[0] - ranks_high[0]).abs();
assert!(
hub_diff > 1e-4,
"Damping factor should affect hub PageRank: diff={}",
hub_diff
);
assert!((ranks_low.iter().sum::<f64>() - 1.0).abs() < 1e-6);
assert!((ranks_high.iter().sum::<f64>() - 1.0).abs() < 1e-6);
}
#[test]
fn test_pagerank_empty_graph() {
let graph = DiGraph::new();
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
assert_eq!(ranks.len(), 0);
}
#[test]
fn test_pagerank_single_node() {
let mut graph = DiGraph::new();
graph.add_node(NodeData::test_node(0));
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
assert_eq!(ranks.len(), 1);
assert!((ranks[0] - 1.0).abs() < 1e-9);
}
#[test]
fn test_pagerank_weighted_edges() {
let mut graph = DiGraph::new();
let n0 = graph.add_node(NodeData::test_node(0));
let n1 = graph.add_node(NodeData::test_node(1));
let n2 = graph.add_node(NodeData::test_node(2));
graph.add_edge(
n0,
n1,
EdgeData::Import {
weight: 5.0,
visibility: Visibility::Public,
},
);
graph.add_edge(
n0,
n2,
EdgeData::Import {
weight: 0.5,
visibility: Visibility::Public,
},
);
graph.add_edge(n1, n0, EdgeData::test_edge(1.0));
graph.add_edge(n2, n0, EdgeData::test_edge(1.0));
let matrices = GraphMatrices::from(&graph);
let pr = PageRankComputer::default();
let ranks = pr.compute(&matrices);
assert!(
ranks[1] > ranks[2],
"Node with stronger incoming edge should have higher PageRank"
);
}
}