@@ -1801,6 +1801,7 @@ static int test_initconfig_api(void)
18011801 goto error ;
18021802 }
18031803
1804+ // Set an integer option
18041805 if (PyInitConfig_SetInt (config , "hash_seed" , 10 ) < 0 ) {
18051806 goto error ;
18061807 }
@@ -1827,6 +1828,11 @@ static int test_initconfig_api(void)
18271828 goto error ;
18281829 }
18291830
1831+ // Set an optional string to NULL explicitly (must not crash).
1832+ if (PyInitConfig_SetStr (config , "prefix" , NULL ) < 0 ) {
1833+ goto error ;
1834+ }
1835+
18301836 if (Py_InitializeFromInitConfig (config ) < 0 ) {
18311837 goto error ;
18321838 }
@@ -1847,6 +1853,99 @@ static int test_initconfig_api(void)
18471853}
18481854
18491855
1856+ static void
1857+ check_initconfig_error (PyInitConfig * config , const char * expected )
1858+ {
1859+ const char * err_msg ;
1860+ assert (PyInitConfig_GetError (config , & err_msg ) == 1 );
1861+ assert (strcmp (err_msg , expected ) == 0 );
1862+ }
1863+
1864+
1865+ // Test errors of PyInitConfig_Set*() functions
1866+ static int test_initconfig_set_errors (void )
1867+ {
1868+ char * strlist [] = {"value" };
1869+
1870+ PyInitConfig * config = PyInitConfig_Create ();
1871+ if (config == NULL ) {
1872+ printf ("Init allocation error\n" );
1873+ return 1 ;
1874+ }
1875+
1876+ // Unknown option
1877+ assert (PyInitConfig_SetInt (config , "non-existent" , 123 ) < 0 );
1878+ check_initconfig_error (config , "unknown config option name" );
1879+ assert (PyInitConfig_SetStr (config , "non-existent" , "abc" ) < 0 );
1880+ check_initconfig_error (config , "unknown config option name" );
1881+ assert (PyInitConfig_SetStrList (config , "non-existent" ,
1882+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1883+ check_initconfig_error (config , "unknown config option name" );
1884+
1885+
1886+ // Wrong type
1887+ assert (PyInitConfig_SetInt (config , "platlibdir" , 123 ) == -1 );
1888+ check_initconfig_error (config , "config option type is not int" );
1889+
1890+ assert (PyInitConfig_SetStr (config , "cpu_count" , "abc" ) == -1 );
1891+ check_initconfig_error (config , "config option type is not string" );
1892+
1893+ assert (PyInitConfig_SetStrList (config , "cpu_count" ,
1894+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1895+ check_initconfig_error (config , "config option type is not strings list" );
1896+
1897+
1898+ // Test SetInt() range: cpu_count option type is PyConfig_MEMBER_INT
1899+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MIN ) == 0 );
1900+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MAX ) == 0 );
1901+
1902+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MIN ) == -1 );
1903+ check_initconfig_error (config , "config option value is out of int range" );
1904+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MAX ) == -1 );
1905+ check_initconfig_error (config , "config option value is out of int range" );
1906+
1907+
1908+ // Test SetInt() range: verbose option type is PyConfig_MEMBER_UINT
1909+ assert (PyInitConfig_SetInt (config , "verbose" , 0 ) == 0 );
1910+ assert (PyInitConfig_SetInt (config , "verbose" , UINT_MAX ) == 0 );
1911+
1912+ assert (PyInitConfig_SetInt (config , "verbose" , -1 ) == -1 );
1913+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1914+ assert (PyInitConfig_SetInt (config , "verbose" , INT64_MAX ) == -1 );
1915+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1916+
1917+
1918+ // SetStr() decode error
1919+ assert (PyInitConfig_SetStr (config , "platlibdir" , "\xff" ) == -1 );
1920+ check_initconfig_error (config , "decoding error" );
1921+
1922+
1923+ // Setting a non-optional string to NULL fails with an error,
1924+ // but leaves the optional unchanged.
1925+ if (PyInitConfig_SetStr (config , "program_name" , PROGRAM_NAME_UTF8 ) < 0 ) {
1926+ goto error ;
1927+ }
1928+ assert (PyInitConfig_SetStr (config , "program_name" , NULL ) < 0 );
1929+ check_initconfig_error (config , "config option string cannot be NULL" );
1930+ char * str ;
1931+ assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
1932+ assert (strcmp (str , PROGRAM_NAME_UTF8 ) == 0 );
1933+ free (str );
1934+
1935+
1936+ PyInitConfig_Free (config );
1937+ return 0 ;
1938+
1939+ error :
1940+ {
1941+ const char * err_msg ;
1942+ (void )PyInitConfig_GetError (config , & err_msg );
1943+ printf ("Python init failed: %s\n" , err_msg );
1944+ exit (1 );
1945+ }
1946+ }
1947+
1948+
18501949static int test_initconfig_get_api (void )
18511950{
18521951 PyInitConfig * config = PyInitConfig_Create ();
@@ -1859,6 +1958,7 @@ static int test_initconfig_get_api(void)
18591958 assert (PyInitConfig_HasOption (config , "verbose" ) == 1 );
18601959 assert (PyInitConfig_HasOption (config , "utf8_mode" ) == 1 );
18611960 assert (PyInitConfig_HasOption (config , "non-existent" ) == 0 );
1961+ assert (PyInitConfig_HasOption (config , "" ) == 0 );
18621962
18631963 // test PyInitConfig_GetInt()
18641964 assert (initconfig_getint (config , "dev_mode" ) == 0 );
@@ -1870,7 +1970,7 @@ static int test_initconfig_get_api(void)
18701970 assert (PyInitConfig_SetInt (config , "utf8_mode" , 0 ) == 0 );
18711971 assert (initconfig_getint (config , "utf8_mode" ) == 0 );
18721972
1873- // test PyInitConfig_GetStr()
1973+ // test PyInitConfig_GetStr() on an unset string (NULL by default)
18741974 char * str ;
18751975 assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
18761976 assert (str == NULL );
@@ -1896,8 +1996,11 @@ static int test_initconfig_get_api(void)
18961996
18971997 // Setting hash_seed sets use_hash_seed
18981998 assert (initconfig_getint (config , "use_hash_seed" ) == 0 );
1999+ assert (initconfig_getint (config , "hash_seed" ) == 0 );
2000+
18992001 assert (PyInitConfig_SetInt (config , "hash_seed" , 123 ) == 0 );
19002002 assert (initconfig_getint (config , "use_hash_seed" ) == 1 );
2003+ assert (initconfig_getint (config , "hash_seed" ) == 123 );
19012004
19022005 // Setting module_search_paths sets module_search_paths_set
19032006 assert (initconfig_getint (config , "module_search_paths_set" ) == 0 );
@@ -1906,6 +2009,7 @@ static int test_initconfig_get_api(void)
19062009 Py_ARRAY_LENGTH (paths ), paths ) == 0 );
19072010 assert (initconfig_getint (config , "module_search_paths_set" ) == 1 );
19082011
2012+ PyInitConfig_Free (config );
19092013 return 0 ;
19102014}
19112015
@@ -3179,6 +3283,7 @@ static struct TestCase TestCases[] = {
31793283 {"test_init_is_python_build" , test_init_is_python_build },
31803284 {"test_init_warnoptions" , test_init_warnoptions },
31813285 {"test_initconfig_api" , test_initconfig_api },
3286+ {"test_initconfig_set_errors" , test_initconfig_set_errors },
31823287 {"test_initconfig_get_api" , test_initconfig_get_api },
31833288 {"test_initconfig_exit" , test_initconfig_exit },
31843289 {"test_initconfig_module" , test_initconfig_module },
0 commit comments