[3.7] bpo-35233: Rewrite test_embed.InitConfigTests (GH-10524) (GH-10529)

* Add C functions:

  * _Py_GetGlobalVariablesAsDict()
  * _PyCoreConfig_AsDict()
  * _PyMainInterpreterConfig_AsDict()

* Add new _testcapi methods:

  * get_global_config()
  * get_core_config()
  * get_main_config()

* test.pythoninfo: get global, core and main configuration
* _testembed now serializes global, core and main configurations
  using JSON to reuse _Py_GetGlobalVariablesAsDict(),
  _PyCoreConfig_AsDict() and _PyMainInterpreterConfig_AsDict(),
  rather than duplicating code.
* test_embed.InitConfigTests now test much more configuration
  variables
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 6c35f95..b198962 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -293,92 +293,77 @@
 }
 
 
+static int
+dump_config_impl(void)
+{
+    PyObject *config = NULL;
+    PyObject *dict = NULL;
+
+    config = PyDict_New();
+    if (config == NULL) {
+        goto error;
+    }
+
+    /* global config */
+    dict = _Py_GetGlobalVariablesAsDict();
+    if (dict == NULL) {
+        goto error;
+    }
+    if (PyDict_SetItemString(config, "global_config", dict) < 0) {
+        goto error;
+    }
+    Py_CLEAR(dict);
+
+    /* core config */
+    PyInterpreterState *interp = PyThreadState_Get()->interp;
+    const _PyCoreConfig *core_config = &interp->core_config;
+    dict = _PyCoreConfig_AsDict(core_config);
+    if (dict == NULL) {
+        goto error;
+    }
+    if (PyDict_SetItemString(config, "core_config", dict) < 0) {
+        goto error;
+    }
+    Py_CLEAR(dict);
+
+    /* main config */
+    const _PyMainInterpreterConfig *main_config = &interp->config;
+    dict = _PyMainInterpreterConfig_AsDict(main_config);
+    if (dict == NULL) {
+        goto error;
+    }
+    if (PyDict_SetItemString(config, "main_config", dict) < 0) {
+        goto error;
+    }
+    Py_CLEAR(dict);
+
+    PyObject *json = PyImport_ImportModule("json");
+    PyObject *res = PyObject_CallMethod(json, "dumps", "O", config);
+    Py_DECREF(json);
+    Py_CLEAR(config);
+    if (res == NULL) {
+        goto error;
+    }
+
+    PySys_FormatStdout("%S\n", res);
+    Py_DECREF(res);
+
+    return 0;
+
+error:
+    Py_XDECREF(config);
+    Py_XDECREF(dict);
+    return -1;
+}
+
+
 static void
 dump_config(void)
 {
-#define ASSERT_EQUAL(a, b) \
-    if ((a) != (b)) { \
-        printf("ERROR: %s != %s (%i != %i)\n", #a, #b, (a), (b)); \
-        exit(1); \
+    if (dump_config_impl() < 0) {
+        fprintf(stderr, "failed to dump the configuration:\n");
+        PyErr_Print();
     }
-#define ASSERT_STR_EQUAL(a, b) \
-    if ((a) == NULL || (b == NULL) || wcscmp((a), (b)) != 0) { \
-        printf("ERROR: %s != %s ('%ls' != '%ls')\n", #a, #b, (a), (b)); \
-        exit(1); \
-    }
-
-    PyInterpreterState *interp = PyThreadState_Get()->interp;
-    _PyCoreConfig *config = &interp->core_config;
-
-    printf("install_signal_handlers = %i\n", config->install_signal_handlers);
-
-    printf("Py_IgnoreEnvironmentFlag = %i\n", Py_IgnoreEnvironmentFlag);
-
-    printf("use_hash_seed = %i\n", config->use_hash_seed);
-    printf("hash_seed = %lu\n", config->hash_seed);
-
-    printf("allocator = %s\n", config->allocator);
-
-    printf("dev_mode = %i\n", config->dev_mode);
-    printf("faulthandler = %i\n", config->faulthandler);
-    printf("tracemalloc = %i\n", config->tracemalloc);
-    printf("import_time = %i\n", config->import_time);
-    printf("show_ref_count = %i\n", config->show_ref_count);
-    printf("show_alloc_count = %i\n", config->show_alloc_count);
-    printf("dump_refs = %i\n", config->dump_refs);
-    printf("malloc_stats = %i\n", config->malloc_stats);
-
-    printf("coerce_c_locale = %i\n", config->coerce_c_locale);
-    printf("coerce_c_locale_warn = %i\n", config->coerce_c_locale_warn);
-    printf("utf8_mode = %i\n", config->utf8_mode);
-
-    printf("program_name = %ls\n", config->program_name);
-    ASSERT_STR_EQUAL(config->program_name, Py_GetProgramName());
-
-    printf("argc = %i\n", config->argc);
-    printf("argv = [");
-    for (int i=0; i < config->argc; i++) {
-        if (i) {
-            printf(", ");
-        }
-        printf("\"%ls\"", config->argv[i]);
-    }
-    printf("]\n");
-
-    printf("program = %ls\n", config->program);
-    /* FIXME: test xoptions */
-    /* FIXME: test warnoptions */
-    /* FIXME: test module_search_path_env */
-    /* FIXME: test home */
-    /* FIXME: test module_search_paths */
-    /* FIXME: test executable */
-    /* FIXME: test prefix */
-    /* FIXME: test base_prefix */
-    /* FIXME: test exec_prefix */
-    /* FIXME: test base_exec_prefix */
-    /* FIXME: test dll_path */
-
-    printf("Py_IsolatedFlag = %i\n", Py_IsolatedFlag);
-    printf("Py_NoSiteFlag = %i\n", Py_NoSiteFlag);
-    printf("Py_BytesWarningFlag = %i\n", Py_BytesWarningFlag);
-    printf("Py_InspectFlag = %i\n", Py_InspectFlag);
-    printf("Py_InteractiveFlag = %i\n", Py_InteractiveFlag);
-    printf("Py_OptimizeFlag = %i\n", Py_OptimizeFlag);
-    printf("Py_DebugFlag = %i\n", Py_DebugFlag);
-    printf("Py_DontWriteBytecodeFlag = %i\n", Py_DontWriteBytecodeFlag);
-    printf("Py_VerboseFlag = %i\n", Py_VerboseFlag);
-    printf("Py_QuietFlag = %i\n", Py_QuietFlag);
-    printf("Py_NoUserSiteDirectory = %i\n", Py_NoUserSiteDirectory);
-    printf("Py_UnbufferedStdioFlag = %i\n", Py_UnbufferedStdioFlag);
-    /* FIXME: test legacy_windows_fs_encoding */
-    /* FIXME: test legacy_windows_stdio */
-
-    printf("_disable_importlib = %i\n", config->_disable_importlib);
-    /* cannot test _Py_CheckHashBasedPycsMode: the symbol is not exported */
-    printf("Py_FrozenFlag = %i\n", Py_FrozenFlag);
-
-#undef ASSERT_EQUAL
-#undef ASSERT_STR_EQUAL
 }