Skip to content

Commit e44a006

Browse files
committed
test: add comprehensive test coverage for improved shortest path algorithms
- Add tests for Zero trait implementations - Add tests for VertexDistance ordering behavior - Add edge case tests for empty graphs and disconnected vertices - Add tests for bucket algorithm with weight limits - Add tests for adaptive algorithm threshold behavior - Add tests for priority queue behavior and visited vertex skipping - Add tests for different numeric types (u32, i64) - Add tests for bucket algorithm with empty buckets - Increase test coverage from 90.31% to target coverage
1 parent 2d4e506 commit e44a006

File tree

1 file changed

+225
-2
lines changed

1 file changed

+225
-2
lines changed

src/graph/improved_shortest_path.rs

Lines changed: 225 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,230 @@ mod tests {
494494
assert_eq!(bucket_result, improved_result);
495495

496496
// Bucket approach should be faster for small integer weights
497-
println!("Bucket duration: {:?}", bucket_duration);
498-
println!("Improved duration: {:?}", improved_duration);
497+
println!("Bucket duration: {bucket_duration:?}");
498+
println!("Improved duration: {improved_duration:?}");
499+
}
500+
501+
#[test]
502+
fn test_zero_trait_implementations() {
503+
use super::Zero;
504+
// Test all Zero trait implementations
505+
assert_eq!(usize::zero(), 0);
506+
assert_eq!(isize::zero(), 0);
507+
assert_eq!(u32::zero(), 0);
508+
assert_eq!(i32::zero(), 0);
509+
assert_eq!(u64::zero(), 0);
510+
assert_eq!(i64::zero(), 0);
511+
assert_eq!(f32::zero(), 0.0);
512+
assert_eq!(f64::zero(), 0.0);
513+
}
514+
515+
#[test]
516+
fn test_vertex_distance_ordering() {
517+
use super::VertexDistance;
518+
519+
// Test ordering behavior for min-heap (reverse ordering)
520+
let vd1 = VertexDistance {
521+
vertex: 1,
522+
distance: 5,
523+
};
524+
let vd2 = VertexDistance {
525+
vertex: 2,
526+
distance: 3,
527+
};
528+
529+
// vd2 should be "greater" (comes first in min-heap) due to smaller distance
530+
assert!(vd2 > vd1);
531+
532+
// Test equality
533+
let vd3 = VertexDistance {
534+
vertex: 1,
535+
distance: 5,
536+
};
537+
assert_eq!(vd1.cmp(&vd3), std::cmp::Ordering::Equal);
538+
539+
// Test same distance, different vertices
540+
let vd4 = VertexDistance {
541+
vertex: 3,
542+
distance: 5,
543+
};
544+
assert_ne!(vd1.cmp(&vd4), std::cmp::Ordering::Equal);
545+
}
546+
547+
#[test]
548+
fn test_improved_shortest_path_edge_cases() {
549+
// Test empty graph
550+
let empty_graph: Graph<i32, i32> = BTreeMap::new();
551+
let result = improved_shortest_path(&empty_graph, 0);
552+
assert_eq!(result.len(), 1);
553+
assert_eq!(result[&0], None);
554+
555+
// Test graph with only one vertex and no edges
556+
let mut single_vertex: Graph<i32, i32> = BTreeMap::new();
557+
single_vertex.insert(0, BTreeMap::new());
558+
let result = improved_shortest_path(&single_vertex, 0);
559+
assert_eq!(result.len(), 1);
560+
assert_eq!(result[&0], None);
561+
562+
// Test disconnected vertices
563+
let mut disconnected: Graph<i32, i32> = BTreeMap::new();
564+
disconnected.insert(0, BTreeMap::new());
565+
disconnected.insert(1, BTreeMap::new());
566+
disconnected.insert(2, BTreeMap::new());
567+
let result = improved_shortest_path(&disconnected, 0);
568+
assert_eq!(result.len(), 1);
569+
assert_eq!(result[&0], None);
570+
}
571+
572+
#[test]
573+
fn test_bucket_shortest_path_edge_cases() {
574+
// Test with max_weight = 0
575+
let mut graph = BTreeMap::new();
576+
add_edge(&mut graph, 0, 1, 0);
577+
578+
let result = bucket_shortest_path(&graph, 0, 0);
579+
assert_eq!(result[&0], None);
580+
assert_eq!(result[&1], Some((0, 0)));
581+
582+
// Test with weights exceeding max_weight
583+
let mut graph = BTreeMap::new();
584+
add_edge(&mut graph, 0, 1, 5);
585+
add_edge(&mut graph, 1, 2, 3);
586+
587+
let result = bucket_shortest_path(&graph, 0, 3);
588+
// Should still work but may not find optimal path for vertex 2
589+
assert_eq!(result[&0], None);
590+
assert_eq!(result[&1], Some((0, 5)));
591+
}
592+
593+
#[test]
594+
fn test_adaptive_shortest_path_edge_cases() {
595+
// Test with empty graph
596+
let empty_graph: Graph<i32, usize> = BTreeMap::new();
597+
let result = adaptive_shortest_path(&empty_graph, 0, 10);
598+
assert_eq!(result.len(), 1);
599+
assert_eq!(result[&0], None);
600+
601+
// Test threshold behavior - should choose bucket for small weights
602+
let mut small_weights = BTreeMap::new();
603+
add_edge(&mut small_weights, 0, 1, 2);
604+
add_edge(&mut small_weights, 1, 2, 1);
605+
606+
let result = adaptive_shortest_path(&small_weights, 0, 5);
607+
assert_eq!(result[&0], None);
608+
assert_eq!(result[&1], Some((0, 2)));
609+
assert_eq!(result[&2], Some((1, 3)));
610+
611+
// Test threshold behavior - should choose improved for large weights
612+
let mut large_weights = BTreeMap::new();
613+
add_edge(&mut large_weights, 0, 1, 10);
614+
add_edge(&mut large_weights, 1, 2, 15);
615+
616+
let result = adaptive_shortest_path(&large_weights, 0, 5);
617+
assert_eq!(result[&0], None);
618+
assert_eq!(result[&1], Some((0, 10)));
619+
assert_eq!(result[&2], Some((1, 25)));
620+
}
621+
622+
#[test]
623+
fn test_priority_queue_behavior() {
624+
// Test that priority queue correctly handles duplicate vertices
625+
let mut graph = BTreeMap::new();
626+
add_edge(&mut graph, 0, 1, 5);
627+
add_edge(&mut graph, 0, 2, 3);
628+
add_edge(&mut graph, 2, 1, 1); // This creates a shorter path to 1
629+
630+
let result = improved_shortest_path(&graph, 0);
631+
632+
// Should find shortest path: 0 -> 2 -> 1 (distance 4)
633+
assert_eq!(result[&0], None);
634+
assert_eq!(result[&2], Some((0, 3)));
635+
assert_eq!(result[&1].unwrap().1, 4); // Distance should be 4, not 5
636+
}
637+
638+
#[test]
639+
fn test_bucket_algorithm_empty_buckets() {
640+
// Test bucket algorithm with gaps in distances
641+
let mut graph = BTreeMap::new();
642+
add_edge(&mut graph, 0, 1, 2);
643+
add_edge(&mut graph, 1, 2, 5); // Creates gap in bucket indices
644+
645+
let result = bucket_shortest_path(&graph, 0, 10);
646+
647+
assert_eq!(result[&0], None);
648+
assert_eq!(result[&1], Some((0, 2)));
649+
assert_eq!(result[&2], Some((1, 7)));
650+
}
651+
652+
#[test]
653+
fn test_visited_vertex_skipping() {
654+
// Test that already visited vertices are properly skipped
655+
let mut graph = BTreeMap::new();
656+
add_edge(&mut graph, 0, 1, 1);
657+
add_edge(&mut graph, 0, 2, 2);
658+
add_edge(&mut graph, 1, 2, 1); // Creates multiple paths to vertex 2
659+
660+
let result = improved_shortest_path(&graph, 0);
661+
662+
// Should find optimal path: 0 -> 1 -> 2 (distance 2)
663+
assert_eq!(result[&0], None);
664+
assert_eq!(result[&1], Some((0, 1)));
665+
assert_eq!(result[&2].unwrap().1, 2);
666+
}
667+
668+
#[test]
669+
fn test_different_numeric_types() {
670+
// Test with different numeric types to ensure trait implementations work
671+
let mut graph_u32: Graph<u32, u32> = BTreeMap::new();
672+
graph_u32.insert(0, BTreeMap::new());
673+
graph_u32.insert(1, BTreeMap::new());
674+
graph_u32.entry(0).or_default().insert(1, 5);
675+
676+
let result_u32 = improved_shortest_path(&graph_u32, 0);
677+
assert_eq!(result_u32[&1], Some((0, 5)));
678+
679+
// Test with i64 (which implements Ord)
680+
let mut graph_i64: Graph<i64, i64> = BTreeMap::new();
681+
graph_i64.insert(0, BTreeMap::new());
682+
graph_i64.insert(1, BTreeMap::new());
683+
graph_i64.entry(0).or_default().insert(1, 314);
684+
685+
let result_i64 = improved_shortest_path(&graph_i64, 0);
686+
assert_eq!(result_i64[&1], Some((0, 314)));
687+
}
688+
689+
#[test]
690+
fn test_visited_vertex_continue_coverage() {
691+
// Test to specifically cover the continue statement when vertex is already visited
692+
// This happens when a vertex appears multiple times in the priority queue
693+
let mut graph = BTreeMap::new();
694+
add_edge(&mut graph, 0, 1, 1);
695+
add_edge(&mut graph, 0, 2, 2);
696+
add_edge(&mut graph, 1, 2, 1);
697+
add_edge(&mut graph, 2, 3, 1);
698+
699+
// This creates a scenario where vertex 2 might be processed multiple times
700+
// due to different paths: 0->2 (weight 2) and 0->1->2 (weight 2)
701+
let result = improved_shortest_path(&graph, 0);
702+
703+
assert_eq!(result[&0], None);
704+
assert_eq!(result[&1], Some((0, 1)));
705+
assert_eq!(result[&2].unwrap().1, 2); // Should find shortest path
706+
assert_eq!(result[&3].unwrap().1, 3); // 0->1->2->3 or 0->2->3
707+
}
708+
709+
#[test]
710+
fn test_bucket_visited_vertex_continue_coverage() {
711+
// Test to cover the continue statement in bucket algorithm
712+
let mut graph = BTreeMap::new();
713+
add_edge(&mut graph, 0, 1, 1);
714+
add_edge(&mut graph, 0, 2, 2);
715+
add_edge(&mut graph, 1, 2, 1);
716+
717+
let result = bucket_shortest_path(&graph, 0, 5);
718+
719+
assert_eq!(result[&0], None);
720+
assert_eq!(result[&1], Some((0, 1)));
721+
assert_eq!(result[&2].unwrap().1, 2);
499722
}
500723
}

0 commit comments

Comments
 (0)