@@ -418,7 +418,7 @@ fn main(wrong_param: u32) -> i32 {
418418 check bool (" should have failed for: " ^ description) false true
419419 ) invalid_programs
420420
421- (* * Test 6 : Map file descriptor generation for userspace *)
421+ (* * Test 7 : Map file descriptor generation for userspace *)
422422let test_map_fd_generation () =
423423 let code = {|
424424pin var shared_counter : hash < u32, u32 > (1024 )
@@ -475,6 +475,315 @@ fn main() -> i32 {
475475 with
476476 | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
477477
478+ (* * Test 8: No map FD declarations when outer condition is false (no map ops, no exec, no pinned maps) *)
479+ let test_map_fd_not_generated_without_usage () =
480+ (* Map used only in eBPF program (not in main), no pinned maps, no exec *)
481+ let code = {|
482+ var ebpf_side_only : hash < u32, u64 > (1024 )
483+
484+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
485+ ebpf_side_only[1 ] = 100
486+ return XDP_PASS
487+ }
488+
489+ fn main () -> i32 {
490+ return 0
491+ }
492+ |} in
493+ try
494+ let ast = parse_string_with_builtins code in
495+ match get_generated_userspace_code ast " test_no_fd.ks" with
496+ | Some generated_content ->
497+ (* uses_map_operations=false, uses_exec=false, has_pinned_maps=false
498+ → map_fd_declarations = "" → no "int ebpf_side_only_fd = -1" *)
499+ let has_fd_decl = contains_pattern generated_content " int ebpf_side_only_fd" in
500+ check bool " no fd declaration when no userspace map usage" false has_fd_decl
501+ | None ->
502+ fail " Failed to generate userspace code"
503+ with
504+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
505+
506+ (* * Test 9: Only userspace-used maps get FD declarations when no pinned maps *)
507+ let test_map_fd_only_for_userspace_used_maps () =
508+ (* used_map is referenced in main; ebpf_only_map is referenced only in @xdp fn *)
509+ let code = {|
510+ var used_map : hash < u32, u64 > (1024 )
511+ var ebpf_only_map : hash < u32, u64 > (1024 )
512+
513+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
514+ ebpf_only_map[1 ] = 100
515+ return XDP_PASS
516+ }
517+
518+ fn main () -> i32 {
519+ used_map[1 ] = 42
520+ return 0
521+ }
522+ |} in
523+ try
524+ let ast = parse_string_with_builtins code in
525+ match get_generated_userspace_code ast " test_used_maps_fd.ks" with
526+ | Some generated_content ->
527+ (* uses_map_operations=true, has_pinned_maps=false
528+ → maps_for_fd = used_global_maps_with_exec = [used_map] (not ebpf_only_map) *)
529+ let has_used_map_fd = contains_pattern generated_content " int used_map_fd" in
530+ let has_ebpf_only_fd = contains_pattern generated_content " int ebpf_only_map_fd" in
531+ check bool " used map gets fd declaration" true has_used_map_fd;
532+ check bool " ebpf-only map does NOT get fd declaration" false has_ebpf_only_fd
533+ | None ->
534+ fail " Failed to generate userspace code"
535+ with
536+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
537+
538+ (* * Test 10: Pinned maps cause all global maps (including eBPF-only ones) to get FD declarations *)
539+ let test_map_fd_pinned_includes_all_global_maps () =
540+ (* pinned_map is pinned and used in main; other_map is non-pinned and used only in @xdp fn *)
541+ let code = {|
542+ pin var pinned_map : hash < u32, u64 > (1024 )
543+ var other_map : hash < u32, u64 > (512 )
544+
545+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
546+ other_map[1 ] = 100
547+ return XDP_PASS
548+ }
549+
550+ fn main () -> i32 {
551+ pinned_map[1 ] = 10
552+ return 0
553+ }
554+ |} in
555+ try
556+ let ast = parse_string_with_builtins code in
557+ match get_generated_userspace_code ast " test_pinned_fd.ks" with
558+ | Some generated_content ->
559+ (* has_pinned_maps=true → outer condition true, maps_for_fd = global_maps
560+ → BOTH pinned_map and other_map get int ..._fd = -1 declarations *)
561+ let has_pinned_map_fd = contains_pattern generated_content " int pinned_map_fd" in
562+ let has_other_map_fd = contains_pattern generated_content " int other_map_fd" in
563+ check bool " pinned map gets fd declaration" true has_pinned_map_fd;
564+ check bool " non-pinned ebpf-only map ALSO gets fd declaration (global_maps used)" true has_other_map_fd
565+ | None ->
566+ fail " Failed to generate userspace code"
567+ with
568+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
569+
570+ (* * Test 11: Map setup code not generated when no userspace map usage, no exec, no pinned maps *)
571+ let test_map_setup_not_generated_without_usage () =
572+ (* Map used only in eBPF program, no map access in main, no pinned maps, no exec *)
573+ let code = {|
574+ var ebpf_only : hash < u32, u64 > (1024 )
575+
576+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
577+ ebpf_only[1 ] = 100
578+ return XDP_PASS
579+ }
580+
581+ fn main () -> i32 {
582+ return 0
583+ }
584+ |} in
585+ try
586+ let ast = parse_string_with_builtins code in
587+ match get_generated_userspace_code ast " test_no_setup.ks" with
588+ | Some generated_content ->
589+ (* map_setup_code="" → all_setup_code="" → no bpf_object__find_map_by_name anywhere *)
590+ let has_find_map = contains_pattern generated_content " bpf_object__find_map_by_name" in
591+ check bool " no bpf_object__find_map_by_name when no userspace map usage" false has_find_map
592+ | None ->
593+ fail " Failed to generate userspace code"
594+ with
595+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
596+
597+ (* * Test 12: Map setup code uses only userspace-used maps when no pinned maps *)
598+ let test_map_setup_only_for_used_maps () =
599+ (* var count triggers skeleton loading (has_global_vars=true → needs_object_loading=true).
600+ used_map is referenced in main; ebpf_only_map is referenced only in @xdp fn. *)
601+ let code = {|
602+ var count : u64 = 0
603+ var used_map : hash < u32, u64 > (1024 )
604+ var ebpf_only_map : hash < u32, u64 > (1024 )
605+
606+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
607+ ebpf_only_map[1 ] = 100
608+ return XDP_PASS
609+ }
610+
611+ fn main () -> i32 {
612+ used_map[1 ] = 42
613+ return 0
614+ }
615+ |} in
616+ try
617+ let ast = parse_string_with_builtins code in
618+ match get_generated_userspace_code ast " test_setup_used_maps.ks" with
619+ | Some generated_content ->
620+ (* has_pinned_maps=false, uses_map_operations=true
621+ → maps_for_setup = used_global_maps_with_exec = [used_map]
622+ setup_call injects all_setup_code; only used_map gets find_map_by_name *)
623+ let has_used_map_setup = contains_pattern generated_content " find_map_by_name.*used_map" in
624+ let has_ebpf_only_setup = contains_pattern generated_content " find_map_by_name.*ebpf_only_map" in
625+ check bool " used_map has setup code (find_map_by_name)" true has_used_map_setup;
626+ check bool " ebpf_only_map does NOT get setup code" false has_ebpf_only_setup
627+ | None ->
628+ fail " Failed to generate userspace code"
629+ with
630+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
631+
632+ (* * Test 13: Map setup code includes all global maps when pinned maps exist *)
633+ let test_map_setup_pinned_includes_all_global_maps () =
634+ (* var count triggers skeleton loading.
635+ pinned_map is pinned. other_map is non-pinned and eBPF-only (not accessed in main).
636+ Because has_pinned_maps=true, maps_for_setup = global_maps = [pinned_map, other_map]. *)
637+ let code = {|
638+ var count : u64 = 0
639+ pin var pinned_map : hash < u32, u64 > (1024 )
640+ var other_map : hash < u32, u64 > (512 )
641+
642+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
643+ other_map[1 ] = 100
644+ return XDP_PASS
645+ }
646+
647+ fn main () -> i32 {
648+ return 0
649+ }
650+ |} in
651+ try
652+ let ast = parse_string_with_builtins code in
653+ match get_generated_userspace_code ast " test_setup_pinned.ks" with
654+ | Some generated_content ->
655+ (* has_pinned_maps=true → maps_for_setup = global_maps = [pinned_map, other_map]
656+ setup_call is triggered by has_pinned_maps; all_setup_code includes setup for BOTH maps *)
657+ let has_pinned_map_setup = contains_pattern generated_content " find_map_by_name.*pinned_map" in
658+ let has_other_map_setup = contains_pattern generated_content " find_map_by_name.*other_map" in
659+ check bool " pinned_map gets setup code (find_map_by_name)" true has_pinned_map_setup;
660+ check bool " eBPF-only other_map ALSO gets setup code (global_maps used)" true has_other_map_setup
661+ | None ->
662+ fail " Failed to generate userspace code"
663+ with
664+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
665+
666+ (* * Test 14: Directory creation helper (ensure_bpf_dir) generated when pinned maps exist *)
667+ let test_mkdir_helper_generated_with_pinned_maps () =
668+ let code = {|
669+ pin var my_map : hash < u32, u64 > (1024 )
670+
671+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
672+ return XDP_PASS
673+ }
674+
675+ fn main () -> i32 {
676+ my_map[1 ] = 99
677+ return 0
678+ }
679+ |} in
680+ try
681+ let ast = parse_string_with_builtins code in
682+ match get_generated_userspace_code ast " test_mkdir_pinned.ks" with
683+ | Some generated_content ->
684+ (* has_pinned_maps=true → mkdir_helper_function is the ensure_bpf_dir function *)
685+ let has_ensure_bpf_dir = contains_pattern generated_content " ensure_bpf_dir" in
686+ check bool " ensure_bpf_dir present when pinned maps exist" true has_ensure_bpf_dir
687+ | None ->
688+ fail " Failed to generate userspace code"
689+ with
690+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
691+
692+ (* * Test 15: Directory creation helper (ensure_bpf_dir) not generated without pinned maps *)
693+ let test_mkdir_helper_not_generated_without_pinned_maps () =
694+ let code = {|
695+ var regular_map : hash < u32, u64 > (1024 )
696+
697+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
698+ return XDP_PASS
699+ }
700+
701+ fn main () -> i32 {
702+ regular_map[1 ] = 42
703+ return 0
704+ }
705+ |} in
706+ try
707+ let ast = parse_string_with_builtins code in
708+ match get_generated_userspace_code ast " test_mkdir_no_pinned.ks" with
709+ | Some generated_content ->
710+ (* has_pinned_maps=false → mkdir_helper_function = "" *)
711+ let has_ensure_bpf_dir = contains_pattern generated_content " ensure_bpf_dir" in
712+ check bool " ensure_bpf_dir absent when no pinned maps" false has_ensure_bpf_dir
713+ | None ->
714+ fail " Failed to generate userspace code"
715+ with
716+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
717+
718+ (* * Test 16: Pinned map setup emits bpf_obj_get / ensure_bpf_dir / bpf_map__pin logic *)
719+ let test_pin_logic_pinned_map_setup () =
720+ let code = {|
721+ var count : u64 = 0
722+ pin var pinned_counter : hash < u32, u64 > (1024 )
723+
724+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
725+ return XDP_PASS
726+ }
727+
728+ fn main () -> i32 {
729+ return 0
730+ }
731+ |} in
732+ try
733+ let ast = parse_string_with_builtins code in
734+ match get_generated_userspace_code ast " test_pin_logic.ks" with
735+ | Some generated_content ->
736+ (* Some pin_path branch: generates bpf_obj_get to check existing pin *)
737+ let has_bpf_obj_get = contains_pattern generated_content " bpf_obj_get" in
738+ (* ... _existing_fd variable for the pinned map *)
739+ let has_existing_fd = contains_pattern generated_content " pinned_counter_existing_fd" in
740+ (* ... ensure_bpf_dir to create directory before pinning *)
741+ let has_ensure_bpf_dir = contains_pattern generated_content " ensure_bpf_dir" in
742+ (* ... bpf_map__pin to pin the map object *)
743+ let has_bpf_map_pin = contains_pattern generated_content " bpf_map__pin.*pinned_counter" in
744+ check bool " bpf_obj_get present for pinned map" true has_bpf_obj_get;
745+ check bool " _existing_fd variable present for pinned map" true has_existing_fd;
746+ check bool " ensure_bpf_dir called before pinning" true has_ensure_bpf_dir;
747+ check bool " bpf_map__pin called to pin the map" true has_bpf_map_pin
748+ | None ->
749+ fail " Failed to generate userspace code"
750+ with
751+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
752+
753+ (* * Test 17: Non-pinned map setup uses plain bpf_map__fd only *)
754+ let test_pin_logic_non_pinned_map_setup () =
755+ let code = {|
756+ var count : u64 = 0
757+ var regular_map : hash < u32, u64 > (1024 )
758+
759+ @ xdp fn test (ctx : * xdp_md) -> xdp_action {
760+ return XDP_PASS
761+ }
762+
763+ fn main () -> i32 {
764+ regular_map[1 ] = 42
765+ return 0
766+ }
767+ |} in
768+ try
769+ let ast = parse_string_with_builtins code in
770+ match get_generated_userspace_code ast " test_no_pin_logic.ks" with
771+ | Some generated_content ->
772+ (* None branch: plain fd fetch *)
773+ let has_bpf_map_fd = contains_pattern generated_content " bpf_map__fd.*regular_map" in
774+ (* None branch: no pinning machinery *)
775+ let has_bpf_obj_get = contains_pattern generated_content " bpf_obj_get" in
776+ let has_existing_fd = contains_pattern generated_content " regular_map_existing_fd" in
777+ let has_bpf_map_pin = contains_pattern generated_content " bpf_map__pin.*regular_map" in
778+ check bool " bpf_map__fd used for non-pinned map" true has_bpf_map_fd;
779+ check bool " bpf_obj_get NOT present for non-pinned map" false has_bpf_obj_get;
780+ check bool " _existing_fd NOT present for non-pinned map" false has_existing_fd;
781+ check bool " bpf_map__pin NOT called for non-pinned map" false has_bpf_map_pin
782+ | None ->
783+ fail " Failed to generate userspace code"
784+ with
785+ | exn -> fail (" Error occurred: " ^ Printexc. to_string exn )
786+
478787let global_function_maps_tests = [
479788 " global_map_accessibility" , `Quick , test_global_map_accessibility;
480789 " global_only_map_access" , `Quick , test_global_only_map_access;
@@ -483,6 +792,16 @@ let global_function_maps_tests = [
483792 " global_function_code_structure" , `Quick , test_global_function_code_structure;
484793 " global_function_error_handling" , `Quick , test_global_function_error_handling;
485794 " map_fd_generation" , `Quick , test_map_fd_generation;
795+ " map_fd_not_generated_without_usage" , `Quick , test_map_fd_not_generated_without_usage;
796+ " map_fd_only_for_userspace_used_maps" , `Quick , test_map_fd_only_for_userspace_used_maps;
797+ " map_fd_pinned_includes_all_global_maps" , `Quick , test_map_fd_pinned_includes_all_global_maps;
798+ " mkdir_helper_generated_with_pinned_maps" , `Quick , test_mkdir_helper_generated_with_pinned_maps;
799+ " mkdir_helper_not_generated_without_pinned_maps" , `Quick , test_mkdir_helper_not_generated_without_pinned_maps;
800+ " map_setup_not_generated_without_usage" , `Quick , test_map_setup_not_generated_without_usage;
801+ " map_setup_only_for_used_maps" , `Quick , test_map_setup_only_for_used_maps;
802+ " map_setup_pinned_includes_all_global_maps" , `Quick , test_map_setup_pinned_includes_all_global_maps;
803+ " pin_logic_pinned_map_setup" , `Quick , test_pin_logic_pinned_map_setup;
804+ " pin_logic_non_pinned_map_setup" , `Quick , test_pin_logic_non_pinned_map_setup;
486805]
487806
488807let () =
0 commit comments