@@ -394,3 +394,224 @@ impl Default for ProcfsPortManager {
394394 Self :: new ( )
395395 }
396396}
397+
398+ #[ cfg( test) ]
399+ mod tests {
400+ use super :: * ;
401+
402+ #[ test]
403+ fn test_procfs_port_manager_creation ( ) {
404+ let manager = ProcfsPortManager :: new ( ) ;
405+ assert ! ( manager. pid_cache. is_empty( ) ) ;
406+ assert_eq ! ( manager. cache_ttl, std:: time:: Duration :: from_secs( 2 ) ) ;
407+ }
408+
409+ #[ test]
410+ fn test_procfs_port_manager_default ( ) {
411+ let manager = ProcfsPortManager :: default ( ) ;
412+ assert ! ( manager. pid_cache. is_empty( ) ) ;
413+ }
414+
415+ #[ test]
416+ fn test_parse_ipv4_address_all_zeros ( ) {
417+ let manager = ProcfsPortManager :: new ( ) ;
418+ let result = manager. parse_ipv4_address ( "00000000" ) ;
419+ assert_eq ! ( result, "*" ) ;
420+ }
421+
422+ #[ test]
423+ fn test_parse_ipv4_address_localhost ( ) {
424+ let manager = ProcfsPortManager :: new ( ) ;
425+ // 127.0.0.1 in little-endian hex: 0100007F
426+ let result = manager. parse_ipv4_address ( "0100007F" ) ;
427+ assert_eq ! ( result, "127.0.0.1" ) ;
428+ }
429+
430+ #[ test]
431+ fn test_parse_ipv4_address_invalid_length ( ) {
432+ let manager = ProcfsPortManager :: new ( ) ;
433+ let result = manager. parse_ipv4_address ( "00" ) ;
434+ assert_eq ! ( result, "*" ) ;
435+ }
436+
437+ #[ test]
438+ fn test_parse_ipv6_address_all_zeros ( ) {
439+ let manager = ProcfsPortManager :: new ( ) ;
440+ let result = manager. parse_ipv6_address ( "00000000000000000000000000000000" ) ;
441+ assert_eq ! ( result, "*" ) ;
442+ }
443+
444+ #[ test]
445+ fn test_parse_ipv6_address_invalid_length ( ) {
446+ let manager = ProcfsPortManager :: new ( ) ;
447+ let result = manager. parse_ipv6_address ( "0000" ) ;
448+ assert_eq ! ( result, "*" ) ;
449+ }
450+
451+ #[ test]
452+ fn test_parse_ipv6_address_localhost ( ) {
453+ let manager = ProcfsPortManager :: new ( ) ;
454+ // ::1 in hex: 00000000000000000000000000000001
455+ let result = manager. parse_ipv6_address ( "00000000000000000000000000000001" ) ;
456+ assert_eq ! ( result, "::1" ) ;
457+ }
458+
459+ #[ test]
460+ fn test_parse_address_ipv4 ( ) {
461+ let manager = ProcfsPortManager :: new ( ) ;
462+ // Format: address:port in hex
463+ // 0.0.0.0:8080 -> 00000000:1F90
464+ let result = manager. parse_address ( "00000000:1F90" , false ) ;
465+ assert ! ( result. is_some( ) ) ;
466+ let ( address, port) = result. unwrap ( ) ;
467+ assert_eq ! ( address, "*" ) ;
468+ assert_eq ! ( port, 8080 ) ;
469+ }
470+
471+ #[ test]
472+ fn test_parse_address_ipv4_localhost_port_3000 ( ) {
473+ let manager = ProcfsPortManager :: new ( ) ;
474+ // 127.0.0.1:3000 -> 0100007F:0BB8
475+ let result = manager. parse_address ( "0100007F:0BB8" , false ) ;
476+ assert ! ( result. is_some( ) ) ;
477+ let ( address, port) = result. unwrap ( ) ;
478+ assert_eq ! ( address, "127.0.0.1" ) ;
479+ assert_eq ! ( port, 3000 ) ;
480+ }
481+
482+ #[ test]
483+ fn test_parse_address_ipv6 ( ) {
484+ let manager = ProcfsPortManager :: new ( ) ;
485+ // [::]:8080 -> 00000000000000000000000000000000:1F90
486+ let result = manager. parse_address ( "00000000000000000000000000000000:1F90" , true ) ;
487+ assert ! ( result. is_some( ) ) ;
488+ let ( address, port) = result. unwrap ( ) ;
489+ assert_eq ! ( address, "*" ) ;
490+ assert_eq ! ( port, 8080 ) ;
491+ }
492+
493+ #[ test]
494+ fn test_parse_address_invalid ( ) {
495+ let manager = ProcfsPortManager :: new ( ) ;
496+ // Missing colon
497+ let result = manager. parse_address ( "00000000" , false ) ;
498+ assert ! ( result. is_none( ) ) ;
499+ }
500+
501+ #[ test]
502+ fn test_parse_tcp_content_empty ( ) {
503+ let manager = ProcfsPortManager :: new ( ) ;
504+ let content = " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n " ;
505+ let result = manager. parse_tcp_content ( content, false ) ;
506+ assert ! ( result. is_ok( ) ) ;
507+ assert ! ( result. unwrap( ) . is_empty( ) ) ;
508+ }
509+
510+ #[ test]
511+ fn test_parse_tcp_content_listening ( ) {
512+ let manager = ProcfsPortManager :: new ( ) ;
513+ let content = " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n 0: 00000000:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 12345 1 0000000000000000 100 0 0 10 0" ;
514+ let result = manager. parse_tcp_content ( content, false ) ;
515+ assert ! ( result. is_ok( ) ) ;
516+ let processes = result. unwrap ( ) ;
517+ assert_eq ! ( processes. len( ) , 1 ) ;
518+ assert_eq ! ( processes[ 0 ] . port, 8080 ) ;
519+ assert_eq ! ( processes[ 0 ] . protocol, "tcp" ) ;
520+ assert_eq ! ( processes[ 0 ] . address, "*" ) ;
521+ assert_eq ! ( processes[ 0 ] . inode, Some ( 12345 ) ) ;
522+ }
523+
524+ #[ test]
525+ fn test_parse_tcp_content_established_skipped ( ) {
526+ let manager = ProcfsPortManager :: new ( ) ;
527+ // State 01 = ESTABLISHED, should be skipped
528+ let content = " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n 0: 00000000:1F90 00000000:0000 01 00000000:00000000 00:00000000 00000000 0 0 12345 1 0000000000000000 100 0 0 10 0" ;
529+ let result = manager. parse_tcp_content ( content, false ) ;
530+ assert ! ( result. is_ok( ) ) ;
531+ assert ! ( result. unwrap( ) . is_empty( ) ) ;
532+ }
533+
534+ #[ test]
535+ fn test_parse_udp_content ( ) {
536+ let manager = ProcfsPortManager :: new ( ) ;
537+ let content = " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops\n 0: 00000000:0035 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 54321 2 0000000000000000 0" ;
538+ let result = manager. parse_udp_content ( content, false ) ;
539+ assert ! ( result. is_ok( ) ) ;
540+ let processes = result. unwrap ( ) ;
541+ assert_eq ! ( processes. len( ) , 1 ) ;
542+ assert_eq ! ( processes[ 0 ] . port, 53 ) ; // DNS port
543+ assert_eq ! ( processes[ 0 ] . protocol, "udp" ) ;
544+ assert_eq ! ( processes[ 0 ] . inode, Some ( 54321 ) ) ;
545+ }
546+
547+ #[ test]
548+ fn test_get_display_path_dev_process ( ) {
549+ let manager = ProcfsPortManager :: new ( ) ;
550+ let process_info = ProcessInfo {
551+ pid : 1234 ,
552+ name : "node" . to_string ( ) ,
553+ command : "node /home/user/project/server.js" . to_string ( ) ,
554+ executable_path : "/usr/bin/node" . to_string ( ) ,
555+ working_directory : "/home/user/project" . to_string ( ) ,
556+ port : 3000 ,
557+ protocol : "tcp" . to_string ( ) ,
558+ address : "*" . to_string ( ) ,
559+ inode : Some ( 12345 ) ,
560+ } ;
561+ let result = manager. get_display_path ( & process_info) ;
562+ assert_eq ! ( result, "/home/user/project" ) ;
563+ }
564+
565+ #[ test]
566+ fn test_get_display_path_system_process ( ) {
567+ let manager = ProcfsPortManager :: new ( ) ;
568+ let process_info = ProcessInfo {
569+ pid : 1234 ,
570+ name : "nginx" . to_string ( ) ,
571+ command : "nginx: master process" . to_string ( ) ,
572+ executable_path : "/usr/sbin/nginx" . to_string ( ) ,
573+ working_directory : "/" . to_string ( ) ,
574+ port : 80 ,
575+ protocol : "tcp" . to_string ( ) ,
576+ address : "*" . to_string ( ) ,
577+ inode : Some ( 12345 ) ,
578+ } ;
579+ let result = manager. get_display_path ( & process_info) ;
580+ assert_eq ! ( result, "/usr/sbin/nginx" ) ;
581+ }
582+
583+ #[ test]
584+ fn test_clear_cache ( ) {
585+ let mut manager = ProcfsPortManager :: new ( ) ;
586+ manager. pid_cache . insert (
587+ 1234 ,
588+ ProcessDetails {
589+ name : "test" . to_string ( ) ,
590+ command : "test" . to_string ( ) ,
591+ executable_path : "/test" . to_string ( ) ,
592+ working_directory : "/" . to_string ( ) ,
593+ } ,
594+ ) ;
595+ assert ! ( !manager. pid_cache. is_empty( ) ) ;
596+
597+ manager. clear_cache ( ) ;
598+ assert ! ( manager. pid_cache. is_empty( ) ) ;
599+ }
600+
601+ #[ test]
602+ fn test_is_listening_connection ( ) {
603+ let manager = ProcfsPortManager :: new ( ) ;
604+ let process_info = ProcessInfo {
605+ pid : 1234 ,
606+ name : "test" . to_string ( ) ,
607+ command : "test" . to_string ( ) ,
608+ executable_path : "/test" . to_string ( ) ,
609+ working_directory : "/" . to_string ( ) ,
610+ port : 3000 ,
611+ protocol : "tcp" . to_string ( ) ,
612+ address : "*" . to_string ( ) ,
613+ inode : Some ( 12345 ) ,
614+ } ;
615+ assert ! ( manager. is_listening_connection( & process_info) ) ;
616+ }
617+ }
0 commit comments