test: stop using PATH_TEST()/QMP_TEST() macro to make not confuse gcc/gcov/lcov (#42338)
This commit is contained in:
@@ -104,7 +104,7 @@ jobs:
|
||||
--exclude "*.gperf" \
|
||||
--output-file build/test/coverage/initial.coverage-info \
|
||||
--base-directory src/ \
|
||||
--ignore-errors source,inconsistent \
|
||||
--ignore-errors source \
|
||||
--no-external \
|
||||
--substitute "s#src/src#src#g"
|
||||
|
||||
|
||||
+88
-76
@@ -18,46 +18,44 @@
|
||||
|
||||
static char *runtime_dir = NULL;
|
||||
|
||||
static int setup_test(Manager **m) {
|
||||
char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
|
||||
"directorynotempty", "makedirectory");
|
||||
_cleanup_(manager_freep) Manager *tmp = NULL;
|
||||
static int setup_test(Manager **ret) {
|
||||
int r;
|
||||
|
||||
ASSERT_NOT_NULL(m);
|
||||
|
||||
r = enter_cgroup_subroot(NULL);
|
||||
if (r == -ENOMEDIUM)
|
||||
return log_tests_skipped("cgroupfs not available");
|
||||
|
||||
r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
if (manager_errno_skip_test(r))
|
||||
return log_tests_skipped_errno(r, "manager_new");
|
||||
ASSERT_OK(r);
|
||||
ASSERT_OK(manager_startup(tmp, NULL, NULL, NULL, NULL));
|
||||
ASSERT_OK(manager_startup(m, NULL, NULL, NULL, NULL));
|
||||
|
||||
STRV_FOREACH(test_path, tests_path) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = strjoin("/tmp/test-path_", *test_path);
|
||||
ASSERT_NOT_NULL(p);
|
||||
FOREACH_STRING(s,
|
||||
"exists",
|
||||
"existsglobFOOBAR",
|
||||
"changed",
|
||||
"modified",
|
||||
"unit",
|
||||
"directorynotempty",
|
||||
"makedirectory") {
|
||||
|
||||
_cleanup_free_ char *p = ASSERT_NOT_NULL(strjoin("/tmp/test-path_", s));
|
||||
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
}
|
||||
|
||||
*m = TAKE_PTR(tmp);
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Service *service_for_path(Manager *m, Path *path, const char *service_name) {
|
||||
_cleanup_free_ char *tmp = NULL;
|
||||
Unit *service_unit = NULL;
|
||||
|
||||
static Service* service_for_path(Manager *m, Path *path, const char *service_name) {
|
||||
ASSERT_NOT_NULL(m);
|
||||
ASSERT_NOT_NULL(path);
|
||||
|
||||
Unit *service_unit;
|
||||
if (!service_name) {
|
||||
tmp = ASSERT_NOT_NULL(strreplace(UNIT(path)->id, ".path", ".service"));
|
||||
_cleanup_free_ char *tmp = ASSERT_NOT_NULL(strreplace(UNIT(path)->id, ".path", ".service"));
|
||||
service_unit = manager_get_unit(m, tmp);
|
||||
} else
|
||||
service_unit = manager_get_unit(m, service_name);
|
||||
@@ -66,19 +64,6 @@ static Service *service_for_path(Manager *m, Path *path, const char *service_nam
|
||||
return SERVICE(service_unit);
|
||||
}
|
||||
|
||||
/* Define a test that gets a freshly-initialized Manager passed as `m`. The body returns 0 on
|
||||
* success or EXIT_TEST_SKIP to skip; the wrapper hands the value back to the test framework. */
|
||||
#define PATH_TEST(name) \
|
||||
static int test_##name##_body(Manager *m); \
|
||||
TEST_RET(name) { \
|
||||
_cleanup_(manager_freep) Manager *m = NULL; \
|
||||
int r = setup_test(&m); \
|
||||
if (r != 0) \
|
||||
return r; \
|
||||
return test_##name##_body(m); \
|
||||
} \
|
||||
static int test_##name##_body(Manager *m)
|
||||
|
||||
static int _check_states(
|
||||
unsigned line,
|
||||
Manager *m,
|
||||
@@ -155,16 +140,20 @@ static int _check_states(
|
||||
return _r; \
|
||||
} while (0)
|
||||
|
||||
PATH_TEST(path_exists) {
|
||||
TEST_RET(path_exists) {
|
||||
const char *test_path = "/tmp/test-path_exists";
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, NULL);
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, NULL);
|
||||
|
||||
ASSERT_OK(unit_start(unit, NULL));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
@@ -184,16 +173,20 @@ PATH_TEST(path_exists) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_existsglob) {
|
||||
TEST_RET(path_existsglob) {
|
||||
const char *test_path = "/tmp/test-path_existsglobFOOBAR";
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, NULL);
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, NULL);
|
||||
|
||||
ASSERT_OK(unit_start(unit, NULL));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
@@ -213,17 +206,20 @@ PATH_TEST(path_existsglob) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_changed) {
|
||||
TEST_RET(path_changed) {
|
||||
const char *test_path = "/tmp/test-path_changed";
|
||||
FILE *f;
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, NULL);
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, NULL);
|
||||
|
||||
ASSERT_OK(unit_start(unit, NULL));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
@@ -235,8 +231,7 @@ PATH_TEST(path_changed) {
|
||||
ASSERT_OK(unit_stop(UNIT(service)));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
|
||||
f = ASSERT_NOT_NULL(fopen(test_path, "w"));
|
||||
fclose(f);
|
||||
fclose(ASSERT_NOT_NULL(fopen(test_path, "w")));
|
||||
|
||||
check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
|
||||
|
||||
@@ -248,17 +243,20 @@ PATH_TEST(path_changed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_modified) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
TEST_RET(path_modified) {
|
||||
const char *test_path = "/tmp/test-path_modified";
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, NULL);
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, NULL);
|
||||
|
||||
ASSERT_OK(unit_start(unit, NULL));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
@@ -270,7 +268,7 @@ PATH_TEST(path_modified) {
|
||||
ASSERT_OK(unit_stop(UNIT(service)));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
|
||||
f = ASSERT_NOT_NULL(fopen(test_path, "w"));
|
||||
_cleanup_fclose_ FILE *f = ASSERT_NOT_NULL(fopen(test_path, "w"));
|
||||
fputs("test", f);
|
||||
|
||||
check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
|
||||
@@ -283,16 +281,20 @@ PATH_TEST(path_modified) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_unit) {
|
||||
TEST_RET(path_unit) {
|
||||
const char *test_path = "/tmp/test-path_unit";
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, "path-mycustomunit.service");
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, "path-mycustomunit.service");
|
||||
|
||||
ASSERT_OK(unit_start(unit, NULL));
|
||||
check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
|
||||
@@ -308,16 +310,20 @@ PATH_TEST(path_unit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_directorynotempty) {
|
||||
TEST_RET(path_directorynotempty) {
|
||||
const char *test_file, *test_path = "/tmp/test-path_directorynotempty/";
|
||||
Unit *unit = NULL;
|
||||
Path *path = NULL;
|
||||
Service *service = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit));
|
||||
|
||||
path = PATH(unit);
|
||||
service = service_for_path(m, path, NULL);
|
||||
Path *path = PATH(unit);
|
||||
Service *service = service_for_path(m, path, NULL);
|
||||
|
||||
ASSERT_FAIL(access(test_path, F_OK));
|
||||
|
||||
@@ -344,11 +350,16 @@ PATH_TEST(path_directorynotempty) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PATH_TEST(path_makedirectory_directorymode) {
|
||||
TEST_RET(path_makedirectory_directorymode) {
|
||||
const char *test_path = "/tmp/test-path_makedirectory/";
|
||||
Unit *unit = NULL;
|
||||
struct stat s;
|
||||
int r;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
r = setup_test(&m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
Unit *unit;
|
||||
ASSERT_OK(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit));
|
||||
|
||||
ASSERT_FAIL(access(test_path, F_OK));
|
||||
@@ -359,6 +370,7 @@ PATH_TEST(path_makedirectory_directorymode) {
|
||||
ASSERT_OK_ERRNO(access(test_path, F_OK));
|
||||
|
||||
/* Check the mode we specified with DirectoryMode=0744 */
|
||||
struct stat s;
|
||||
ASSERT_OK_ERRNO(stat(test_path, &s));
|
||||
ASSERT_EQ((mode_t) (s.st_mode & S_IRWXU), (mode_t) 0700);
|
||||
ASSERT_EQ((mode_t) (s.st_mode & S_IRWXG), (mode_t) 0040);
|
||||
|
||||
+49
-21
@@ -151,20 +151,6 @@ static void run_qmp_test(sd_fiber_func_t mock_fn, sd_fiber_func_t client_fn) {
|
||||
ASSERT_OK(sd_future_result(mock_f));
|
||||
}
|
||||
|
||||
/* Define a test whose body runs as the client fiber on an event loop shared with `mock_fn`.
|
||||
* The body receives `QmpClient *client` as its argument. */
|
||||
#define QMP_TEST(name, mock_fn) \
|
||||
static int test_##name##_body(QmpClient *client); \
|
||||
static int test_##name##_fiber(void *userdata) { \
|
||||
int r = test_##name##_body(userdata); \
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0)); \
|
||||
return r; \
|
||||
} \
|
||||
TEST(name) { \
|
||||
run_qmp_test(mock_fn, test_##name##_fiber); \
|
||||
} \
|
||||
static int test_##name##_body(QmpClient *client)
|
||||
|
||||
static int mock_qmp_basic_fiber(void *userdata) {
|
||||
_cleanup_(json_stream_done) JsonStream s = {};
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *stop_event = NULL;
|
||||
@@ -201,7 +187,8 @@ static int test_event_callback(
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_basic, mock_qmp_basic_fiber) {
|
||||
static int qmp_client_basic_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
|
||||
_cleanup_free_ char *error_desc = NULL;
|
||||
bool event_received = false;
|
||||
@@ -220,9 +207,14 @@ QMP_TEST(qmp_client_basic, mock_qmp_basic_fiber) {
|
||||
ASSERT_OK_POSITIVE(qmp_client_call(client, "cont", NULL, NULL, NULL));
|
||||
|
||||
ASSERT_TRUE(event_received);
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_basic) {
|
||||
run_qmp_test(mock_qmp_basic_fiber, qmp_client_basic_fiber);
|
||||
}
|
||||
|
||||
static int mock_qmp_eof_fiber(void *userdata) {
|
||||
_cleanup_(json_stream_done) JsonStream s = {};
|
||||
|
||||
@@ -232,12 +224,18 @@ static int mock_qmp_eof_fiber(void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_eof, mock_qmp_eof_fiber) {
|
||||
static int qmp_client_eof_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
int r = qmp_client_call(client, "query-status", NULL, NULL, NULL);
|
||||
ASSERT_TRUE(ERRNO_IS_NEG_DISCONNECT(r));
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_eof) {
|
||||
run_qmp_test(mock_qmp_eof_fiber, qmp_client_eof_fiber);
|
||||
}
|
||||
|
||||
static int mock_qmp_call_fiber(void *userdata) {
|
||||
_cleanup_(json_stream_done) JsonStream s = {};
|
||||
|
||||
@@ -250,7 +248,8 @@ static int mock_qmp_call_fiber(void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_call, mock_qmp_call_fiber) {
|
||||
static int qmp_client_call_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
_cleanup_(sd_future_cancel_wait_unrefp) sd_future *f = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
|
||||
_cleanup_free_ char *error_desc = NULL;
|
||||
@@ -286,9 +285,14 @@ QMP_TEST(qmp_client_call, mock_qmp_call_fiber) {
|
||||
/* qmp_client_call() also surfaces QMP errors as -EIO, regardless of whether the caller
|
||||
* passed ret_error_desc. */
|
||||
ASSERT_ERROR(qmp_client_call(client, "stop", NULL, NULL, NULL), EIO);
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_call) {
|
||||
run_qmp_test(mock_qmp_call_fiber, qmp_client_call_fiber);
|
||||
}
|
||||
|
||||
static int mock_qmp_call_disconnect_fiber(void *userdata) {
|
||||
_cleanup_(json_stream_done) JsonStream s = {};
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *stop_cmd = NULL;
|
||||
@@ -302,12 +306,18 @@ static int mock_qmp_call_disconnect_fiber(void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_call_disconnect, mock_qmp_call_disconnect_fiber) {
|
||||
static int qmp_client_call_disconnect_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
int r = qmp_client_call(client, "stop", NULL, NULL, NULL);
|
||||
ASSERT_TRUE(ERRNO_IS_NEG_DISCONNECT(r));
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_call_disconnect) {
|
||||
run_qmp_test(mock_qmp_call_disconnect_fiber, qmp_client_call_disconnect_fiber);
|
||||
}
|
||||
|
||||
static int mock_qmp_fd_fiber(void *userdata) {
|
||||
_cleanup_(json_stream_done) JsonStream s = {};
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *cap_cmd = NULL, *addfd_cmd = NULL,
|
||||
@@ -336,7 +346,8 @@ static int mock_qmp_fd_fiber(void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_invoke_with_fd, mock_qmp_fd_fiber) {
|
||||
static int qmp_client_invoke_with_fd_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *args = NULL;
|
||||
_cleanup_close_ int fd_to_pass = -EBADF;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
|
||||
@@ -349,9 +360,14 @@ QMP_TEST(qmp_client_invoke_with_fd, mock_qmp_fd_fiber) {
|
||||
QMP_CLIENT_ARGS_FD(args, TAKE_FD(fd_to_pass)),
|
||||
&result, NULL));
|
||||
ASSERT_NOT_NULL(result);
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_invoke_with_fd) {
|
||||
run_qmp_test(mock_qmp_fd_fiber, qmp_client_invoke_with_fd_fiber);
|
||||
}
|
||||
|
||||
static int on_dead_peer_reply(
|
||||
QmpClient *client,
|
||||
sd_json_variant *result,
|
||||
@@ -433,7 +449,8 @@ static int tripwire_callback(
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_invoke_slot_lifecycle, mock_qmp_slot_fiber) {
|
||||
static int qmp_client_invoke_slot_lifecycle_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
_cleanup_(qmp_slot_unrefp) QmpSlot *slot = NULL;
|
||||
|
||||
ASSERT_OK(qmp_client_invoke(client, &slot, "query-status", NULL, nop_callback, NULL));
|
||||
@@ -447,10 +464,16 @@ QMP_TEST(qmp_client_invoke_slot_lifecycle, mock_qmp_slot_fiber) {
|
||||
|
||||
/* Explicit out-of-order unref exercises the already-disconnected path in qmp_slot_free(). */
|
||||
slot = qmp_slot_unref(slot);
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMP_TEST(qmp_client_invoke_slot_cancel, mock_qmp_slot_fiber) {
|
||||
TEST(qmp_invoke_slot_lifecycle) {
|
||||
run_qmp_test(mock_qmp_slot_fiber, qmp_client_invoke_slot_lifecycle_fiber);
|
||||
}
|
||||
|
||||
static int qmp_client_invoke_slot_cancel_fiber(void *userdata) {
|
||||
QmpClient *client = ASSERT_NOT_NULL(userdata);
|
||||
QmpSlot *slot = NULL;
|
||||
bool fired = false;
|
||||
|
||||
@@ -463,9 +486,14 @@ QMP_TEST(qmp_client_invoke_slot_cancel, mock_qmp_slot_fiber) {
|
||||
ASSERT_OK_POSITIVE(qmp_client_call(client, "stop", NULL, NULL, NULL));
|
||||
|
||||
ASSERT_FALSE(fired);
|
||||
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(qmp_invoke_slot_cancel) {
|
||||
run_qmp_test(mock_qmp_slot_fiber, qmp_client_invoke_slot_cancel_fiber);
|
||||
}
|
||||
|
||||
TEST(qmp_schema_has_member) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *schema = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user