@@ -1859,6 +1859,7 @@ static int test_initconfig_api(void)
18591859 goto error ;
18601860 }
18611861
1862+ // Set an integer option
18621863 if (PyInitConfig_SetInt (config , "hash_seed" , 10 ) < 0 ) {
18631864 goto error ;
18641865 }
@@ -1885,6 +1886,11 @@ static int test_initconfig_api(void)
18851886 goto error ;
18861887 }
18871888
1889+ // Set an optional string to NULL explicitly (must not crash).
1890+ if (PyInitConfig_SetStr (config , "prefix" , NULL ) < 0 ) {
1891+ goto error ;
1892+ }
1893+
18881894 if (Py_InitializeFromInitConfig (config ) < 0 ) {
18891895 goto error ;
18901896 }
@@ -1905,6 +1911,99 @@ static int test_initconfig_api(void)
19051911}
19061912
19071913
1914+ static void
1915+ check_initconfig_error (PyInitConfig * config , const char * expected )
1916+ {
1917+ const char * err_msg ;
1918+ assert (PyInitConfig_GetError (config , & err_msg ) == 1 );
1919+ assert (strcmp (err_msg , expected ) == 0 );
1920+ }
1921+
1922+
1923+ // Test errors of PyInitConfig_Set*() functions
1924+ static int test_initconfig_set_errors (void )
1925+ {
1926+ char * strlist [] = {"value" };
1927+
1928+ PyInitConfig * config = PyInitConfig_Create ();
1929+ if (config == NULL ) {
1930+ printf ("Init allocation error\n" );
1931+ return 1 ;
1932+ }
1933+
1934+ // Unknown option
1935+ assert (PyInitConfig_SetInt (config , "non-existent" , 123 ) < 0 );
1936+ check_initconfig_error (config , "unknown config option name" );
1937+ assert (PyInitConfig_SetStr (config , "non-existent" , "abc" ) < 0 );
1938+ check_initconfig_error (config , "unknown config option name" );
1939+ assert (PyInitConfig_SetStrList (config , "non-existent" ,
1940+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1941+ check_initconfig_error (config , "unknown config option name" );
1942+
1943+
1944+ // Wrong type
1945+ assert (PyInitConfig_SetInt (config , "platlibdir" , 123 ) == -1 );
1946+ check_initconfig_error (config , "config option type is not int" );
1947+
1948+ assert (PyInitConfig_SetStr (config , "cpu_count" , "abc" ) == -1 );
1949+ check_initconfig_error (config , "config option type is not string" );
1950+
1951+ assert (PyInitConfig_SetStrList (config , "cpu_count" ,
1952+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1953+ check_initconfig_error (config , "config option type is not strings list" );
1954+
1955+
1956+ // Test SetInt() range: cpu_count option type is PyConfig_MEMBER_INT
1957+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MIN ) == 0 );
1958+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MAX ) == 0 );
1959+
1960+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MIN ) == -1 );
1961+ check_initconfig_error (config , "config option value is out of int range" );
1962+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MAX ) == -1 );
1963+ check_initconfig_error (config , "config option value is out of int range" );
1964+
1965+
1966+ // Test SetInt() range: verbose option type is PyConfig_MEMBER_UINT
1967+ assert (PyInitConfig_SetInt (config , "verbose" , 0 ) == 0 );
1968+ assert (PyInitConfig_SetInt (config , "verbose" , UINT_MAX ) == 0 );
1969+
1970+ assert (PyInitConfig_SetInt (config , "verbose" , -1 ) == -1 );
1971+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1972+ assert (PyInitConfig_SetInt (config , "verbose" , INT64_MAX ) == -1 );
1973+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1974+
1975+
1976+ // SetStr() decode error
1977+ assert (PyInitConfig_SetStr (config , "platlibdir" , "\xff" ) == -1 );
1978+ check_initconfig_error (config , "decoding error" );
1979+
1980+
1981+ // Setting a non-optional string to NULL fails with an error,
1982+ // but leaves the optional unchanged.
1983+ if (PyInitConfig_SetStr (config , "program_name" , PROGRAM_NAME_UTF8 ) < 0 ) {
1984+ goto error ;
1985+ }
1986+ assert (PyInitConfig_SetStr (config , "program_name" , NULL ) < 0 );
1987+ check_initconfig_error (config , "config option string cannot be NULL" );
1988+ char * str ;
1989+ assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
1990+ assert (strcmp (str , PROGRAM_NAME_UTF8 ) == 0 );
1991+ free (str );
1992+
1993+
1994+ PyInitConfig_Free (config );
1995+ return 0 ;
1996+
1997+ error :
1998+ {
1999+ const char * err_msg ;
2000+ (void )PyInitConfig_GetError (config , & err_msg );
2001+ printf ("Python init failed: %s\n" , err_msg );
2002+ exit (1 );
2003+ }
2004+ }
2005+
2006+
19082007static int test_initconfig_get_api (void )
19092008{
19102009 PyInitConfig * config = PyInitConfig_Create ();
@@ -1917,6 +2016,7 @@ static int test_initconfig_get_api(void)
19172016 assert (PyInitConfig_HasOption (config , "verbose" ) == 1 );
19182017 assert (PyInitConfig_HasOption (config , "utf8_mode" ) == 1 );
19192018 assert (PyInitConfig_HasOption (config , "non-existent" ) == 0 );
2019+ assert (PyInitConfig_HasOption (config , "" ) == 0 );
19202020
19212021 // test PyInitConfig_GetInt()
19222022 assert (initconfig_getint (config , "dev_mode" ) == 0 );
@@ -1928,7 +2028,7 @@ static int test_initconfig_get_api(void)
19282028 assert (PyInitConfig_SetInt (config , "utf8_mode" , 1 ) == 0 );
19292029 assert (initconfig_getint (config , "utf8_mode" ) == 1 );
19302030
1931- // test PyInitConfig_GetStr()
2031+ // test PyInitConfig_GetStr() on an unset string (NULL by default)
19322032 char * str ;
19332033 assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
19342034 assert (str == NULL );
@@ -1954,8 +2054,11 @@ static int test_initconfig_get_api(void)
19542054
19552055 // Setting hash_seed sets use_hash_seed
19562056 assert (initconfig_getint (config , "use_hash_seed" ) == 0 );
2057+ assert (initconfig_getint (config , "hash_seed" ) == 0 );
2058+
19572059 assert (PyInitConfig_SetInt (config , "hash_seed" , 123 ) == 0 );
19582060 assert (initconfig_getint (config , "use_hash_seed" ) == 1 );
2061+ assert (initconfig_getint (config , "hash_seed" ) == 123 );
19592062
19602063 // Setting module_search_paths sets module_search_paths_set
19612064 assert (initconfig_getint (config , "module_search_paths_set" ) == 0 );
@@ -1964,6 +2067,7 @@ static int test_initconfig_get_api(void)
19642067 Py_ARRAY_LENGTH (paths ), paths ) == 0 );
19652068 assert (initconfig_getint (config , "module_search_paths_set" ) == 1 );
19662069
2070+ PyInitConfig_Free (config );
19672071 return 0 ;
19682072}
19692073
@@ -2703,6 +2807,7 @@ static struct TestCase TestCases[] = {
27032807 {"test_init_is_python_build" , test_init_is_python_build },
27042808 {"test_init_warnoptions" , test_init_warnoptions },
27052809 {"test_initconfig_api" , test_initconfig_api },
2810+ {"test_initconfig_set_errors" , test_initconfig_set_errors },
27062811 {"test_initconfig_get_api" , test_initconfig_get_api },
27072812 {"test_initconfig_exit" , test_initconfig_exit },
27082813 {"test_initconfig_module" , test_initconfig_module },
0 commit comments