@@ -367,8 +367,8 @@ test_path_sep(void) {
367367}
368368
369369static int
370- test_create_temp_ini ( char * out_path , size_t out_path_size ) {
371- if (!out_path || out_path_size == 0 ) {
370+ test_create_temp_ini_with_contents ( const char * contents , char * out_path , size_t out_path_size ) {
371+ if (!contents || ! out_path || out_path_size == 0 ) {
372372 return -1 ;
373373 }
374374
@@ -405,21 +405,28 @@ test_create_temp_ini(char* out_path, size_t out_path_size) {
405405 return -1 ;
406406 }
407407
408- fputs ("version = 1\n"
409- "\n"
410- "[input]\n"
411- "source = \"rtl\"\n"
412- "rtl_device = 0\n"
413- "rtl_freq = \"100000000\"\n"
414- "\n"
415- "[trunking]\n"
416- "enabled = true\n" ,
417- fp );
418-
408+ fputs (contents , fp );
419409 fclose (fp );
420410 return 0 ;
421411}
422412
413+ static int
414+ test_create_temp_ini (char * out_path , size_t out_path_size ) {
415+ if (!out_path || out_path_size == 0 ) {
416+ return -1 ;
417+ }
418+ return test_create_temp_ini_with_contents ("version = 1\n"
419+ "\n"
420+ "[input]\n"
421+ "source = \"rtl\"\n"
422+ "rtl_device = 0\n"
423+ "rtl_freq = \"100000000\"\n"
424+ "\n"
425+ "[trunking]\n"
426+ "enabled = true\n" ,
427+ out_path , out_path_size );
428+ }
429+
423430static int
424431test_create_temp_vertex_ks_csv (char * out_path , size_t out_path_size , int malformed ) {
425432 if (!out_path || out_path_size == 0 ) {
@@ -617,6 +624,159 @@ test_bootstrap_print_config_normalizes_soapy_shorthand(void) {
617624 return test_rc ;
618625}
619626
627+ static int
628+ test_bootstrap_profile_preserves_trunking_with_ncurses_cli (void ) {
629+ dsd_opts * opts = (dsd_opts * )calloc (1 , sizeof (dsd_opts ));
630+ dsd_state * state = (dsd_state * )calloc (1 , sizeof (dsd_state ));
631+ if (!opts || !state ) {
632+ free (opts );
633+ free (state );
634+ fprintf (stderr , "out of memory\n" );
635+ return 1 ;
636+ }
637+
638+ initOpts (opts );
639+ initState (state );
640+
641+ (void )dsd_unsetenv ("DSD_NEO_CONFIG" );
642+ (void )dsd_setenv ("DSD_NEO_NO_BOOTSTRAP" , "1" , 1 );
643+
644+ static const char * ini = "version = 1\n"
645+ "\n"
646+ "[input]\n"
647+ "source = \"pulse\"\n"
648+ "\n"
649+ "[profile.p25_trunk]\n"
650+ "input.source = \"rtl\"\n"
651+ "input.rtl_device = 0\n"
652+ "input.rtl_freq = \"100000000\"\n"
653+ "trunking.enabled = true\n" ;
654+
655+ char cfg_path [1024 ];
656+ if (test_create_temp_ini_with_contents (ini , cfg_path , sizeof cfg_path ) != 0 ) {
657+ fprintf (stderr , "failed to create temp profile ini\n" );
658+ freeState (state );
659+ free (opts );
660+ free (state );
661+ return 1 ;
662+ }
663+
664+ char arg0 [] = "dsd-neo" ;
665+ char arg1 [] = "--config" ;
666+ char arg2 [1024 ];
667+ char arg3 [] = "--profile" ;
668+ char arg4 [] = "p25_trunk" ;
669+ char arg5 [] = "-N" ;
670+ snprintf (arg2 , sizeof arg2 , "%s" , cfg_path );
671+ char * argv [] = {arg0 , arg1 , arg2 , arg3 , arg4 , arg5 , NULL };
672+
673+ int argc_effective = 0 ;
674+ int exit_rc = -1 ;
675+ int rc = dsd_runtime_bootstrap (6 , argv , opts , state , & argc_effective , & exit_rc );
676+ if (rc != DSD_BOOTSTRAP_CONTINUE ) {
677+ fprintf (stderr , "expected rc=%d, got %d (exit_rc=%d)\n" , DSD_BOOTSTRAP_CONTINUE , rc , exit_rc );
678+ (void )remove (cfg_path );
679+ freeState (state );
680+ free (opts );
681+ free (state );
682+ return 1 ;
683+ }
684+
685+ int test_rc = 0 ;
686+ if (opts -> trunk_enable != 1 || opts -> p25_trunk != 1 ) {
687+ fprintf (stderr , "expected profiled trunking to stay enabled, got trunk_enable=%d p25_trunk=%d\n" ,
688+ opts -> trunk_enable , opts -> p25_trunk );
689+ test_rc = 1 ;
690+ }
691+ if (opts -> use_ncurses_terminal != 1 ) {
692+ fprintf (stderr , "expected -N to remain applied, got use_ncurses_terminal=%d\n" , opts -> use_ncurses_terminal );
693+ test_rc = 1 ;
694+ }
695+ if (strncmp (opts -> audio_in_dev , "rtl:" , 4 ) != 0 ) {
696+ fprintf (stderr , "expected profile RTL input, got audio_in_dev=%s\n" , opts -> audio_in_dev );
697+ test_rc = 1 ;
698+ }
699+
700+ (void )remove (cfg_path );
701+ freeState (state );
702+ free (opts );
703+ free (state );
704+ return test_rc ;
705+ }
706+
707+ static int
708+ test_bootstrap_profile_disables_autosave (void ) {
709+ dsd_opts * opts = (dsd_opts * )calloc (1 , sizeof (dsd_opts ));
710+ dsd_state * state = (dsd_state * )calloc (1 , sizeof (dsd_state ));
711+ if (!opts || !state ) {
712+ free (opts );
713+ free (state );
714+ fprintf (stderr , "out of memory\n" );
715+ return 1 ;
716+ }
717+
718+ initOpts (opts );
719+ initState (state );
720+
721+ (void )dsd_unsetenv ("DSD_NEO_CONFIG" );
722+ (void )dsd_setenv ("DSD_NEO_NO_BOOTSTRAP" , "1" , 1 );
723+
724+ static const char * ini = "version = 1\n"
725+ "\n"
726+ "[profile.p25_trunk]\n"
727+ "input.source = \"rtl\"\n"
728+ "input.rtl_device = 0\n"
729+ "input.rtl_freq = \"100000000\"\n"
730+ "trunking.enabled = true\n" ;
731+
732+ char cfg_path [1024 ];
733+ if (test_create_temp_ini_with_contents (ini , cfg_path , sizeof cfg_path ) != 0 ) {
734+ fprintf (stderr , "failed to create temp profile ini\n" );
735+ freeState (state );
736+ free (opts );
737+ free (state );
738+ return 1 ;
739+ }
740+
741+ char arg0 [] = "dsd-neo" ;
742+ char arg1 [] = "--config" ;
743+ char arg2 [1024 ];
744+ char arg3 [] = "--profile" ;
745+ char arg4 [] = "p25_trunk" ;
746+ snprintf (arg2 , sizeof arg2 , "%s" , cfg_path );
747+ char * argv [] = {arg0 , arg1 , arg2 , arg3 , arg4 , NULL };
748+
749+ int argc_effective = 0 ;
750+ int exit_rc = -1 ;
751+ int rc = dsd_runtime_bootstrap (5 , argv , opts , state , & argc_effective , & exit_rc );
752+ if (rc != DSD_BOOTSTRAP_CONTINUE ) {
753+ fprintf (stderr , "expected rc=%d, got %d (exit_rc=%d)\n" , DSD_BOOTSTRAP_CONTINUE , rc , exit_rc );
754+ (void )remove (cfg_path );
755+ freeState (state );
756+ free (opts );
757+ free (state );
758+ return 1 ;
759+ }
760+
761+ int test_rc = 0 ;
762+ if (state -> config_autosave_enabled != 0 ) {
763+ fprintf (stderr , "expected autosave disabled for profiled config, got enabled=%d\n" ,
764+ state -> config_autosave_enabled );
765+ test_rc = 1 ;
766+ }
767+ if (strcmp (state -> config_autosave_path , cfg_path ) != 0 ) {
768+ fprintf (stderr , "expected profiled config path retained as %s, got %s\n" , cfg_path ,
769+ state -> config_autosave_path );
770+ test_rc = 1 ;
771+ }
772+
773+ (void )remove (cfg_path );
774+ freeState (state );
775+ free (opts );
776+ free (state );
777+ return test_rc ;
778+ }
779+
620780static int
621781test_r_playback_optind_is_first_file_regardless_of_option_order (void ) {
622782 int test_rc = 0 ;
@@ -1549,6 +1709,8 @@ main(void) {
15491709 rc |= test_1_loads_rc4_key_allows_0x_prefix ();
15501710 rc |= test_bootstrap_treats_lone_ini_as_config ();
15511711 rc |= test_bootstrap_print_config_normalizes_soapy_shorthand ();
1712+ rc |= test_bootstrap_profile_preserves_trunking_with_ncurses_cli ();
1713+ rc |= test_bootstrap_profile_disables_autosave ();
15521714 rc |= test_r_playback_optind_is_first_file_regardless_of_option_order ();
15531715 rc |= test_open_mbe_missing_file_leaves_stream_null ();
15541716 rc |= test_rdio_long_options_parse ();
0 commit comments