@@ -357,4 +357,123 @@ mod tests {
357357 let ( _, cost) = g. dijkstra ( & "A" , & "C" ) . expect ( "Path should exist" ) ;
358358 assert_eq ! ( cost, 2 ) ; // takes the cheaper A->B edge
359359 }
360+
361+ #[ test]
362+ fn disconnected_graph_dijkstra_returns_none ( ) {
363+ let mut g = Graph :: < & str > :: new ( ) ;
364+ g. add_edge ( "A" , "B" , 1 ) ;
365+ g. add_edge ( "C" , "D" , 1 ) ;
366+ // A and C are in different components
367+ assert ! ( g. dijkstra( & "A" , & "D" ) . is_none( ) ) ;
368+ assert ! ( g. dijkstra( & "C" , & "B" ) . is_none( ) ) ;
369+ }
370+
371+ #[ test]
372+ fn self_loop_dijkstra ( ) {
373+ let mut g = Graph :: < & str > :: new ( ) ;
374+ g. add_edge ( "A" , "A" , 5 ) ;
375+ g. add_edge ( "A" , "B" , 1 ) ;
376+ let ( path, cost) = g. dijkstra ( & "A" , & "B" ) . expect ( "Path should exist" ) ;
377+ assert_eq ! ( path, vec![ "A" , "B" ] ) ;
378+ assert_eq ! ( cost, 1 ) ;
379+ }
380+
381+ #[ test]
382+ fn single_node_graph_dijkstra_self ( ) {
383+ let g = Graph :: < & str > :: new ( ) ;
384+ // No edges at all; start == end => cost 0
385+ let ( path, cost) = g. dijkstra ( & "X" , & "X" ) . expect ( "Self path should exist" ) ;
386+ assert_eq ! ( path, vec![ "X" ] ) ;
387+ assert_eq ! ( cost, 0 ) ;
388+ }
389+
390+ #[ test]
391+ fn single_node_graph_dijkstra_unreachable ( ) {
392+ let g = Graph :: < & str > :: new ( ) ;
393+ assert ! ( g. dijkstra( & "X" , & "Y" ) . is_none( ) ) ;
394+ }
395+
396+ #[ test]
397+ fn astar_nontrivial_heuristic ( ) {
398+ // Grid-like graph where heuristic is Manhattan distance
399+ // Nodes are (row, col) encoded as row*10+col
400+ let mut g = Graph :: < i32 > :: new ( ) ;
401+ // Row 0: 0->1->2
402+ g. add_edge ( 0 , 1 , 1 ) ;
403+ g. add_edge ( 1 , 2 , 1 ) ;
404+ // Row 1: 10->11->12
405+ g. add_edge ( 10 , 11 , 1 ) ;
406+ g. add_edge ( 11 , 12 , 1 ) ;
407+ // Vertical: 0->10, 1->11, 2->12
408+ g. add_edge ( 0 , 10 , 1 ) ;
409+ g. add_edge ( 1 , 11 , 1 ) ;
410+ g. add_edge ( 2 , 12 , 1 ) ;
411+ // Also a long path: 0->10->11->12
412+ // Shortest from 0 to 12: 0->1->2->12 (cost 3) or 0->1->11->12 (cost 3)
413+
414+ let manhattan = |a : & i32 , b : & i32 | -> u64 {
415+ let ( ar, ac) = ( a / 10 , a % 10 ) ;
416+ let ( br, bc) = ( b / 10 , b % 10 ) ;
417+ u64:: from ( ( ar - br) . unsigned_abs ( ) ) + u64:: from ( ( ac - bc) . unsigned_abs ( ) )
418+ } ;
419+
420+ let ( path, cost) = g. astar ( & 0 , & 12 , manhattan) . expect ( "Path should exist" ) ;
421+ assert_eq ! ( cost, 3 ) ;
422+ assert_eq ! ( * path. first( ) . unwrap( ) , 0 ) ;
423+ assert_eq ! ( * path. last( ) . unwrap( ) , 12 ) ;
424+ }
425+
426+ #[ test]
427+ fn astar_unreachable ( ) {
428+ let mut g = Graph :: < u64 > :: new ( ) ;
429+ g. add_edge ( 0 , 1 , 1 ) ;
430+ assert ! ( g. astar( & 0 , & 99 , |a, b| a. abs_diff( * b) ) . is_none( ) ) ;
431+ }
432+
433+ #[ test]
434+ fn bfs_ordering_is_breadth_first ( ) {
435+ // Build a tree:
436+ // A
437+ // / \
438+ // B C
439+ // / \
440+ // D E
441+ let mut g = Graph :: < & str > :: new ( ) ;
442+ g. add_edge ( "A" , "B" , 1 ) ;
443+ g. add_edge ( "A" , "C" , 1 ) ;
444+ g. add_edge ( "B" , "D" , 1 ) ;
445+ g. add_edge ( "B" , "E" , 1 ) ;
446+ let result = g. bfs ( & "A" ) ;
447+ // A must be first
448+ assert_eq ! ( result[ 0 ] , "A" ) ;
449+ // B and C must come before D and E
450+ let pos = |node : & str | result. iter ( ) . position ( |& n| n == node) . unwrap ( ) ;
451+ assert ! ( pos( "B" ) < pos( "D" ) ) ;
452+ assert ! ( pos( "B" ) < pos( "E" ) ) ;
453+ assert ! ( pos( "C" ) < pos( "D" ) ) ;
454+ assert ! ( pos( "C" ) < pos( "E" ) ) ;
455+ }
456+
457+ #[ test]
458+ fn bfs_single_node_no_edges ( ) {
459+ let g = Graph :: < & str > :: new ( ) ;
460+ let result = g. bfs ( & "lonely" ) ;
461+ assert_eq ! ( result, vec![ "lonely" ] ) ;
462+ }
463+
464+ #[ test]
465+ fn default_creates_empty_graph ( ) {
466+ let g = Graph :: < i32 > :: default ( ) ;
467+ assert ! ( g. dijkstra( & 0 , & 1 ) . is_none( ) ) ;
468+ assert_eq ! ( g. bfs( & 0 ) , vec![ 0 ] ) ;
469+ }
470+
471+ #[ test]
472+ fn large_weight_path ( ) {
473+ let mut g = Graph :: < & str > :: new ( ) ;
474+ g. add_edge ( "A" , "B" , u64:: MAX - 1 ) ;
475+ let ( path, cost) = g. dijkstra ( & "A" , & "B" ) . expect ( "Path should exist" ) ;
476+ assert_eq ! ( path, vec![ "A" , "B" ] ) ;
477+ assert_eq ! ( cost, u64 :: MAX - 1 ) ;
478+ }
360479}
0 commit comments