@@ -1720,6 +1720,7 @@ static int test_initconfig_api(void)
17201720 goto error ;
17211721 }
17221722
1723+ // Set an integer option
17231724 if (PyInitConfig_SetInt (config , "hash_seed" , 10 ) < 0 ) {
17241725 goto error ;
17251726 }
@@ -1746,6 +1747,11 @@ static int test_initconfig_api(void)
17461747 goto error ;
17471748 }
17481749
1750+ // Set an optional string to NULL explicitly (must not crash).
1751+ if (PyInitConfig_SetStr (config , "prefix" , NULL ) < 0 ) {
1752+ goto error ;
1753+ }
1754+
17491755 if (Py_InitializeFromInitConfig (config ) < 0 ) {
17501756 goto error ;
17511757 }
@@ -1766,6 +1772,99 @@ static int test_initconfig_api(void)
17661772}
17671773
17681774
1775+ static void
1776+ check_initconfig_error (PyInitConfig * config , const char * expected )
1777+ {
1778+ const char * err_msg ;
1779+ assert (PyInitConfig_GetError (config , & err_msg ) == 1 );
1780+ assert (strcmp (err_msg , expected ) == 0 );
1781+ }
1782+
1783+
1784+ // Test errors of PyInitConfig_Set*() functions
1785+ static int test_initconfig_set_errors (void )
1786+ {
1787+ char * strlist [] = {"value" };
1788+
1789+ PyInitConfig * config = PyInitConfig_Create ();
1790+ if (config == NULL ) {
1791+ printf ("Init allocation error\n" );
1792+ return 1 ;
1793+ }
1794+
1795+ // Unknown option
1796+ assert (PyInitConfig_SetInt (config , "non-existent" , 123 ) < 0 );
1797+ check_initconfig_error (config , "unknown config option name" );
1798+ assert (PyInitConfig_SetStr (config , "non-existent" , "abc" ) < 0 );
1799+ check_initconfig_error (config , "unknown config option name" );
1800+ assert (PyInitConfig_SetStrList (config , "non-existent" ,
1801+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1802+ check_initconfig_error (config , "unknown config option name" );
1803+
1804+
1805+ // Wrong type
1806+ assert (PyInitConfig_SetInt (config , "platlibdir" , 123 ) == -1 );
1807+ check_initconfig_error (config , "config option type is not int" );
1808+
1809+ assert (PyInitConfig_SetStr (config , "cpu_count" , "abc" ) == -1 );
1810+ check_initconfig_error (config , "config option type is not string" );
1811+
1812+ assert (PyInitConfig_SetStrList (config , "cpu_count" ,
1813+ Py_ARRAY_LENGTH (strlist ), strlist ) < 0 );
1814+ check_initconfig_error (config , "config option type is not strings list" );
1815+
1816+
1817+ // Test SetInt() range: cpu_count option type is PyConfig_MEMBER_INT
1818+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MIN ) == 0 );
1819+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT_MAX ) == 0 );
1820+
1821+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MIN ) == -1 );
1822+ check_initconfig_error (config , "config option value is out of int range" );
1823+ assert (PyInitConfig_SetInt (config , "cpu_count" , INT64_MAX ) == -1 );
1824+ check_initconfig_error (config , "config option value is out of int range" );
1825+
1826+
1827+ // Test SetInt() range: verbose option type is PyConfig_MEMBER_UINT
1828+ assert (PyInitConfig_SetInt (config , "verbose" , 0 ) == 0 );
1829+ assert (PyInitConfig_SetInt (config , "verbose" , UINT_MAX ) == 0 );
1830+
1831+ assert (PyInitConfig_SetInt (config , "verbose" , -1 ) == -1 );
1832+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1833+ assert (PyInitConfig_SetInt (config , "verbose" , INT64_MAX ) == -1 );
1834+ check_initconfig_error (config , "config option value is out of unsigned int range" );
1835+
1836+
1837+ // SetStr() decode error
1838+ assert (PyInitConfig_SetStr (config , "platlibdir" , "\xff" ) == -1 );
1839+ check_initconfig_error (config , "decoding error" );
1840+
1841+
1842+ // Setting a non-optional string to NULL fails with an error,
1843+ // but leaves the optional unchanged.
1844+ if (PyInitConfig_SetStr (config , "program_name" , PROGRAM_NAME_UTF8 ) < 0 ) {
1845+ goto error ;
1846+ }
1847+ assert (PyInitConfig_SetStr (config , "program_name" , NULL ) < 0 );
1848+ check_initconfig_error (config , "config option string cannot be NULL" );
1849+ char * str ;
1850+ assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
1851+ assert (strcmp (str , PROGRAM_NAME_UTF8 ) == 0 );
1852+ free (str );
1853+
1854+
1855+ PyInitConfig_Free (config );
1856+ return 0 ;
1857+
1858+ error :
1859+ {
1860+ const char * err_msg ;
1861+ (void )PyInitConfig_GetError (config , & err_msg );
1862+ printf ("Python init failed: %s\n" , err_msg );
1863+ exit (1 );
1864+ }
1865+ }
1866+
1867+
17691868static int test_initconfig_get_api (void )
17701869{
17711870 PyInitConfig * config = PyInitConfig_Create ();
@@ -1778,6 +1877,7 @@ static int test_initconfig_get_api(void)
17781877 assert (PyInitConfig_HasOption (config , "verbose" ) == 1 );
17791878 assert (PyInitConfig_HasOption (config , "utf8_mode" ) == 1 );
17801879 assert (PyInitConfig_HasOption (config , "non-existent" ) == 0 );
1880+ assert (PyInitConfig_HasOption (config , "" ) == 0 );
17811881
17821882 // test PyInitConfig_GetInt()
17831883 assert (initconfig_getint (config , "dev_mode" ) == 0 );
@@ -1789,7 +1889,7 @@ static int test_initconfig_get_api(void)
17891889 assert (PyInitConfig_SetInt (config , "utf8_mode" , 0 ) == 0 );
17901890 assert (initconfig_getint (config , "utf8_mode" ) == 0 );
17911891
1792- // test PyInitConfig_GetStr()
1892+ // test PyInitConfig_GetStr() on an unset string (NULL by default)
17931893 char * str ;
17941894 assert (PyInitConfig_GetStr (config , "program_name" , & str ) == 0 );
17951895 assert (str == NULL );
@@ -1815,8 +1915,11 @@ static int test_initconfig_get_api(void)
18151915
18161916 // Setting hash_seed sets use_hash_seed
18171917 assert (initconfig_getint (config , "use_hash_seed" ) == 0 );
1918+ assert (initconfig_getint (config , "hash_seed" ) == 0 );
1919+
18181920 assert (PyInitConfig_SetInt (config , "hash_seed" , 123 ) == 0 );
18191921 assert (initconfig_getint (config , "use_hash_seed" ) == 1 );
1922+ assert (initconfig_getint (config , "hash_seed" ) == 123 );
18201923
18211924 // Setting module_search_paths sets module_search_paths_set
18221925 assert (initconfig_getint (config , "module_search_paths_set" ) == 0 );
@@ -1825,6 +1928,7 @@ static int test_initconfig_get_api(void)
18251928 Py_ARRAY_LENGTH (paths ), paths ) == 0 );
18261929 assert (initconfig_getint (config , "module_search_paths_set" ) == 1 );
18271930
1931+ PyInitConfig_Free (config );
18281932 return 0 ;
18291933}
18301934
@@ -3188,6 +3292,7 @@ static struct TestCase TestCases[] = {
31883292 {"test_init_is_python_build" , test_init_is_python_build },
31893293 {"test_init_warnoptions" , test_init_warnoptions },
31903294 {"test_initconfig_api" , test_initconfig_api },
3295+ {"test_initconfig_set_errors" , test_initconfig_set_errors },
31913296 {"test_initconfig_get_api" , test_initconfig_get_api },
31923297 {"test_initconfig_exit" , test_initconfig_exit },
31933298 {"test_initconfig_module" , test_initconfig_module },
0 commit comments