From cd4c7f317d75ce4ba3d2a1f7676d994c1202de34 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 10:50:06 -0800 Subject: [PATCH 01/40] Refactor: libcrmcommon: Don't allocate object in pcmk__output_factory_t This commit is much larger than I would prefer, but I didn't see a good way to do it in steps. Previously, a pcmk__output_factory_t created a pcmk__output_t object, NULL-checked it, and assigned all of the format-specific fields. This commit does the following: * Rename pcmk__output_factory_t to pcmk__output_setup_fn_t. * Accept an existing pcmk__output_t * argument in pcmk__output_setup_fn_t. * Return void from pcmk__output_setup_fn_t since it doesn't allocate the object. * Allocate the pcmk__output_t object in pcmk__bare_output_new() and pass it to the setup function. * Assign the request, register_message, and message fields within pcmk__bare_output_new(), since those are common to all setup functions. * Rename several fields and variables from "create" to "setup_fn". * Rename the pcmk__mk_FORMAT_output() functions to pcmk__output_setup_FORMAT(). * Rename the pcmk__output_null_create*() functions to pcmk__output_setup_dummy*(). I chose "setup" over "init" to avoid confusion with the pcmk__output_t:init method. Signed-off-by: Reid Wahl --- include/crm/common/output_internal.h | 58 +++++++++-------- include/crm/common/unittest_internal.h | 6 +- lib/common/output.c | 27 +++++--- lib/common/output_html.c | 63 ++++++++----------- lib/common/output_log.c | 61 ++++++++---------- lib/common/output_none.c | 63 ++++++++----------- lib/common/output_text.c | 63 ++++++++----------- lib/common/output_xml.c | 63 ++++++++----------- .../tests/output/pcmk__register_format_test.c | 12 ++-- .../output/pcmk__register_formats_test.c | 24 +++---- .../output/pcmk__unregister_formats_test.c | 2 +- lib/common/unittest.c | 39 ++++-------- tools/crm_mon.h | 7 ++- tools/crm_mon_curses.c | 63 ++++++++----------- 14 files changed, 243 insertions(+), 308 deletions(-) diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index fde8d6ee235..41a5e09b32e 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -42,15 +42,15 @@ typedef struct pcmk__output_s pcmk__output_t; /*! * \internal - * \brief The type of a function that creates a ::pcmk__output_t. + * \brief Function for format-specific setup of a \c pcmk__output_t * - * Instances of this type are passed to pcmk__register_format(), stored in an - * internal data structure, and later accessed by pcmk__output_new(). For - * examples, see pcmk__mk_xml_output() and pcmk__mk_text_output(). + * Instances of this type are passed to \c pcmk__register_format(), stored in an + * internal data structure, and later accessed by \c pcmk__output_new(). For + * examples, see \c pcmk__output_setup_text() and \c pcmk__output_setup_xml(). * - * \param[in] argv The list of command line arguments. + * \param[in] out Output object to set up */ -typedef pcmk__output_t * (*pcmk__output_factory_t)(char **argv); +typedef void (*pcmk__output_setup_fn_t)(pcmk__output_t *out); /*! * \internal @@ -131,9 +131,10 @@ typedef struct pcmk__supported_format_s { const char *name; /*! - * \brief A function that creates a ::pcmk__output_t. + * \internal + * \brief Function that does format-specific setup for a \c pcmk__output_t */ - pcmk__output_factory_t create; + pcmk__output_setup_fn_t setup_fn; /*! * \brief Format-specific command line options. This can be NULL if @@ -148,17 +149,19 @@ typedef struct pcmk__supported_format_s { extern GOptionEntry pcmk__html_output_entries[]; -pcmk__output_t *pcmk__mk_html_output(char **argv); -pcmk__output_t *pcmk__mk_log_output(char **argv); -pcmk__output_t *pcmk__mk_none_output(char **argv); -pcmk__output_t *pcmk__mk_text_output(char **argv); -pcmk__output_t *pcmk__mk_xml_output(char **argv); +void pcmk__output_setup_html(pcmk__output_t *out); +void pcmk__output_setup_log(pcmk__output_t *out); +void pcmk__output_setup_none(pcmk__output_t *out); +void pcmk__output_setup_text(pcmk__output_t *out); +void pcmk__output_setup_xml(pcmk__output_t *out); -#define PCMK__SUPPORTED_FORMAT_HTML { "html", pcmk__mk_html_output, pcmk__html_output_entries } -#define PCMK__SUPPORTED_FORMAT_LOG { "log", pcmk__mk_log_output, NULL } -#define PCMK__SUPPORTED_FORMAT_NONE { PCMK_VALUE_NONE, pcmk__mk_none_output, NULL } -#define PCMK__SUPPORTED_FORMAT_TEXT { "text", pcmk__mk_text_output, NULL } -#define PCMK__SUPPORTED_FORMAT_XML { "xml", pcmk__mk_xml_output, NULL } +#define PCMK__SUPPORTED_FORMAT_HTML \ + { "html", pcmk__output_setup_html, pcmk__html_output_entries } +#define PCMK__SUPPORTED_FORMAT_LOG { "log", pcmk__output_setup_log, NULL } +#define PCMK__SUPPORTED_FORMAT_NONE \ + { PCMK_VALUE_NONE, pcmk__output_setup_none, NULL } +#define PCMK__SUPPORTED_FORMAT_TEXT { "text", pcmk__output_setup_text, NULL } +#define PCMK__SUPPORTED_FORMAT_XML { "xml", pcmk__output_setup_xml, NULL } /*! * \brief This structure contains everything that makes up a single output @@ -585,20 +588,21 @@ int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, * \brief Register a new output formatter, making it available for use * the same as a base formatter. * - * \param[in,out] group A ::GOptionGroup that formatted output related command - * line arguments should be added to. This can be NULL - * for use outside of command line programs. - * \param[in] name The name of the format. This will be used to select a - * format from command line options and for displaying help. - * \param[in] create A function that creates a ::pcmk__output_t. - * \param[in] options Format-specific command line options. These will be - * added to the context. This argument can also be NULL. + * \param[in,out] group Option group that formatted output-related command + * line arguments should be added to. This can be + * \c NULL for use outside of command line programs. + * \param[in] name Format name. This will be used to select a format + * from command line options and for displaying help. + * \param[in] setup_fn Function that initializes a \c pcmk__output_t + * \param[in] options Format-specific command line options. These will be + * added to the context. This argument can also be + * \c NULL. * * \return Standard Pacemaker return code */ int pcmk__register_format(GOptionGroup *group, const char *name, - pcmk__output_factory_t create, + pcmk__output_setup_fn_t setup, const GOptionEntry *options); /*! diff --git a/include/crm/common/unittest_internal.h b/include/crm/common/unittest_internal.h index d65f83e1f8f..60c5efeab89 100644 --- a/include/crm/common/unittest_internal.h +++ b/include/crm/common/unittest_internal.h @@ -138,7 +138,7 @@ void pcmk__cib_test_cleanup(char *out_path); void pcmk__test_init_logging(const char *name, const char *filename); -pcmk__output_t *pcmk__mk_fake_text_output(char **argv); +void pcmk__output_setup_fake_text(pcmk__output_t *out); int pcmk__output_test_setup_group(void **state); int pcmk__output_test_teardown_group(void **state); void pcmk__set_fake_text_init_succeeds(bool value); @@ -146,8 +146,8 @@ void pcmk__set_testing_output_free(bool value); void pcmk__set_testing_output_and_clear_error(bool value); void pcmk__expect_fake_text_free_priv(void); void pcmk__expect_fake_text_err(void); -pcmk__output_t *pcmk__output_null_create1(char **argv); -pcmk__output_t *pcmk__output_null_create2(char **argv); +void pcmk__output_setup_dummy1(pcmk__output_t *out); +void pcmk__output_setup_dummy2(pcmk__output_t *out); int pcmk__output_message_dummy1(pcmk__output_t *out, va_list args); int pcmk__output_message_dummy2(pcmk__output_t *out, va_list args); diff --git a/lib/common/output.c b/lib/common/output.c index 1d6bba9533b..39f243cf13d 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -71,7 +71,7 @@ int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv) { - pcmk__output_factory_t create = NULL; + pcmk__output_setup_fn_t setup_fn = NULL; pcmk__assert((formatters != NULL) && (out != NULL)); @@ -79,20 +79,26 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, * what it supports so this also may not be valid. */ if (fmt_name == NULL) { - create = g_hash_table_lookup(formatters, "text"); + setup_fn = g_hash_table_lookup(formatters, "text"); } else { - create = g_hash_table_lookup(formatters, fmt_name); + setup_fn = g_hash_table_lookup(formatters, fmt_name); } - if (create == NULL) { + if (setup_fn == NULL) { return pcmk_rc_unknown_format; } - *out = create(argv); + *out = calloc(1, sizeof(pcmk__output_t)); if (*out == NULL) { return ENOMEM; } + setup_fn(*out); + + (*out)->request = pcmk__quote_cmdline(argv); + (*out)->register_message = pcmk__register_message; + (*out)->message = pcmk__call_message; + if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) { (*out)->dest = stdout; } else { @@ -133,12 +139,12 @@ pcmk__output_new(pcmk__output_t **out, const char *fmt_name, int pcmk__register_format(GOptionGroup *group, const char *name, - pcmk__output_factory_t create, + pcmk__output_setup_fn_t setup_fn, const GOptionEntry *options) { char *name_copy = NULL; - pcmk__assert((create != NULL) && !pcmk__str_empty(name)); + pcmk__assert((setup_fn != NULL) && !pcmk__str_empty(name)); // cppcheck doesn't understand the above pcmk__assert line // cppcheck-suppress ctunullpointer @@ -155,7 +161,7 @@ pcmk__register_format(GOptionGroup *group, const char *name, g_option_group_add_entries(group, options); } - g_hash_table_insert(formatters, name_copy, create); + g_hash_table_insert(formatters, name_copy, setup_fn); return pcmk_rc_ok; } @@ -166,9 +172,12 @@ pcmk__register_formats(GOptionGroup *group, if (formats == NULL) { return; } + for (const pcmk__supported_format_t *entry = formats; entry->name != NULL; entry++) { - pcmk__register_format(group, entry->name, entry->create, entry->options); + + pcmk__register_format(group, entry->name, entry->setup_fn, + entry->options); } } diff --git a/lib/common/output_html.c b/lib/common/output_html.c index 3215e0825b1..6ba7a79075a 100644 --- a/lib/common/output_html.c +++ b/lib/common/output_html.c @@ -413,43 +413,32 @@ html_progress(pcmk__output_t *out, bool end) { /* This function intentially left blank */ } -pcmk__output_t * -pcmk__mk_html_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "html"; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = html_init; - retval->free_priv = html_free_priv; - retval->finish = html_finish; - retval->reset = html_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = html_subprocess_output; - retval->version = html_version; - retval->info = html_info; - retval->transient = html_info; - retval->err = html_err; - retval->output_xml = html_output_xml; - - retval->begin_list = html_begin_list; - retval->list_item = html_list_item; - retval->increment_list = html_increment_list; - retval->end_list = html_end_list; - - retval->is_quiet = html_is_quiet; - retval->spacer = html_spacer; - retval->progress = html_progress; - retval->prompt = pcmk__text_prompt; - - return retval; +void +pcmk__output_setup_html(pcmk__output_t *out) +{ + out->fmt_name = "html"; + + out->init = html_init; + out->free_priv = html_free_priv; + out->finish = html_finish; + out->reset = html_reset; + + out->subprocess_output = html_subprocess_output; + out->version = html_version; + out->info = html_info; + out->transient = html_info; + out->err = html_err; + out->output_xml = html_output_xml; + + out->begin_list = html_begin_list; + out->list_item = html_list_item; + out->increment_list = html_increment_list; + out->end_list = html_end_list; + + out->is_quiet = html_is_quiet; + out->spacer = html_spacer; + out->progress = html_progress; + out->prompt = pcmk__text_prompt; } xmlNodePtr diff --git a/lib/common/output_log.c b/lib/common/output_log.c index 608efd625ed..262c8230a4c 100644 --- a/lib/common/output_log.c +++ b/lib/common/output_log.c @@ -300,42 +300,31 @@ log_prompt(const char *prompt, bool echo, char **dest) { /* This function intentionally left blank */ } -pcmk__output_t * -pcmk__mk_log_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "log"; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = log_init; - retval->free_priv = log_free_priv; - retval->finish = log_finish; - retval->reset = log_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = log_subprocess_output; - retval->version = log_version; - retval->info = log_info; - retval->transient = log_transient; - retval->err = log_err; - retval->output_xml = log_output_xml; - - retval->begin_list = log_begin_list; - retval->list_item = log_list_item; - retval->end_list = log_end_list; - - retval->is_quiet = log_is_quiet; - retval->spacer = log_spacer; - retval->progress = log_progress; - retval->prompt = log_prompt; - - return retval; +void +pcmk__output_setup_log(pcmk__output_t *out) +{ + out->fmt_name = "log"; + + out->init = log_init; + out->free_priv = log_free_priv; + out->finish = log_finish; + out->reset = log_reset; + + out->subprocess_output = log_subprocess_output; + out->version = log_version; + out->info = log_info; + out->transient = log_transient; + out->err = log_err; + out->output_xml = log_output_xml; + + out->begin_list = log_begin_list; + out->list_item = log_list_item; + out->end_list = log_end_list; + + out->is_quiet = log_is_quiet; + out->spacer = log_spacer; + out->progress = log_progress; + out->prompt = log_prompt; } /*! diff --git a/lib/common/output_none.c b/lib/common/output_none.c index 8a5032a2242..be49c0f2b76 100644 --- a/lib/common/output_none.c +++ b/lib/common/output_none.c @@ -110,41 +110,30 @@ none_prompt(const char *prompt, bool echo, char **dest) { /* This function intentionally left blank */ } -pcmk__output_t * -pcmk__mk_none_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = PCMK_VALUE_NONE; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = none_init; - retval->free_priv = none_free_priv; - retval->finish = none_finish; - retval->reset = none_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = none_subprocess_output; - retval->version = none_version; - retval->info = none_info; - retval->transient = none_info; - retval->err = none_err; - retval->output_xml = none_output_xml; - - retval->begin_list = none_begin_list; - retval->list_item = none_list_item; - retval->increment_list = none_increment_list; - retval->end_list = none_end_list; - - retval->is_quiet = none_is_quiet; - retval->spacer = none_spacer; - retval->progress = none_progress; - retval->prompt = none_prompt; - - return retval; +void +pcmk__output_setup_none(pcmk__output_t *out) +{ + out->fmt_name = PCMK_VALUE_NONE; + + out->init = none_init; + out->free_priv = none_free_priv; + out->finish = none_finish; + out->reset = none_reset; + + out->subprocess_output = none_subprocess_output; + out->version = none_version; + out->info = none_info; + out->transient = none_info; + out->err = none_err; + out->output_xml = none_output_xml; + + out->begin_list = none_begin_list; + out->list_item = none_list_item; + out->increment_list = none_increment_list; + out->end_list = none_end_list; + + out->is_quiet = none_is_quiet; + out->spacer = none_spacer; + out->progress = none_progress; + out->prompt = none_prompt; } diff --git a/lib/common/output_text.c b/lib/common/output_text.c index fcade4736b8..6d6b6774115 100644 --- a/lib/common/output_text.c +++ b/lib/common/output_text.c @@ -305,43 +305,32 @@ text_progress(pcmk__output_t *out, bool end) { } } -pcmk__output_t * -pcmk__mk_text_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "text"; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = text_init; - retval->free_priv = text_free_priv; - retval->finish = text_finish; - retval->reset = text_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = text_subprocess_output; - retval->version = text_version; - retval->info = text_info; - retval->transient = text_transient; - retval->err = text_err; - retval->output_xml = text_output_xml; - - retval->begin_list = text_begin_list; - retval->list_item = text_list_item; - retval->increment_list = text_increment_list; - retval->end_list = text_end_list; - - retval->is_quiet = text_is_quiet; - retval->spacer = text_spacer; - retval->progress = text_progress; - retval->prompt = pcmk__text_prompt; - - return retval; +void +pcmk__output_setup_text(pcmk__output_t *out) +{ + out->fmt_name = "text"; + + out->init = text_init; + out->free_priv = text_free_priv; + out->finish = text_finish; + out->reset = text_reset; + + out->subprocess_output = text_subprocess_output; + out->version = text_version; + out->info = text_info; + out->transient = text_transient; + out->err = text_err; + out->output_xml = text_output_xml; + + out->begin_list = text_begin_list; + out->list_item = text_list_item; + out->increment_list = text_increment_list; + out->end_list = text_end_list; + + out->is_quiet = text_is_quiet; + out->spacer = text_spacer; + out->progress = text_progress; + out->prompt = pcmk__text_prompt; } /*! diff --git a/lib/common/output_xml.c b/lib/common/output_xml.c index 1b237db96d2..0603783dbff 100644 --- a/lib/common/output_xml.c +++ b/lib/common/output_xml.c @@ -439,43 +439,32 @@ xml_progress(pcmk__output_t *out, bool end) { /* This function intentionally left blank */ } -pcmk__output_t * -pcmk__mk_xml_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "xml"; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = xml_init; - retval->free_priv = xml_free_priv; - retval->finish = xml_finish; - retval->reset = xml_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = xml_subprocess_output; - retval->version = xml_version; - retval->info = xml_info; - retval->transient = xml_info; - retval->err = xml_err; - retval->output_xml = xml_output_xml; - - retval->begin_list = xml_begin_list; - retval->list_item = xml_list_item; - retval->increment_list = xml_increment_list; - retval->end_list = xml_end_list; - - retval->is_quiet = xml_is_quiet; - retval->spacer = xml_spacer; - retval->progress = xml_progress; - retval->prompt = pcmk__text_prompt; - - return retval; +void +pcmk__output_setup_xml(pcmk__output_t *out) +{ + out->fmt_name = "xml"; + + out->init = xml_init; + out->free_priv = xml_free_priv; + out->finish = xml_finish; + out->reset = xml_reset; + + out->subprocess_output = xml_subprocess_output; + out->version = xml_version; + out->info = xml_info; + out->transient = xml_info; + out->err = xml_err; + out->output_xml = xml_output_xml; + + out->begin_list = xml_begin_list; + out->list_item = xml_list_item; + out->increment_list = xml_increment_list; + out->end_list = xml_end_list; + + out->is_quiet = xml_is_quiet; + out->spacer = xml_spacer; + out->progress = xml_progress; + out->prompt = pcmk__text_prompt; } xmlNodePtr diff --git a/lib/common/tests/output/pcmk__register_format_test.c b/lib/common/tests/output/pcmk__register_format_test.c index 29a1ba3d173..12768dc805d 100644 --- a/lib/common/tests/output/pcmk__register_format_test.c +++ b/lib/common/tests/output/pcmk__register_format_test.c @@ -16,10 +16,10 @@ invalid_params(void **state) { pcmk__assert_asserts(pcmk__register_format(NULL, "fake", NULL, NULL)); pcmk__assert_asserts(pcmk__register_format(NULL, "", - pcmk__output_null_create1, + pcmk__output_setup_dummy1, NULL)); pcmk__assert_asserts(pcmk__register_format(NULL, NULL, - pcmk__output_null_create1, + pcmk__output_setup_dummy1, NULL)); } @@ -36,26 +36,26 @@ add_format(void **state) /* Add a fake formatter and check that it's the only item in the hash * table */ - rc = pcmk__register_format(NULL, "fake", pcmk__output_null_create1, NULL); + rc = pcmk__register_format(NULL, "fake", pcmk__output_setup_dummy1, NULL); assert_int_equal(rc, pcmk_rc_ok); formatters = pcmk__output_formatters(); assert_int_equal(g_hash_table_size(formatters), 1); value = g_hash_table_lookup(formatters, "fake"); - assert_ptr_equal(value, pcmk__output_null_create1); + assert_ptr_equal(value, pcmk__output_setup_dummy1); /* Add a second fake formatter that should overwrite the first one, leaving * only one item (with the new function) in the hash table */ - rc = pcmk__register_format(NULL, "fake", pcmk__output_null_create2, NULL); + rc = pcmk__register_format(NULL, "fake", pcmk__output_setup_dummy2, NULL); assert_int_equal(rc, pcmk_rc_ok); formatters = pcmk__output_formatters(); assert_int_equal(g_hash_table_size(formatters), 1); value = g_hash_table_lookup(formatters, "fake"); - assert_ptr_equal(value, pcmk__output_null_create2); + assert_ptr_equal(value, pcmk__output_setup_dummy2); pcmk__unregister_formats(); } diff --git a/lib/common/tests/output/pcmk__register_formats_test.c b/lib/common/tests/output/pcmk__register_formats_test.c index 7743bc12ddf..e5133e6c9ff 100644 --- a/lib/common/tests/output/pcmk__register_formats_test.c +++ b/lib/common/tests/output/pcmk__register_formats_test.c @@ -25,7 +25,7 @@ invalid_entries(void **state) * the marker for the end of the format table. */ pcmk__supported_format_t formats[] = { - { "", pcmk__output_null_create1, NULL }, + { "", pcmk__output_setup_dummy1, NULL }, { NULL }, }; @@ -38,8 +38,8 @@ valid_entries(void **state) GHashTable *formatters = NULL; pcmk__supported_format_t formats[] = { - { "fmt1", pcmk__output_null_create1, NULL }, - { "fmt2", pcmk__output_null_create2, NULL }, + { "fmt1", pcmk__output_setup_dummy1, NULL }, + { "fmt2", pcmk__output_setup_dummy2, NULL }, { NULL }, }; @@ -48,9 +48,9 @@ valid_entries(void **state) formatters = pcmk__output_formatters(); assert_int_equal(g_hash_table_size(formatters), 2); assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), - pcmk__output_null_create1); + pcmk__output_setup_dummy1); assert_ptr_equal(g_hash_table_lookup(formatters, "fmt2"), - pcmk__output_null_create2); + pcmk__output_setup_dummy2); pcmk__unregister_formats(); } @@ -61,8 +61,8 @@ duplicate_keys(void **state) GHashTable *formatters = NULL; pcmk__supported_format_t formats[] = { - { "fmt1", pcmk__output_null_create1, NULL }, - { "fmt1", pcmk__output_null_create2, NULL }, + { "fmt1", pcmk__output_setup_dummy1, NULL }, + { "fmt1", pcmk__output_setup_dummy2, NULL }, { NULL }, }; @@ -71,7 +71,7 @@ duplicate_keys(void **state) formatters = pcmk__output_formatters(); assert_int_equal(g_hash_table_size(formatters), 1); assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), - pcmk__output_null_create2); + pcmk__output_setup_dummy2); pcmk__unregister_formats(); } @@ -82,8 +82,8 @@ duplicate_values(void **state) GHashTable *formatters = NULL; pcmk__supported_format_t formats[] = { - { "fmt1", pcmk__output_null_create1, NULL }, - { "fmt2", pcmk__output_null_create1, NULL }, + { "fmt1", pcmk__output_setup_dummy1, NULL }, + { "fmt2", pcmk__output_setup_dummy1, NULL }, { NULL }, }; @@ -92,9 +92,9 @@ duplicate_values(void **state) formatters = pcmk__output_formatters(); assert_int_equal(g_hash_table_size(formatters), 2); assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), - pcmk__output_null_create1); + pcmk__output_setup_dummy1); assert_ptr_equal(g_hash_table_lookup(formatters, "fmt2"), - pcmk__output_null_create1); + pcmk__output_setup_dummy1); pcmk__unregister_formats(); } diff --git a/lib/common/tests/output/pcmk__unregister_formats_test.c b/lib/common/tests/output/pcmk__unregister_formats_test.c index 6c979cb1d40..91899f05f84 100644 --- a/lib/common/tests/output/pcmk__unregister_formats_test.c +++ b/lib/common/tests/output/pcmk__unregister_formats_test.c @@ -24,7 +24,7 @@ invalid_params(void **state) static void non_null_formatters(void **state) { - pcmk__register_format(NULL, "fake", pcmk__output_null_create1, NULL); + pcmk__register_format(NULL, "fake", pcmk__output_setup_dummy1, NULL); pcmk__unregister_formats(); assert_null(pcmk__output_formatters()); diff --git a/lib/common/unittest.c b/lib/common/unittest.c index 66fa748af0c..3da2f293919 100644 --- a/lib/common/unittest.c +++ b/lib/common/unittest.c @@ -202,32 +202,19 @@ fake_text_err(pcmk__output_t *out, const char *format, ...) } } -pcmk__output_t * -pcmk__mk_fake_text_output(char **argv) +void +pcmk__output_setup_fake_text(pcmk__output_t *out) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "text"; - - retval->init = fake_text_init; - retval->free_priv = fake_text_free_priv; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->err = fake_text_err; - - return retval; + out->fmt_name = "text"; + out->init = fake_text_init; + out->free_priv = fake_text_free_priv; + out->err = fake_text_err; } int pcmk__output_test_setup_group(void **state) { - pcmk__register_format(NULL, "text", pcmk__mk_fake_text_output, NULL); + pcmk__register_format(NULL, "text", pcmk__output_setup_fake_text, NULL); return 0; } @@ -268,16 +255,16 @@ pcmk__expect_fake_text_err(void) expect_function_call(fake_text_err); } -pcmk__output_t * -pcmk__output_null_create1(char **argv) +void +pcmk__output_setup_dummy1(pcmk__output_t *out) { - return NULL; + return; } -pcmk__output_t * -pcmk__output_null_create2(char **argv) +void +pcmk__output_setup_dummy2(pcmk__output_t *out) { - return NULL; + return; } int diff --git a/tools/crm_mon.h b/tools/crm_mon.h index eba01717f54..f1df66a1cd9 100644 --- a/tools/crm_mon.h +++ b/tools/crm_mon.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 the Pacemaker project contributors + * Copyright 2019-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -55,13 +55,14 @@ enum mon_exec_mode { void crm_mon_register_messages(pcmk__output_t *out); #if PCMK__ENABLE_CURSES -pcmk__output_t *crm_mon_mk_curses_output(char **argv); +void crm_mon_output_setup_curses(pcmk__output_t *out); void curses_formatted_printf(pcmk__output_t *out, const char *format, ...) G_GNUC_PRINTF(2, 3); void curses_formatted_vprintf(pcmk__output_t *out, const char *format, va_list args) G_GNUC_PRINTF(2, 0); void curses_indented_printf(pcmk__output_t *out, const char *format, ...) G_GNUC_PRINTF(2, 3); void curses_indented_vprintf(pcmk__output_t *out, const char *format, va_list args) G_GNUC_PRINTF(2, 0); -#define CRM_MON_SUPPORTED_FORMAT_CURSES { "console", crm_mon_mk_curses_output, NULL } +#define CRM_MON_SUPPORTED_FORMAT_CURSES \ + { "console", crm_mon_output_setup_curses, NULL } #endif #endif diff --git a/tools/crm_mon_curses.c b/tools/crm_mon_curses.c index 2732ac00eb4..7f14dd87f38 100644 --- a/tools/crm_mon_curses.c +++ b/tools/crm_mon_curses.c @@ -337,43 +337,32 @@ curses_prompt(const char *prompt, bool do_echo, char **dest) } } -pcmk__output_t * -crm_mon_mk_curses_output(char **argv) { - pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); - - if (retval == NULL) { - return NULL; - } - - retval->fmt_name = "console"; - retval->request = pcmk__quote_cmdline(argv); - - retval->init = curses_init; - retval->free_priv = curses_free_priv; - retval->finish = curses_finish; - retval->reset = curses_reset; - - retval->register_message = pcmk__register_message; - retval->message = pcmk__call_message; - - retval->subprocess_output = curses_subprocess_output; - retval->version = curses_ver; - retval->err = curses_error; - retval->info = curses_info; - retval->transient = curses_info; - retval->output_xml = curses_output_xml; - - retval->begin_list = curses_begin_list; - retval->list_item = curses_list_item; - retval->increment_list = curses_increment_list; - retval->end_list = curses_end_list; - - retval->is_quiet = curses_is_quiet; - retval->spacer = curses_spacer; - retval->progress = curses_progress; - retval->prompt = curses_prompt; - - return retval; +void +crm_mon_output_setup_curses(pcmk__output_t *out) +{ + out->fmt_name = "console"; + + out->init = curses_init; + out->free_priv = curses_free_priv; + out->finish = curses_finish; + out->reset = curses_reset; + + out->subprocess_output = curses_subprocess_output; + out->version = curses_ver; + out->err = curses_error; + out->info = curses_info; + out->transient = curses_info; + out->output_xml = curses_output_xml; + + out->begin_list = curses_begin_list; + out->list_item = curses_list_item; + out->increment_list = curses_increment_list; + out->end_list = curses_end_list; + + out->is_quiet = curses_is_quiet; + out->spacer = curses_spacer; + out->progress = curses_progress; + out->prompt = curses_prompt; } G_GNUC_PRINTF(2, 0) From ae65ba3af6ed72387f6efe616c8a442bb62bd3a6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:02:12 -0800 Subject: [PATCH 02/40] Refactor: libcrmcommon: Make pcmk__call_message() static Signed-off-by: Reid Wahl --- include/crm/common/output_internal.h | 15 ------- lib/common/output.c | 61 +++++++++++++++++----------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index 41a5e09b32e..56bfdbdec3d 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -535,21 +535,6 @@ struct pcmk__output_s { void (*prompt) (const char *prompt, bool echo, char **dest); }; -/*! - * \internal - * \brief Call a formatting function for a previously registered message. - * - * \note This function is for implementing custom formatters. It should not - * be called directly. Instead, call out->message. - * - * \param[in,out] out The output functions structure. - * \param[in] message_id The message to be handled. Unknown messages - * will be ignored. - * \param[in] ... Arguments to be passed to the registered function. - */ -int -pcmk__call_message(pcmk__output_t *out, const char *message_id, ...); - /*! * \internal * \brief Free a ::pcmk__output_t structure that was previously created by diff --git a/lib/common/output.c b/lib/common/output.c index 39f243cf13d..cf1c5a66d4c 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -50,6 +50,43 @@ pcmk__output_free(pcmk__output_t *out) { free(out); } +/*! + * \internal + * \brief Call a formatting function for a previously registered message + * + * \param[in,out] out Output object + * \param[in] message_id Message to handle + * \param[in] ... Arguments to be passed to the registered function + * + * \note This function is for implementing custom formatters. It should not + * be called directly. Instead, call out->message. + * + * \return Return value of the formatting function, or \c EINVAL if no + * formatting function is found + */ +static int +call_message(pcmk__output_t *out, const char *message_id, ...) +{ + va_list args; + int rc = pcmk_rc_ok; + pcmk__message_fn_t fn; + + pcmk__assert((out != NULL) && !pcmk__str_empty(message_id)); + + fn = g_hash_table_lookup(out->messages, message_id); + if (fn == NULL) { + pcmk__debug("Called unknown output message '%s' for format '%s'", + message_id, out->fmt_name); + return EINVAL; + } + + va_start(args, message_id); + rc = fn(out, args); + va_end(args); + + return rc; +} + /*! * \internal * \brief Create a new \p pcmk__output_t structure @@ -97,7 +134,7 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, (*out)->request = pcmk__quote_cmdline(argv); (*out)->register_message = pcmk__register_message; - (*out)->message = pcmk__call_message; + (*out)->message = call_message; if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) { (*out)->dest = stdout; @@ -189,28 +226,6 @@ pcmk__unregister_formats(void) { } } -int -pcmk__call_message(pcmk__output_t *out, const char *message_id, ...) { - va_list args; - int rc = pcmk_rc_ok; - pcmk__message_fn_t fn; - - pcmk__assert((out != NULL) && !pcmk__str_empty(message_id)); - - fn = g_hash_table_lookup(out->messages, message_id); - if (fn == NULL) { - pcmk__debug("Called unknown output message '%s' for format '%s'", - message_id, out->fmt_name); - return EINVAL; - } - - va_start(args, message_id); - rc = fn(out, args); - va_end(args); - - return rc; -} - void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn) From ad915d4f6c1a3fb7bc1d799bba33a9ee7ba9abcc Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:05:32 -0800 Subject: [PATCH 03/40] Refactor: libcrmcommon: Make pcmk__register_message() library-private It could be static, except that it has unit tests. Signed-off-by: Reid Wahl --- include/crm/common/output_internal.h | 15 --------------- lib/common/crmcommon_private.h | 4 ++++ lib/common/output.c | 11 +++++++++++ lib/common/tests/output/pcmk__output_free_test.c | 2 ++ .../tests/output/pcmk__register_message_test.c | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index 56bfdbdec3d..fb249d281f9 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -613,21 +613,6 @@ pcmk__register_formats(GOptionGroup *group, void pcmk__unregister_formats(void); -/*! - * \internal - * \brief Register a function to handle a custom message. - * - * \note This function is for implementing custom formatters. It should not - * be called directly. Instead, call out->register_message. - * - * \param[in,out] out The output functions structure. - * \param[in] message_id The message to be handled. - * \param[in] fn The custom format function to call for message_id. - */ -void -pcmk__register_message(pcmk__output_t *out, const char *message_id, - pcmk__message_fn_t fn); - /*! * \internal * \brief Register an entire table of custom formatting functions at once. diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 00354ad0846..2c5f974624d 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -358,6 +358,10 @@ G_GNUC_INTERNAL int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv); +G_GNUC_INTERNAL +void pcmk__register_message(pcmk__output_t *out, const char *message_id, + pcmk__message_fn_t fn); + G_GNUC_INTERNAL void pcmk__register_option_messages(pcmk__output_t *out); diff --git a/lib/common/output.c b/lib/common/output.c index cf1c5a66d4c..54f796d4dc2 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -226,6 +226,17 @@ pcmk__unregister_formats(void) { } } +/*! + * \internal + * \brief Register a function to handle a custom message + * + * \param[in,out] out Output object + * \param[in] message_id Message to handle + * \param[in] fn Format function to call for \p message_id + * + * \note This function is for implementing custom formatters. It should not + * be called directly. Instead, call out->register_message. + */ void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn) diff --git a/lib/common/tests/output/pcmk__output_free_test.c b/lib/common/tests/output/pcmk__output_free_test.c index e8555cc7126..669bab8e62a 100644 --- a/lib/common/tests/output/pcmk__output_free_test.c +++ b/lib/common/tests/output/pcmk__output_free_test.c @@ -13,6 +13,8 @@ #include +#include "../../crmcommon_private.h" // pcmk__register_message + static int setup(void **state) { diff --git a/lib/common/tests/output/pcmk__register_message_test.c b/lib/common/tests/output/pcmk__register_message_test.c index 381063ec6ab..ca0acb49789 100644 --- a/lib/common/tests/output/pcmk__register_message_test.c +++ b/lib/common/tests/output/pcmk__register_message_test.c @@ -13,7 +13,7 @@ #include -#include "../../crmcommon_private.h" +#include "../../crmcommon_private.h" // pcmk__register_message static void null_params(void **state) From 5fd72c4862be96cf9b4084bff46e4a1a4b9a9558 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:10:09 -0800 Subject: [PATCH 04/40] Refactor: libcrmcommon: Drop pcmk__output_t:register_message() Nothing uses it. pcmk__register_message() is always called directly. Most of the calls are in unit tests. The only other call is in pcmk__register_messages(). Considering that, it doesn't seem that we would gain much by calling it as a method of pcmk__output_t. Signed-off-by: Reid Wahl --- include/crm/common/output_internal.h | 16 +--------------- lib/common/output.c | 4 ---- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index fb249d281f9..f744d2687e0 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -301,20 +301,6 @@ struct pcmk__output_s { */ void (*reset) (pcmk__output_t *out); - /*! - * \internal - * \brief Register a custom message. - * - * \param[in,out] out The output functions structure. - * \param[in] message_id The name of the message to register. This name - * will be used as the message_id parameter to the - * message function in order to call the custom - * format function. - * \param[in] fn The custom format function to call for message_id. - */ - void (*register_message) (pcmk__output_t *out, const char *message_id, - pcmk__message_fn_t fn); - /*! * \internal * \brief Call a previously registered custom message. @@ -322,7 +308,7 @@ struct pcmk__output_s { * \param[in,out] out The output functions structure. * \param[in] message_id The name of the message to call. This name must * be the same as the message_id parameter of some - * previous call to register_message. + * previous call to \c pcmk__register_message(). * \param[in] ... Arguments to be passed to the registered function. * * \return A standard Pacemaker return code. Generally: 0 if a function was diff --git a/lib/common/output.c b/lib/common/output.c index 54f796d4dc2..96567c4383d 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -133,7 +133,6 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, setup_fn(*out); (*out)->request = pcmk__quote_cmdline(argv); - (*out)->register_message = pcmk__register_message; (*out)->message = call_message; if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) { @@ -233,9 +232,6 @@ pcmk__unregister_formats(void) { * \param[in,out] out Output object * \param[in] message_id Message to handle * \param[in] fn Format function to call for \p message_id - * - * \note This function is for implementing custom formatters. It should not - * be called directly. Instead, call out->register_message. */ void pcmk__register_message(pcmk__output_t *out, const char *message_id, From 7b439ebf0ee654145b94f1aeb9708e667ebc755e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 20:11:44 -0800 Subject: [PATCH 05/40] Refactor: libcrmcommon: pcmk__quote_cmdline() takes const char *const * This is unfortunately the way to make a double-const (char **) (that is, the top-level pointer and the next-level pointers are const). It also unfortunately requires explicit casts. That was the initial motivation for all of the output setup shuffling in previous commits. I wanted fewer calls to pcmk__quote_cmdline(). Signed-off-by: Reid Wahl --- include/crm/common/cmdline_internal.h | 13 +------------ lib/common/cmdline.c | 18 +++++++++++++++++- lib/common/output.c | 2 +- .../tests/cmdline/pcmk__quote_cmdline_test.c | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/crm/common/cmdline_internal.h b/include/crm/common/cmdline_internal.h index 0bfcd47333e..d0b8d0d78af 100644 --- a/include/crm/common/cmdline_internal.h +++ b/include/crm/common/cmdline_internal.h @@ -106,18 +106,7 @@ void pcmk__add_arg_group(GOptionContext *context, const char *name, const char *header, const char *desc, const GOptionEntry entries[]); -/*! - * \internal - * \brief Prepare the command line for being added to a pcmk__output_t as the - * request - * - * This performs various transformations on the command line arguments, such - * as surrounding arguments containing spaces with quotes and escaping any - * single quotes in the string. - * - * \param[in,out] argv Command line (typically from pcmk__cmdline_preproc()) - */ -gchar *pcmk__quote_cmdline(gchar **argv); +gchar *pcmk__quote_cmdline(const char *const *argv); /*! * \internal diff --git a/lib/common/cmdline.c b/lib/common/cmdline.c index 656360c55ed..f7c008e30d7 100644 --- a/lib/common/cmdline.c +++ b/lib/common/cmdline.c @@ -143,8 +143,24 @@ pcmk__add_arg_group(GOptionContext *context, const char *name, // group is now owned by context, we don't free it here } +/*! + * \internal + * \brief Prepare a command line to add to a \c pcmk__output_t as the request + * + * This performs various transformations on the command line arguments, such + * as surrounding arguments containing spaces with quotes and escaping any + * single quotes in the string. + * + * \param[in] argv Command line (typically from \c pcmk__cmdline_preproc()) + * + * \return Newly allocated command line suitable for use as the + * \c PCMK_XA_REQUEST attribute value in XML output + * + * \note The caller is responsible for freeing the return value using + * \c g_free(). + */ gchar * -pcmk__quote_cmdline(gchar **argv) +pcmk__quote_cmdline(const char *const *argv) { GString *cmdline = NULL; diff --git a/lib/common/output.c b/lib/common/output.c index 96567c4383d..58f968581f7 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -132,7 +132,7 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, setup_fn(*out); - (*out)->request = pcmk__quote_cmdline(argv); + (*out)->request = pcmk__quote_cmdline((const char *const *) argv); (*out)->message = call_message; if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) { diff --git a/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c index ae09f076e4c..3392ed490a1 100644 --- a/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c +++ b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c @@ -21,7 +21,7 @@ static void assert_quote_cmdline(const char **argv, const gchar *expected_single, const gchar *expected_double) { - gchar *processed = pcmk__quote_cmdline((gchar **) argv); + gchar *processed = pcmk__quote_cmdline((const char *const *) argv); assert_true(pcmk__str_any_of(processed, expected_single, expected_double, NULL)); From 5839372f7f0bd5e8b8bea760289336bbd9e9a190 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 20:09:27 -0800 Subject: [PATCH 06/40] Refactor: libcrmcommon: pcmk__bare_output_new takes const char *const * Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 2 +- lib/common/output.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 2c5f974624d..4810961ffc4 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -356,7 +356,7 @@ pcmk__ipc_methods_t *pcmk__schedulerd_api_methods(void); */ G_GNUC_INTERNAL int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, - const char *filename, char **argv); + const char *filename, const char *const *argv); G_GNUC_INTERNAL void pcmk__register_message(pcmk__output_t *out, const char *message_id, diff --git a/lib/common/output.c b/lib/common/output.c index 58f968581f7..9f2cc2ee293 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -106,7 +106,7 @@ call_message(pcmk__output_t *out, const char *message_id, ...) */ int pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, - const char *filename, char **argv) + const char *filename, const char *const *argv) { pcmk__output_setup_fn_t setup_fn = NULL; @@ -132,7 +132,7 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, setup_fn(*out); - (*out)->request = pcmk__quote_cmdline((const char *const *) argv); + (*out)->request = pcmk__quote_cmdline(argv); (*out)->message = call_message; if (pcmk__str_eq(filename, "-", pcmk__str_null_matches)) { @@ -163,7 +163,8 @@ int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, const char *filename, char **argv) { - int rc = pcmk__bare_output_new(out, fmt_name, filename, argv); + int rc = pcmk__bare_output_new(out, fmt_name, filename, + (const char *const *) argv); if (rc == pcmk_rc_ok) { // Register libcrmcommon messages From 60c3fa0accb2cdc0e03f17ab9f391eb38d776a07 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 20:23:04 -0800 Subject: [PATCH 07/40] Refactor: libcrmcommon: pcmk__output_new() takes const char *const * Signed-off-by: Reid Wahl --- daemons/attrd/pacemaker-attrd.c | 3 ++- daemons/based/pacemaker-based.c | 3 ++- daemons/controld/pacemaker-controld.c | 3 ++- daemons/execd/pacemaker-execd.c | 3 ++- daemons/fenced/pacemaker-fenced.c | 3 ++- daemons/pacemakerd/pacemakerd.c | 3 ++- daemons/schedulerd/pacemaker-schedulerd.c | 3 ++- include/crm/common/output_internal.h | 2 +- lib/cib/cib_attrs.c | 2 +- lib/common/output.c | 13 ++++++------- tools/attrd_updater.c | 3 ++- tools/cibadmin.c | 3 ++- tools/cibsecret.c | 3 ++- tools/crm_attribute.c | 3 ++- tools/crm_diff.c | 3 ++- tools/crm_error.c | 3 ++- tools/crm_mon.c | 3 ++- tools/crm_node.c | 3 ++- tools/crm_resource.c | 3 ++- tools/crm_rule.c | 3 ++- tools/crm_shadow.c | 3 ++- tools/crm_simulate.c | 3 ++- tools/crm_ticket.c | 3 ++- tools/crm_verify.c | 3 ++- tools/crmadmin.c | 3 ++- tools/iso8601.c | 3 ++- tools/stonith_admin.c | 3 ++- 27 files changed, 56 insertions(+), 33 deletions(-) diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 461cb75a66e..ee0c9e4193a 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -112,7 +112,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if ((rc != pcmk_rc_ok) || (out == NULL)) { attrd_exit_status = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, attrd_exit_status, diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index 888a1f91a77..3b13feb3545 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -184,7 +184,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/daemons/controld/pacemaker-controld.c b/daemons/controld/pacemaker-controld.c index 84442c93e2c..8948477a861 100644 --- a/daemons/controld/pacemaker-controld.c +++ b/daemons/controld/pacemaker-controld.c @@ -90,7 +90,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/daemons/execd/pacemaker-execd.c b/daemons/execd/pacemaker-execd.c index 0dcf38a43f0..05da4ad822a 100644 --- a/daemons/execd/pacemaker-execd.c +++ b/daemons/execd/pacemaker-execd.c @@ -355,7 +355,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index df9ebbe9990..b169b3a8344 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -370,7 +370,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c index 85487f914de..6edfa6d0fcc 100644 --- a/daemons/pacemakerd/pacemakerd.c +++ b/daemons/pacemakerd/pacemakerd.c @@ -363,7 +363,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if ((rc != pcmk_rc_ok) || (out == NULL)) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/daemons/schedulerd/pacemaker-schedulerd.c b/daemons/schedulerd/pacemaker-schedulerd.c index 2fa0e0c4cbe..0da6b6b7388 100644 --- a/daemons/schedulerd/pacemaker-schedulerd.c +++ b/daemons/schedulerd/pacemaker-schedulerd.c @@ -98,7 +98,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if ((rc != pcmk_rc_ok) || (out == NULL)) { exit_code = CRM_EX_FATAL; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index f744d2687e0..d7120debf95 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -552,7 +552,7 @@ void pcmk__output_free(pcmk__output_t *out); * \return Standard Pacemaker return code */ int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, - const char *filename, char **argv); + const char *filename, const char *const *argv); /*! * \internal diff --git a/lib/cib/cib_attrs.c b/lib/cib/cib_attrs.c index 1a2de1c5c17..23f1726dbfa 100644 --- a/lib/cib/cib_attrs.c +++ b/lib/cib/cib_attrs.c @@ -39,7 +39,7 @@ new_output_object(const char *ty) }; pcmk__register_formats(NULL, formats); - rc = pcmk__output_new(&out, ty, NULL, (char**)argv); + rc = pcmk__output_new(&out, ty, NULL, argv); if ((rc != pcmk_rc_ok) || (out == NULL)) { pcmk__err("Can't out due to internal error: %s", pcmk_rc_str(rc)); return NULL; diff --git a/lib/common/output.c b/lib/common/output.c index 9f2cc2ee293..259b1f84761 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -161,10 +161,9 @@ pcmk__bare_output_new(pcmk__output_t **out, const char *fmt_name, int pcmk__output_new(pcmk__output_t **out, const char *fmt_name, - const char *filename, char **argv) + const char *filename, const char *const *argv) { - int rc = pcmk__bare_output_new(out, fmt_name, filename, - (const char *const *) argv); + int rc = pcmk__bare_output_new(out, fmt_name, filename, argv); if (rc == pcmk_rc_ok) { // Register libcrmcommon messages @@ -333,14 +332,14 @@ int pcmk__log_output_new(pcmk__output_t **out) { int rc = pcmk_rc_ok; - const char* argv[] = { "", NULL }; + const char *argv[] = { "", NULL }; pcmk__supported_format_t formats[] = { PCMK__SUPPORTED_FORMAT_LOG, { NULL, NULL, NULL } }; pcmk__register_formats(NULL, formats); - rc = pcmk__output_new(out, "log", NULL, (char **) argv); + rc = pcmk__output_new(out, "log", NULL, argv); if ((rc != pcmk_rc_ok) || (*out == NULL)) { pcmk__err("Can't log certain messages due to internal error: %s", pcmk_rc_str(rc)); @@ -362,14 +361,14 @@ int pcmk__text_output_new(pcmk__output_t **out, const char *filename) { int rc = pcmk_rc_ok; - const char* argv[] = { "", NULL }; + const char *argv[] = { "", NULL }; pcmk__supported_format_t formats[] = { PCMK__SUPPORTED_FORMAT_TEXT, { NULL, NULL, NULL } }; pcmk__register_formats(NULL, formats); - rc = pcmk__output_new(out, "text", filename, (char **) argv); + rc = pcmk__output_new(out, "text", filename, argv); if ((rc != pcmk_rc_ok) || (*out == NULL)) { pcmk__err("Can't create text output object to internal error: %s", pcmk_rc_str(rc)); diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c index 6dca3a51f91..1dc1fd6f779 100644 --- a/tools/attrd_updater.c +++ b/tools/attrd_updater.c @@ -304,7 +304,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("attrd_updater", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/tools/cibadmin.c b/tools/cibadmin.c index fc20bdea950..ab960cd4887 100644 --- a/tools/cibadmin.c +++ b/tools/cibadmin.c @@ -1099,7 +1099,8 @@ main(int argc, char **argv) } } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/cibsecret.c b/tools/cibsecret.c index 8a20ad436ed..bb463f0f514 100644 --- a/tools/cibsecret.c +++ b/tools/cibsecret.c @@ -1115,7 +1115,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("cibsecret", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_attribute.c b/tools/crm_attribute.c index c7de7b71376..bc0c5338e20 100644 --- a/tools/crm_attribute.c +++ b/tools/crm_attribute.c @@ -765,7 +765,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_attribute", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/tools/crm_diff.c b/tools/crm_diff.c index 8661ec6c77c..13d291fb655 100644 --- a/tools/crm_diff.c +++ b/tools/crm_diff.c @@ -262,7 +262,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_diff", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_error.c b/tools/crm_error.c index 8a0d2f1dde8..9f968a9c9de 100644 --- a/tools/crm_error.c +++ b/tools/crm_error.c @@ -98,7 +98,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_error", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_mon.c b/tools/crm_mon.c index ab42c3bac96..8d77d45813b 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -1447,7 +1447,8 @@ main(int argc, char **argv) reconcile_output_format(args); set_default_exec_mode(args); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_ERROR, "Error creating output format %s: %s", diff --git a/tools/crm_node.c b/tools/crm_node.c index 0a89e7f3cb6..ca74b617c52 100644 --- a/tools/crm_node.c +++ b/tools/crm_node.c @@ -792,7 +792,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_node", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = pcmk_rc2exitc(rc); g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_resource.c b/tools/crm_resource.c index bbcd5f77738..69f591be740 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -2086,7 +2086,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_resource", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, _("Error creating output format %s: %s"), diff --git a/tools/crm_rule.c b/tools/crm_rule.c index bf22b197c3b..b0150937788 100644 --- a/tools/crm_rule.c +++ b/tools/crm_rule.c @@ -120,7 +120,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_rule", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/tools/crm_shadow.c b/tools/crm_shadow.c index 890994815de..2df4ed0ae85 100644 --- a/tools/crm_shadow.c +++ b/tools/crm_shadow.c @@ -1196,7 +1196,8 @@ main(int argc, char **argv) goto done; } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_simulate.c b/tools/crm_simulate.c index 6f08a917f44..9af843c3cee 100644 --- a/tools/crm_simulate.c +++ b/tools/crm_simulate.c @@ -482,7 +482,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_simulate", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { fprintf(stderr, "Error creating output format %s: %s\n", args->output_ty, pcmk_rc_str(rc)); diff --git a/tools/crm_ticket.c b/tools/crm_ticket.c index 428a59524e9..3643d04ca14 100644 --- a/tools/crm_ticket.c +++ b/tools/crm_ticket.c @@ -369,7 +369,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_ticket", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = pcmk_rc2exitc(rc); g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crm_verify.c b/tools/crm_verify.c index 145fb1d0220..bae40385284 100644 --- a/tools/crm_verify.c +++ b/tools/crm_verify.c @@ -193,7 +193,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crm_verify", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/crmadmin.c b/tools/crmadmin.c index 62b8aadcdfc..121928c6dcd 100644 --- a/tools/crmadmin.c +++ b/tools/crmadmin.c @@ -189,7 +189,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("crmadmin", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", diff --git a/tools/iso8601.c b/tools/iso8601.c index d8d0a1a7f8a..c3126fe89c6 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -333,7 +333,8 @@ main(int argc, char **argv) pcmk__cli_init_logging("iso8601", args->verbosity); - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = pcmk_rc2exitc(rc); g_set_error(&error, PCMK__EXITC_ERROR, exit_code, diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c index 431f4705b70..7d0d96f9faa 100644 --- a/tools/stonith_admin.c +++ b/tools/stonith_admin.c @@ -422,7 +422,8 @@ main(int argc, char **argv) name = strdup(crm_system_name); } - rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); + rc = pcmk__output_new(&out, args->output_ty, args->output_dest, + (const char *const *) argv); if (rc != pcmk_rc_ok) { exit_code = CRM_EX_ERROR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s", From 197688487ccb1dac505ccc7acd561209dd01fcb1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 22:45:23 -0800 Subject: [PATCH 08/40] Low: libcrmcommon: Avoid memory leak in assert_hr_format() Signed-off-by: Reid Wahl --- lib/common/tests/iso8601/pcmk__time_format_hr_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index ead23e9c8fc..d1796ad29e7 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -63,6 +63,7 @@ assert_hr_format(const char *format, const char *expected, || (strcmp(result, alternate) == 0)); } + crm_time_free(dt); free(result); } From cc1639bda655b4ae8d78d98528ec3d5f08837259 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 22:31:34 -0800 Subject: [PATCH 09/40] Refactor: libcrmcommon: New assert_hr_format_usec() This is a step toward converting the assertion helper into macros. We'll need multiple macros to avoid complaints from the compiler or Coverity about NULL arguments, always-true/always-false conditions, etc. Signed-off-by: Reid Wahl --- .../tests/iso8601/pcmk__time_format_hr_test.c | 71 +++++++++++++------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index d1796ad29e7..5693d932a35 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -67,6 +67,31 @@ assert_hr_format(const char *format, const char *expected, free(result); } +/*! + * \internal + * \brief Check that \c pcmk__time_format_hr() produced expected high-res result + * + * \param[in] format Time format string + * \param[in] expected Check succeeds if result matches this + * \param[in] usec Microseconds component of the reference time + */ +static void +assert_hr_format_usec(const char *format, const char *expected, int usec) +{ + crm_time_t *dt = NULL; + char *result = NULL; + + dt = crm_time_new(DATE_TIME_S); + assert_non_null(dt); + + result = pcmk__time_format_hr(format, dt, usec); + assert_non_null(result); + assert_string_equal(result, expected); + + crm_time_free(dt); + free(result); +} + static void null_format(void **state) { @@ -145,34 +170,34 @@ with_frac(void **state) "The time is " TIME_S ".000000 right NOW", NULL, 0); // Display at appropriate resolution by truncating toward zero - assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".123456", NULL, - usec); - assert_hr_format("%H:%M:%S.%6N", TIME_S ".123456", NULL, usec); - assert_hr_format("%H:%M:%S.%6N %M", TIME_S ".123456 " MINUTE_S, NULL, usec); - assert_hr_format("%H:%M:%S.%5N", TIME_S ".12345", NULL, usec); - assert_hr_format("%H:%M:%S.%4N", TIME_S ".1234", NULL, usec); - assert_hr_format("%H:%M:%S.%3N", TIME_S ".123", NULL, usec); - assert_hr_format("%H:%M:%S.%2N", TIME_S ".12", NULL, usec); - assert_hr_format("%H:%M:%S.%1N", TIME_S ".1", NULL, usec); - assert_hr_format("%H:%M:%S.%0N", TIME_S ".", NULL, usec); - assert_hr_format("%H:%M:%S.%N", TIME_S ".", NULL, usec); + assert_hr_format_usec("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".123456", + usec); + assert_hr_format_usec("%H:%M:%S.%6N", TIME_S ".123456", usec); + assert_hr_format_usec("%H:%M:%S.%6N %M", TIME_S ".123456 " MINUTE_S, usec); + assert_hr_format_usec("%H:%M:%S.%5N", TIME_S ".12345", usec); + assert_hr_format_usec("%H:%M:%S.%4N", TIME_S ".1234", usec); + assert_hr_format_usec("%H:%M:%S.%3N", TIME_S ".123", usec); + assert_hr_format_usec("%H:%M:%S.%2N", TIME_S ".12", usec); + assert_hr_format_usec("%H:%M:%S.%1N", TIME_S ".1", usec); + assert_hr_format_usec("%H:%M:%S.%0N", TIME_S ".", usec); + assert_hr_format_usec("%H:%M:%S.%N", TIME_S ".", usec); // Leading zero is ignored, not treated as a request for zero-padding - assert_hr_format("%H:%M:%S.%03N", TIME_S ".123", NULL, usec); + assert_hr_format_usec("%H:%M:%S.%03N", TIME_S ".123", usec); // Same as above, but with zero-padding for smaller fractional components usec = 789; - assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000789", NULL, - usec); - assert_hr_format("%H:%M:%S.%6N", TIME_S ".000789", NULL, usec); - assert_hr_format("%H:%M:%S.%6N %S", TIME_S ".000789 " SECOND_S, NULL, usec); - assert_hr_format("%H:%M:%S.%5N", TIME_S ".00078", NULL, usec); - assert_hr_format("%H:%M:%S.%4N", TIME_S ".0007", NULL, usec); - assert_hr_format("%H:%M:%S.%3N", TIME_S ".000", NULL, usec); - assert_hr_format("%H:%M:%S.%2N", TIME_S ".00", NULL, usec); - assert_hr_format("%H:%M:%S.%1N", TIME_S ".0", NULL, usec); - assert_hr_format("%H:%M:%S.%0N", TIME_S ".", NULL, usec); - assert_hr_format("%H:%M:%S.%N", TIME_S ".", NULL, usec); + assert_hr_format_usec("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000789", + usec); + assert_hr_format_usec("%H:%M:%S.%6N", TIME_S ".000789", usec); + assert_hr_format_usec("%H:%M:%S.%6N %S", TIME_S ".000789 " SECOND_S, usec); + assert_hr_format_usec("%H:%M:%S.%5N", TIME_S ".00078", usec); + assert_hr_format_usec("%H:%M:%S.%4N", TIME_S ".0007", usec); + assert_hr_format_usec("%H:%M:%S.%3N", TIME_S ".000", usec); + assert_hr_format_usec("%H:%M:%S.%2N", TIME_S ".00", usec); + assert_hr_format_usec("%H:%M:%S.%1N", TIME_S ".0", usec); + assert_hr_format_usec("%H:%M:%S.%0N", TIME_S ".", usec); + assert_hr_format_usec("%H:%M:%S.%N", TIME_S ".", usec); } PCMK__UNIT_TEST(NULL, NULL, From ef295183ad79431d9dc835fdbe58751865eed121 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 22:36:23 -0800 Subject: [PATCH 10/40] Refactor: libcrmcommon: Drop usec arg from assert_hr_format() Signed-off-by: Reid Wahl --- .../tests/iso8601/pcmk__time_format_hr_test.c | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index 5693d932a35..24c46280e32 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -33,21 +33,20 @@ * \param[in] expected Assertion succeeds if result matches this * \param[in] alternate If this is not NULL, assertion may also succeed if * result matches this - * \param[in] usec Microseconds component of the reference time * * \note This allows two possible results because different strftime() * implementations handle certain format syntax differently. */ static void assert_hr_format(const char *format, const char *expected, - const char *alternate, int usec) + const char *alternate) { crm_time_t *dt = crm_time_new(DATE_TIME_S); char *result = NULL; assert_non_null(dt); - result = pcmk__time_format_hr(format, dt, usec); + result = pcmk__time_format_hr(format, dt, 0); if (expected == NULL) { assert_null(result); @@ -98,13 +97,13 @@ null_format(void **state) assert_null(pcmk__time_format_hr(NULL, NULL, 0)); // For pcmk__time_format_hr(NULL, dt, 0) - assert_hr_format(NULL, NULL, NULL, 0); + assert_hr_format(NULL, NULL, NULL); } static void no_specifiers(void **state) { - assert_hr_format("no specifiers", "no specifiers", NULL, 0); + assert_hr_format("no specifiers", "no specifiers", NULL); /* @COMPAT The following four tests will fail when we remove the fallback * to strftime(). g_date_time_format() requires a literal '%' to be escaped @@ -113,44 +112,43 @@ no_specifiers(void **state) assert_hr_format("this has a literal % in it", "this has a literal % in it", // *BSD strftime() strips single % - "this has a literal in it", 0); + "this has a literal in it"); assert_hr_format("this has a literal %01 in it", "this has a literal %01 in it", // *BSD strftime() strips %0 - "this has a literal 1 in it", 0); + "this has a literal 1 in it"); assert_hr_format("%2 this starts and ends with %", "%2 this starts and ends with %", // *BSD strftime() strips % in front of nonzero number - "2 this starts and ends with %", 0); + "2 this starts and ends with %"); /* strftime() treats % with a number (and no specifier) as a literal string * to be formatted with a field width (undocumented and probably a bug ...) */ assert_hr_format("this ends with %10", "this ends with %10", // *BSD strftime() strips % in front of nonzero number - "this ends with 10", 0); + "this ends with 10"); } static void without_frac(void **state) { - assert_hr_format("%Y-%m-%d %H:%M:%S", DATE_S " " TIME_S, NULL, 0); + assert_hr_format("%Y-%m-%d %H:%M:%S", DATE_S " " TIME_S, NULL); - assert_hr_format("%H:%M %a %b %d", HOUR_S ":" MINUTE_S " Sun Jun 02", NULL, - 0); - assert_hr_format("%H:%M:%S", TIME_S, NULL, 0); + assert_hr_format("%H:%M %a %b %d", HOUR_S ":" MINUTE_S " Sun Jun 02", NULL); + assert_hr_format("%H:%M:%S", TIME_S, NULL); assert_hr_format("The time is %H:%M right now", - "The time is " HOUR_S ":" MINUTE_S " right now", NULL, 0); + "The time is " HOUR_S ":" MINUTE_S " right now", NULL); /* @COMPAT This test will fail when we remove the fallback to strftime(). * g_date_time_format() doesn't support field widths. + * + * BSD strftime() also doesn't support field widths, hence the alternate. */ - assert_hr_format("%3S seconds", "0" SECOND_S " seconds", - // *BSD strftime() doesn't support field widths - "3S seconds", 0); + assert_hr_format("%3S seconds", "0" SECOND_S " seconds", "3S seconds"); // strftime() treats %% as a literal % - assert_hr_format("%%H %%N", "%H %N", NULL, 0); + assert_hr_format("%%H %%N", "%H %N", NULL); } static void @@ -159,15 +157,15 @@ with_frac(void **state) int usec = 123456; // Display time with no fractional seconds component - assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000000", NULL, - 0); - assert_hr_format("%H:%M:%S.%6N", TIME_S ".000000", NULL, 0); - assert_hr_format("%H:%M:%S.%6N %H", TIME_S ".000000 " HOUR_S, NULL, 0); - assert_hr_format("%H:%M:%S.%3N", TIME_S ".000", NULL, 0); - assert_hr_format("%H:%M:%S.%0N", TIME_S ".", NULL, 0); - assert_hr_format("%H:%M:%S.%N", TIME_S ".", NULL, 0); + assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000000", + NULL); + assert_hr_format("%H:%M:%S.%6N", TIME_S ".000000", NULL); + assert_hr_format("%H:%M:%S.%6N %H", TIME_S ".000000 " HOUR_S, NULL); + assert_hr_format("%H:%M:%S.%3N", TIME_S ".000", NULL); + assert_hr_format("%H:%M:%S.%0N", TIME_S ".", NULL); + assert_hr_format("%H:%M:%S.%N", TIME_S ".", NULL); assert_hr_format("The time is %H:%M:%S.%06N right NOW", - "The time is " TIME_S ".000000 right NOW", NULL, 0); + "The time is " TIME_S ".000000 right NOW", NULL); // Display at appropriate resolution by truncating toward zero assert_hr_format_usec("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".123456", From 70b5f71d2d97c60b77daf1e8611e5ce08986799f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 22:44:34 -0800 Subject: [PATCH 11/40] Refactor: libcrmcommon: Drop NULL-check of expected in assert_hr_format Signed-off-by: Reid Wahl --- .../tests/iso8601/pcmk__time_format_hr_test.c | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index 24c46280e32..cb928e27145 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -41,18 +41,13 @@ static void assert_hr_format(const char *format, const char *expected, const char *alternate) { - crm_time_t *dt = crm_time_new(DATE_TIME_S); + crm_time_t *dt = NULL; char *result = NULL; + dt = crm_time_new(DATE_TIME_S); assert_non_null(dt); result = pcmk__time_format_hr(format, dt, 0); - - if (expected == NULL) { - assert_null(result); - return; - } - assert_non_null(result); if (alternate == NULL) { @@ -94,10 +89,20 @@ assert_hr_format_usec(const char *format, const char *expected, int usec) static void null_format(void **state) { + crm_time_t *dt = NULL; + char *result = NULL; + + // NULL format and NULL crm_time_t assert_null(pcmk__time_format_hr(NULL, NULL, 0)); - // For pcmk__time_format_hr(NULL, dt, 0) - assert_hr_format(NULL, NULL, NULL); + // NULL format and non-NULL crm_time_t + dt = crm_time_new(DATE_TIME_S); + assert_non_null(dt); + + result = pcmk__time_format_hr(NULL, dt, 0); + assert_null(result); + + free(dt); } static void From 55c5ebca8a5a571ff9fd2b47d425b1f4a033764d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 23:01:07 -0800 Subject: [PATCH 12/40] Refactor: libcrmcommon: New assert_hr_format_alt() This is a step toward converting the assertion helpers into macros. We'll need multiple macros to avoid complaints from the compiler or Coverity about NULL arguments, always-true/always-false conditions, etc. In this case we could probably use variadic arguments, but the error messages on failed assertions would be less clear. At best, we could show that the result is not equal to the last expected string (the alternate). Signed-off-by: Reid Wahl --- .../tests/iso8601/pcmk__time_format_hr_test.c | 106 +++++++++++------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index cb928e27145..c26325a5301 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -27,19 +27,43 @@ /*! * \internal - * \brief Assert that pcmk__time_format_hr() produced expected result + * \brief Check that \c pcmk__time_format_hr() produced expected result + * + * \param[in] format Time format string + * \param[in] expected Check succeeds if result matches this + */ +static void +assert_hr_format(const char *format, const char *expected) +{ + crm_time_t *dt = NULL; + char *result = NULL; + + dt = crm_time_new(DATE_TIME_S); + assert_non_null(dt); + + result = pcmk__time_format_hr(format, dt, 0); + assert_non_null(result); + + assert_string_equal(result, expected); + + crm_time_free(dt); + free(result); +} + +/*! + * \internal + * \brief Check that \c pcmk__time_format_hr() produced expected result (or alt) * * \param[in] format Time format string - * \param[in] expected Assertion succeeds if result matches this - * \param[in] alternate If this is not NULL, assertion may also succeed if - * result matches this + * \param[in] expected Check succeeds if result matches this + * \param[in] alternate Check also succeeds if result matches this * - * \note This allows two possible results because different strftime() + * \note This allows two possible results because different \c strftime() * implementations handle certain format syntax differently. */ static void -assert_hr_format(const char *format, const char *expected, - const char *alternate) +assert_hr_format_alt(const char *format, const char *expected, + const char *alternate) { crm_time_t *dt = NULL; char *result = NULL; @@ -50,12 +74,9 @@ assert_hr_format(const char *format, const char *expected, result = pcmk__time_format_hr(format, dt, 0); assert_non_null(result); - if (alternate == NULL) { - assert_string_equal(result, expected); - } else { - assert_true((strcmp(result, expected) == 0) - || (strcmp(result, alternate) == 0)); - } + // CMocka has no abstraction for comparing to multiple strings + assert_true((strcmp(result, expected) == 0) + || (strcmp(result, alternate) == 0)); crm_time_free(dt); free(result); @@ -108,52 +129,52 @@ null_format(void **state) static void no_specifiers(void **state) { - assert_hr_format("no specifiers", "no specifiers", NULL); + assert_hr_format("no specifiers", "no specifiers"); /* @COMPAT The following four tests will fail when we remove the fallback * to strftime(). g_date_time_format() requires a literal '%' to be escaped * as "%%". */ - assert_hr_format("this has a literal % in it", - "this has a literal % in it", - // *BSD strftime() strips single % - "this has a literal in it"); - assert_hr_format("this has a literal %01 in it", - "this has a literal %01 in it", - // *BSD strftime() strips %0 - "this has a literal 1 in it"); - assert_hr_format("%2 this starts and ends with %", - "%2 this starts and ends with %", - // *BSD strftime() strips % in front of nonzero number - "2 this starts and ends with %"); + assert_hr_format_alt("this has a literal % in it", + "this has a literal % in it", + // *BSD strftime() strips single % + "this has a literal in it"); + assert_hr_format_alt("this has a literal %01 in it", + "this has a literal %01 in it", + // *BSD strftime() strips %0 + "this has a literal 1 in it"); + assert_hr_format_alt("%2 this starts and ends with %", + "%2 this starts and ends with %", + // *BSD strftime() strips % in front of nonzero number + "2 this starts and ends with %"); /* strftime() treats % with a number (and no specifier) as a literal string * to be formatted with a field width (undocumented and probably a bug ...) */ - assert_hr_format("this ends with %10", "this ends with %10", - // *BSD strftime() strips % in front of nonzero number - "this ends with 10"); + assert_hr_format_alt("this ends with %10", "this ends with %10", + // *BSD strftime() strips % in front of nonzero number + "this ends with 10"); } static void without_frac(void **state) { - assert_hr_format("%Y-%m-%d %H:%M:%S", DATE_S " " TIME_S, NULL); + assert_hr_format("%Y-%m-%d %H:%M:%S", DATE_S " " TIME_S); - assert_hr_format("%H:%M %a %b %d", HOUR_S ":" MINUTE_S " Sun Jun 02", NULL); - assert_hr_format("%H:%M:%S", TIME_S, NULL); + assert_hr_format("%H:%M %a %b %d", HOUR_S ":" MINUTE_S " Sun Jun 02"); + assert_hr_format("%H:%M:%S", TIME_S); assert_hr_format("The time is %H:%M right now", - "The time is " HOUR_S ":" MINUTE_S " right now", NULL); + "The time is " HOUR_S ":" MINUTE_S " right now"); /* @COMPAT This test will fail when we remove the fallback to strftime(). * g_date_time_format() doesn't support field widths. * * BSD strftime() also doesn't support field widths, hence the alternate. */ - assert_hr_format("%3S seconds", "0" SECOND_S " seconds", "3S seconds"); + assert_hr_format_alt("%3S seconds", "0" SECOND_S " seconds", "3S seconds"); // strftime() treats %% as a literal % - assert_hr_format("%%H %%N", "%H %N", NULL); + assert_hr_format("%%H %%N", "%H %N"); } static void @@ -162,15 +183,14 @@ with_frac(void **state) int usec = 123456; // Display time with no fractional seconds component - assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000000", - NULL); - assert_hr_format("%H:%M:%S.%6N", TIME_S ".000000", NULL); - assert_hr_format("%H:%M:%S.%6N %H", TIME_S ".000000 " HOUR_S, NULL); - assert_hr_format("%H:%M:%S.%3N", TIME_S ".000", NULL); - assert_hr_format("%H:%M:%S.%0N", TIME_S ".", NULL); - assert_hr_format("%H:%M:%S.%N", TIME_S ".", NULL); + assert_hr_format("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".000000"); + assert_hr_format("%H:%M:%S.%6N", TIME_S ".000000"); + assert_hr_format("%H:%M:%S.%6N %H", TIME_S ".000000 " HOUR_S); + assert_hr_format("%H:%M:%S.%3N", TIME_S ".000"); + assert_hr_format("%H:%M:%S.%0N", TIME_S "."); + assert_hr_format("%H:%M:%S.%N", TIME_S "."); assert_hr_format("The time is %H:%M:%S.%06N right NOW", - "The time is " TIME_S ".000000 right NOW", NULL); + "The time is " TIME_S ".000000 right NOW"); // Display at appropriate resolution by truncating toward zero assert_hr_format_usec("%Y-%m-%d %H:%M:%S.%6N", DATE_S " " TIME_S ".123456", From 514e81ba06aab620014de3a1afb5fab7251c173f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 01:04:55 -0800 Subject: [PATCH 13/40] Refactor: libcrmcommon: Drop assert_lookup_user() name argument Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__lookup_user_test.c | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index 962d3adfb85..1718dc3f9bf 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -21,9 +21,8 @@ /*! * \internal - * \brief Perform one test of \c pcmk__lookup_user() + * \brief Perform one test of \c pcmk__lookup_user() with name \c "hauser" * - * \param[in] name \c name argument for \c pcmk__lookup_user() * \param[in] uid \c uid argument for \c pcmk__lookup_user() * (unchanged upon return) * \param[in] gid \c gid argument for \c pcmk__lookup_user() @@ -35,13 +34,13 @@ * \c pcmk__lookup_user() call */ static void -assert_lookup_user(const char *name, uid_t *uid, gid_t *gid, int expected_rc, - uid_t expected_uid, gid_t expected_gid) +assert_lookup_user(uid_t *uid, gid_t *gid, int expected_rc, uid_t expected_uid, + gid_t expected_gid) { uid_t uid_orig = ((uid != NULL)? *uid : 0); gid_t gid_orig = ((gid != NULL)? *gid : 0); - assert_int_equal(pcmk__lookup_user(name, uid, gid), expected_rc); + assert_int_equal(pcmk__lookup_user("hauser", uid, gid), expected_rc); if (uid != NULL) { assert_int_equal(*uid, expected_uid); @@ -60,10 +59,17 @@ null_name(void **state) gid_t gid = 0; // These dump core via CRM_CHECK() - assert_lookup_user(NULL, NULL, NULL, EINVAL, 0, 0); - assert_lookup_user(NULL, NULL, &gid, EINVAL, 0, 0); - assert_lookup_user(NULL, &uid, NULL, EINVAL, 0, 0); - assert_lookup_user(NULL, &uid, &gid, EINVAL, 0, 0); + assert_int_equal(pcmk__lookup_user(NULL, NULL, NULL), EINVAL); + + assert_int_equal(pcmk__lookup_user(NULL, &uid, 0), EINVAL); + assert_int_equal(uid, 0); + + assert_int_equal(pcmk__lookup_user(NULL, NULL, &gid), EINVAL); + assert_int_equal(gid, 0); + + assert_int_equal(pcmk__lookup_user(NULL, &uid, &gid), EINVAL); + assert_int_equal(uid, 0); + assert_int_equal(gid, 0); } static void @@ -77,7 +83,7 @@ getpwnam_fails(void **state) expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, EIO); // errno will_return(__wrap_getpwnam, NULL); // return value - assert_lookup_user("hauser", &uid, &gid, EIO, 0, 0); + assert_lookup_user(&uid, &gid, EIO, 0, 0); pcmk__mock_getpwnam = false; } @@ -99,7 +105,7 @@ no_matching_pwent(void **state) expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); // errno will_return(__wrap_getpwnam, NULL); // return value - assert_lookup_user("hauser", &uid, &gid, ENOENT, 0, 0); + assert_lookup_user(&uid, &gid, ENOENT, 0, 0); pcmk__mock_getpwnam = false; } @@ -119,25 +125,25 @@ entry_found(void **state) expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user("hauser", NULL, NULL, pcmk_rc_ok, 0, 0); + assert_lookup_user(NULL, NULL, pcmk_rc_ok, 0, 0); // Non-NULL uid and NULL gid expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user("hauser", &uid, NULL, pcmk_rc_ok, 1000, 0); + assert_lookup_user(&uid, NULL, pcmk_rc_ok, 1000, 0); // NULL uid and non-NULL gid expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user("hauser", NULL, &gid, pcmk_rc_ok, 0, 1000); + assert_lookup_user(NULL, &gid, pcmk_rc_ok, 0, 1000); // Non-NULL uid and non-NULL gid expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user("hauser", &uid, &gid, pcmk_rc_ok, 1000, 1000); + assert_lookup_user(&uid, &gid, pcmk_rc_ok, 1000, 1000); pcmk__mock_getpwnam = false; } From 194c291cad8519d202c4be995a6e1885d5d1fe9e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 01:08:21 -0800 Subject: [PATCH 14/40] Refactor: libcrmcommon: Reduce duplication in pcmk__lookup_user() test Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__lookup_user_test.c | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index 1718dc3f9bf..eda0c7bc4cf 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -40,6 +40,10 @@ assert_lookup_user(uid_t *uid, gid_t *gid, int expected_rc, uid_t expected_uid, uid_t uid_orig = ((uid != NULL)? *uid : 0); gid_t gid_orig = ((gid != NULL)? *gid : 0); + pcmk__mock_getpwnam = true; + + expect_string(__wrap_getpwnam, name, "hauser"); + assert_int_equal(pcmk__lookup_user("hauser", uid, gid), expected_rc); if (uid != NULL) { @@ -50,6 +54,8 @@ assert_lookup_user(uid_t *uid, gid_t *gid, int expected_rc, uid_t expected_uid, assert_int_equal(*gid, expected_gid); *gid = gid_orig; } + + pcmk__mock_getpwnam = false; } static void @@ -78,14 +84,9 @@ getpwnam_fails(void **state) uid_t uid = 0; gid_t gid = 0; - pcmk__mock_getpwnam = true; - - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, EIO); // errno will_return(__wrap_getpwnam, NULL); // return value assert_lookup_user(&uid, &gid, EIO, 0, 0); - - pcmk__mock_getpwnam = false; } static void @@ -94,20 +95,15 @@ no_matching_pwent(void **state) uid_t uid = 0; gid_t gid = 0; - pcmk__mock_getpwnam = true; - /* errno may or may not be set when no matching passwd entry is found. * However, if the return value is NULL and errno == 0, then we can be sure * no entry was found. In other words, it's sufficient but not necessary. So * this is our test case for "no matching entry," and we should return * ENOENT. */ - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); // errno will_return(__wrap_getpwnam, NULL); // return value assert_lookup_user(&uid, &gid, ENOENT, 0, 0); - - pcmk__mock_getpwnam = false; } static void @@ -119,33 +115,25 @@ entry_found(void **state) // We don't care about the other fields of the passwd entry struct passwd returned_ent = { .pw_uid = 1000, .pw_gid = 1000 }; - pcmk__mock_getpwnam = true; - // NULL uid and NULL gid - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); assert_lookup_user(NULL, NULL, pcmk_rc_ok, 0, 0); // Non-NULL uid and NULL gid - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); assert_lookup_user(&uid, NULL, pcmk_rc_ok, 1000, 0); // NULL uid and non-NULL gid - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); assert_lookup_user(NULL, &gid, pcmk_rc_ok, 0, 1000); // Non-NULL uid and non-NULL gid - expect_string(__wrap_getpwnam, name, "hauser"); will_return(__wrap_getpwnam, 0); will_return(__wrap_getpwnam, &returned_ent); assert_lookup_user(&uid, &gid, pcmk_rc_ok, 1000, 1000); - - pcmk__mock_getpwnam = false; } PCMK__UNIT_TEST(NULL, NULL, From 8ae3f29680f9400716a377e21ef7a12d7fe1f546 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 01:16:55 -0800 Subject: [PATCH 15/40] Refactor: libcrmcommon: Move will_return() calls to assert_lookup_user() Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__lookup_user_test.c | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index eda0c7bc4cf..c25003ca056 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -21,8 +21,10 @@ /*! * \internal - * \brief Perform one test of \c pcmk__lookup_user() with name \c "hauser" + * \brief Perform one test of \c pcmk__lookup_user() with non-NULL name * + * \param[in] errno_to_set Value that \c getpwnam() should set \c errno to + * \param[in] returned_ent Passwd entry that \c getpwnam() should return * \param[in] uid \c uid argument for \c pcmk__lookup_user() * (unchanged upon return) * \param[in] gid \c gid argument for \c pcmk__lookup_user() @@ -34,17 +36,21 @@ * \c pcmk__lookup_user() call */ static void -assert_lookup_user(uid_t *uid, gid_t *gid, int expected_rc, uid_t expected_uid, +assert_lookup_user(int errno_to_set, struct passwd *returned_ent, uid_t *uid, + gid_t *gid, int expected_rc, uid_t expected_uid, gid_t expected_gid) { + static const char *user_name = "ha_user"; uid_t uid_orig = ((uid != NULL)? *uid : 0); gid_t gid_orig = ((gid != NULL)? *gid : 0); pcmk__mock_getpwnam = true; - expect_string(__wrap_getpwnam, name, "hauser"); + expect_string(__wrap_getpwnam, name, user_name); + will_return(__wrap_getpwnam, errno_to_set); + will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user("hauser", uid, gid), expected_rc); + assert_int_equal(pcmk__lookup_user(user_name, uid, gid), expected_rc); if (uid != NULL) { assert_int_equal(*uid, expected_uid); @@ -84,9 +90,7 @@ getpwnam_fails(void **state) uid_t uid = 0; gid_t gid = 0; - will_return(__wrap_getpwnam, EIO); // errno - will_return(__wrap_getpwnam, NULL); // return value - assert_lookup_user(&uid, &gid, EIO, 0, 0); + assert_lookup_user(EIO, NULL, &uid, &gid, EIO, 0, 0); } static void @@ -101,9 +105,7 @@ no_matching_pwent(void **state) * this is our test case for "no matching entry," and we should return * ENOENT. */ - will_return(__wrap_getpwnam, 0); // errno - will_return(__wrap_getpwnam, NULL); // return value - assert_lookup_user(&uid, &gid, ENOENT, 0, 0); + assert_lookup_user(0, NULL, &uid, &gid, ENOENT, 0, 0); } static void @@ -116,24 +118,16 @@ entry_found(void **state) struct passwd returned_ent = { .pw_uid = 1000, .pw_gid = 1000 }; // NULL uid and NULL gid - will_return(__wrap_getpwnam, 0); - will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user(NULL, NULL, pcmk_rc_ok, 0, 0); + assert_lookup_user(0, &returned_ent, NULL, NULL, pcmk_rc_ok, 0, 0); // Non-NULL uid and NULL gid - will_return(__wrap_getpwnam, 0); - will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user(&uid, NULL, pcmk_rc_ok, 1000, 0); + assert_lookup_user(0, &returned_ent, &uid, NULL, pcmk_rc_ok, 1000, 0); // NULL uid and non-NULL gid - will_return(__wrap_getpwnam, 0); - will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user(NULL, &gid, pcmk_rc_ok, 0, 1000); + assert_lookup_user(0, &returned_ent, NULL, &gid, pcmk_rc_ok, 0, 1000); // Non-NULL uid and non-NULL gid - will_return(__wrap_getpwnam, 0); - will_return(__wrap_getpwnam, &returned_ent); - assert_lookup_user(&uid, &gid, pcmk_rc_ok, 1000, 1000); + assert_lookup_user(0, &returned_ent, &uid, &gid, pcmk_rc_ok, 1000, 1000); } PCMK__UNIT_TEST(NULL, NULL, From 84a26a392e441fcab9325f94dc81d7c6f5ff1aae Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 02:50:11 -0800 Subject: [PATCH 16/40] Refactor: libcrmcommon: Drop assert_lookup_user() uid/gid arguments I don't see how these were useful. Also use all four combinations of uid/gid NULL/non-NULL for each test. Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__lookup_user_test.c | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index c25003ca056..641a9daac71 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -25,10 +25,6 @@ * * \param[in] errno_to_set Value that \c getpwnam() should set \c errno to * \param[in] returned_ent Passwd entry that \c getpwnam() should return - * \param[in] uid \c uid argument for \c pcmk__lookup_user() - * (unchanged upon return) - * \param[in] gid \c gid argument for \c pcmk__lookup_user() - * (unchanged upon return) * \param[in] expected_rc Expected return code of \c pcmk__lookup_user() * \param[in] expected_uid Expected value at \p *uid after * \c pcmk__lookup_user() call @@ -36,30 +32,40 @@ * \c pcmk__lookup_user() call */ static void -assert_lookup_user(int errno_to_set, struct passwd *returned_ent, uid_t *uid, - gid_t *gid, int expected_rc, uid_t expected_uid, - gid_t expected_gid) +assert_lookup_user(int errno_to_set, struct passwd *returned_ent, + int expected_rc, uid_t expected_uid, gid_t expected_gid) { static const char *user_name = "ha_user"; - uid_t uid_orig = ((uid != NULL)? *uid : 0); - gid_t gid_orig = ((gid != NULL)? *gid : 0); + uid_t uid = 0; + gid_t gid = 0; pcmk__mock_getpwnam = true; expect_string(__wrap_getpwnam, name, user_name); will_return(__wrap_getpwnam, errno_to_set); will_return(__wrap_getpwnam, returned_ent); + assert_int_equal(pcmk__lookup_user(user_name, NULL, NULL), expected_rc); + + expect_string(__wrap_getpwnam, name, user_name); + will_return(__wrap_getpwnam, errno_to_set); + will_return(__wrap_getpwnam, returned_ent); + assert_int_equal(pcmk__lookup_user(user_name, &uid, NULL), expected_rc); + assert_int_equal(uid, expected_uid); + uid = 0; - assert_int_equal(pcmk__lookup_user(user_name, uid, gid), expected_rc); + expect_string(__wrap_getpwnam, name, user_name); + will_return(__wrap_getpwnam, errno_to_set); + will_return(__wrap_getpwnam, returned_ent); + assert_int_equal(pcmk__lookup_user(user_name, NULL, &gid), expected_rc); + assert_int_equal(gid, expected_gid); + gid = 0; - if (uid != NULL) { - assert_int_equal(*uid, expected_uid); - *uid = uid_orig; - } - if (gid != NULL) { - assert_int_equal(*gid, expected_gid); - *gid = gid_orig; - } + expect_string(__wrap_getpwnam, name, user_name); + will_return(__wrap_getpwnam, errno_to_set); + will_return(__wrap_getpwnam, returned_ent); + assert_int_equal(pcmk__lookup_user(user_name, &uid, &gid), expected_rc); + assert_int_equal(uid, expected_uid); + assert_int_equal(gid, expected_gid); pcmk__mock_getpwnam = false; } @@ -87,47 +93,28 @@ null_name(void **state) static void getpwnam_fails(void **state) { - uid_t uid = 0; - gid_t gid = 0; - - assert_lookup_user(EIO, NULL, &uid, &gid, EIO, 0, 0); + assert_lookup_user(EIO, NULL, EIO, 0, 0); } static void no_matching_pwent(void **state) { - uid_t uid = 0; - gid_t gid = 0; - /* errno may or may not be set when no matching passwd entry is found. * However, if the return value is NULL and errno == 0, then we can be sure * no entry was found. In other words, it's sufficient but not necessary. So * this is our test case for "no matching entry," and we should return * ENOENT. */ - assert_lookup_user(0, NULL, &uid, &gid, ENOENT, 0, 0); + assert_lookup_user(0, NULL, ENOENT, 0, 0); } static void entry_found(void **state) { - uid_t uid = 0; - gid_t gid = 0; - // We don't care about the other fields of the passwd entry struct passwd returned_ent = { .pw_uid = 1000, .pw_gid = 1000 }; - // NULL uid and NULL gid - assert_lookup_user(0, &returned_ent, NULL, NULL, pcmk_rc_ok, 0, 0); - - // Non-NULL uid and NULL gid - assert_lookup_user(0, &returned_ent, &uid, NULL, pcmk_rc_ok, 1000, 0); - - // NULL uid and non-NULL gid - assert_lookup_user(0, &returned_ent, NULL, &gid, pcmk_rc_ok, 0, 1000); - - // Non-NULL uid and non-NULL gid - assert_lookup_user(0, &returned_ent, &uid, &gid, pcmk_rc_ok, 1000, 1000); + assert_lookup_user(0, &returned_ent, pcmk_rc_ok, 1000, 1000); } PCMK__UNIT_TEST(NULL, NULL, From dba7892ff5de23ef8c1b0129010e6e6ccffc5adc Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 02:55:22 -0800 Subject: [PATCH 17/40] Refactor: libcrmcommon: New assert_lookup_user_one() Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__lookup_user_test.c | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index 641a9daac71..a74c37c5aef 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -19,6 +19,18 @@ #include #include +#define USER_NAME "ha_user" + +static void +assert_lookup_user_one(int errno_to_set, struct passwd *returned_ent, + uid_t *uid, gid_t *gid, int expected_rc) +{ + expect_string(__wrap_getpwnam, name, USER_NAME); + will_return(__wrap_getpwnam, errno_to_set); + will_return(__wrap_getpwnam, returned_ent); + assert_int_equal(pcmk__lookup_user(USER_NAME, uid, gid), expected_rc); +} + /*! * \internal * \brief Perform one test of \c pcmk__lookup_user() with non-NULL name @@ -35,35 +47,22 @@ static void assert_lookup_user(int errno_to_set, struct passwd *returned_ent, int expected_rc, uid_t expected_uid, gid_t expected_gid) { - static const char *user_name = "ha_user"; uid_t uid = 0; gid_t gid = 0; pcmk__mock_getpwnam = true; - expect_string(__wrap_getpwnam, name, user_name); - will_return(__wrap_getpwnam, errno_to_set); - will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user(user_name, NULL, NULL), expected_rc); + assert_lookup_user_one(errno_to_set, returned_ent, NULL, NULL, expected_rc); - expect_string(__wrap_getpwnam, name, user_name); - will_return(__wrap_getpwnam, errno_to_set); - will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user(user_name, &uid, NULL), expected_rc); + assert_lookup_user_one(errno_to_set, returned_ent, &uid, NULL, expected_rc); assert_int_equal(uid, expected_uid); uid = 0; - expect_string(__wrap_getpwnam, name, user_name); - will_return(__wrap_getpwnam, errno_to_set); - will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user(user_name, NULL, &gid), expected_rc); + assert_lookup_user_one(errno_to_set, returned_ent, NULL, &gid, expected_rc); assert_int_equal(gid, expected_gid); gid = 0; - expect_string(__wrap_getpwnam, name, user_name); - will_return(__wrap_getpwnam, errno_to_set); - will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user(user_name, &uid, &gid), expected_rc); + assert_lookup_user_one(errno_to_set, returned_ent, &uid, &gid, expected_rc); assert_int_equal(uid, expected_uid); assert_int_equal(gid, expected_gid); From ef747ae53ffa61b48b3e988d4241f5533a3143f5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 03:03:21 -0800 Subject: [PATCH 18/40] Refactor: libcrmcommon: Test pcmk__compare_versions() bidirectionally Do this unconditionally. We don't need to be terribly concerned with efficiency here. This will make the upcoming conversion to a macro simpler. Signed-off-by: Reid Wahl --- lib/common/tests/utils/pcmk__compare_versions_test.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/common/tests/utils/pcmk__compare_versions_test.c b/lib/common/tests/utils/pcmk__compare_versions_test.c index 22844e9d5ad..7cfeabdd0fc 100644 --- a/lib/common/tests/utils/pcmk__compare_versions_test.c +++ b/lib/common/tests/utils/pcmk__compare_versions_test.c @@ -24,13 +24,7 @@ static void assert_compare_version(const char *v1, const char *v2, int expected_rc) { assert_int_equal(pcmk__compare_versions(v1, v2), expected_rc); - - if (v1 != v2) { - /* Try reverse order even if expected_rc == 0, if v1 and v2 are - * different strings - */ - assert_int_equal(pcmk__compare_versions(v2, v1), -expected_rc); - } + assert_int_equal(pcmk__compare_versions(v2, v1), -expected_rc); } static void From 95b766955bba64fafca8e142af860dd22d3789b7 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 03:08:43 -0800 Subject: [PATCH 19/40] Refactor: libcrmcommon: Rename assert_compare_version() ...to assert_compare_versions(). Signed-off-by: Reid Wahl --- .../tests/utils/pcmk__compare_versions_test.c | 278 +++++++++--------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/lib/common/tests/utils/pcmk__compare_versions_test.c b/lib/common/tests/utils/pcmk__compare_versions_test.c index 7cfeabdd0fc..a6d99a8ac95 100644 --- a/lib/common/tests/utils/pcmk__compare_versions_test.c +++ b/lib/common/tests/utils/pcmk__compare_versions_test.c @@ -21,7 +21,7 @@ * pcmk__compare_versions(v1, v2) */ static void -assert_compare_version(const char *v1, const char *v2, int expected_rc) +assert_compare_versions(const char *v1, const char *v2, int expected_rc) { assert_int_equal(pcmk__compare_versions(v1, v2), expected_rc); assert_int_equal(pcmk__compare_versions(v2, v1), -expected_rc); @@ -30,268 +30,268 @@ assert_compare_version(const char *v1, const char *v2, int expected_rc) static void empty_params(void **state) { - assert_compare_version(NULL, NULL, 0); - assert_compare_version(NULL, "", 0); - assert_compare_version("", "", 0); + assert_compare_versions(NULL, NULL, 0); + assert_compare_versions(NULL, "", 0); + assert_compare_versions("", "", 0); - assert_compare_version(NULL, "1.0.1", -1); - assert_compare_version("", "1.0.1", -1); + assert_compare_versions(NULL, "1.0.1", -1); + assert_compare_versions("", "1.0.1", -1); // NULL or empty is treated as equal to an invalid version - assert_compare_version(NULL, "abc", 0); - assert_compare_version("", "abc", 0); + assert_compare_versions(NULL, "abc", 0); + assert_compare_versions("", "abc", 0); } static void equal_versions(void **state) { - assert_compare_version("0.4.7", "0.4.7", 0); - assert_compare_version("1.0", "1.0", 0); + assert_compare_versions("0.4.7", "0.4.7", 0); + assert_compare_versions("1.0", "1.0", 0); } static void unequal_versions(void **state) { - assert_compare_version("0.4.7", "0.4.8", -1); - assert_compare_version("0.2.3", "0.3", -1); - assert_compare_version("0.99", "1.0", -1); + assert_compare_versions("0.4.7", "0.4.8", -1); + assert_compare_versions("0.2.3", "0.3", -1); + assert_compare_versions("0.99", "1.0", -1); } static void shorter_versions(void **state) { - assert_compare_version("1.0", "1.0.1", -1); - assert_compare_version("1.0", "1", 0); - assert_compare_version("1", "1.2", -1); - assert_compare_version("1.0.0", "1.0", 0); - assert_compare_version("1.0.0", "1.2", -1); - assert_compare_version("0.99", "1", -1); + assert_compare_versions("1.0", "1.0.1", -1); + assert_compare_versions("1.0", "1", 0); + assert_compare_versions("1", "1.2", -1); + assert_compare_versions("1.0.0", "1.0", 0); + assert_compare_versions("1.0.0", "1.2", -1); + assert_compare_versions("0.99", "1", -1); } static void leading_zeros(void **state) { // Equal to self - assert_compare_version("00001.0", "00001.0", 0); + assert_compare_versions("00001.0", "00001.0", 0); // Leading zeros in each segment are ignored - assert_compare_version("0001.0", "1", 0); - assert_compare_version("0.0001", "0.1", 0); - assert_compare_version("0001.1", "1.0001", 0); + assert_compare_versions("0001.0", "1", 0); + assert_compare_versions("0.0001", "0.1", 0); + assert_compare_versions("0001.1", "1.0001", 0); } static void negative_sign(void **state) { // Equal to self - assert_compare_version("-1", "-1", 0); - assert_compare_version("1.-1.5", "1.-1.5", 0); + assert_compare_versions("-1", "-1", 0); + assert_compare_versions("1.-1.5", "1.-1.5", 0); // Negative version is treated as 0 (invalid) - assert_compare_version("-1", "0", 0); - assert_compare_version("-1", "0.0", 0); - assert_compare_version("-1", "0.1", -1); - assert_compare_version("-1", "1.0", -1); + assert_compare_versions("-1", "0", 0); + assert_compare_versions("-1", "0.0", 0); + assert_compare_versions("-1", "0.1", -1); + assert_compare_versions("-1", "1.0", -1); - assert_compare_version("-1", "-0", 0); - assert_compare_version("-1", "-0.0", 0); - assert_compare_version("-1", "-0.1", 0); - assert_compare_version("-1", "-1.0", 0); - assert_compare_version("-1", "-2.0", 0); + assert_compare_versions("-1", "-0", 0); + assert_compare_versions("-1", "-0.0", 0); + assert_compare_versions("-1", "-0.1", 0); + assert_compare_versions("-1", "-1.0", 0); + assert_compare_versions("-1", "-2.0", 0); // Negative sign inside version is treated as garbage - assert_compare_version("1.-1.5", "1.0", 0); - assert_compare_version("1.-1.5", "1.0.5", -1); + assert_compare_versions("1.-1.5", "1.0", 0); + assert_compare_versions("1.-1.5", "1.0.5", -1); - assert_compare_version("1.-1.5", "1.-0", 0); - assert_compare_version("1.-1.5", "1.-0.5", 0); + assert_compare_versions("1.-1.5", "1.-0", 0); + assert_compare_versions("1.-1.5", "1.-0.5", 0); - assert_compare_version("1.-1.5", "1.-1", 0); - assert_compare_version("1.-1.5", "1.-1.9", 0); + assert_compare_versions("1.-1.5", "1.-1", 0); + assert_compare_versions("1.-1.5", "1.-1.9", 0); - assert_compare_version("1.-1.5", "1.-2", 0); - assert_compare_version("1.-1.5", "1.-2.5", 0); + assert_compare_versions("1.-1.5", "1.-2", 0); + assert_compare_versions("1.-1.5", "1.-2.5", 0); - assert_compare_version("1.-1.5", "2.0.5", -1); - assert_compare_version("1.-1.5", "0.0.5", 1); + assert_compare_versions("1.-1.5", "2.0.5", -1); + assert_compare_versions("1.-1.5", "0.0.5", 1); } static void positive_sign(void **state) { // Equal to self - assert_compare_version("+1", "+1", 0); - assert_compare_version("1.+1.5", "1.+1.5", 0); + assert_compare_versions("+1", "+1", 0); + assert_compare_versions("1.+1.5", "1.+1.5", 0); // Version with explicit positive sign is treated as 0 (invalid) - assert_compare_version("+1", "0", 0); - assert_compare_version("+1", "0.0", 0); - assert_compare_version("+1", "0.1", -1); - assert_compare_version("+1", "1.0", -1); - assert_compare_version("+1", "2.0", -1); - - assert_compare_version("+1", "+0", 0); - assert_compare_version("+1", "+0.0", 0); - assert_compare_version("+1", "+0.1", 0); - assert_compare_version("+1", "+1.0", 0); - assert_compare_version("+1", "+2.0", 0); + assert_compare_versions("+1", "0", 0); + assert_compare_versions("+1", "0.0", 0); + assert_compare_versions("+1", "0.1", -1); + assert_compare_versions("+1", "1.0", -1); + assert_compare_versions("+1", "2.0", -1); + + assert_compare_versions("+1", "+0", 0); + assert_compare_versions("+1", "+0.0", 0); + assert_compare_versions("+1", "+0.1", 0); + assert_compare_versions("+1", "+1.0", 0); + assert_compare_versions("+1", "+2.0", 0); // Positive sign inside version is treated as garbage - assert_compare_version("1.+1.5", "1.0", 0); - assert_compare_version("1.+1.5", "1.0.5", -1); + assert_compare_versions("1.+1.5", "1.0", 0); + assert_compare_versions("1.+1.5", "1.0.5", -1); - assert_compare_version("1.+1.5", "1.+0", 0); - assert_compare_version("1.+1.5", "1.+0.5", 0); + assert_compare_versions("1.+1.5", "1.+0", 0); + assert_compare_versions("1.+1.5", "1.+0.5", 0); - assert_compare_version("1.+1.5", "1.+1", 0); - assert_compare_version("1.+1.5", "1.+1.9", 0); + assert_compare_versions("1.+1.5", "1.+1", 0); + assert_compare_versions("1.+1.5", "1.+1.9", 0); - assert_compare_version("1.+1.5", "1.+2", 0); - assert_compare_version("1.+1.5", "1.+2.5", 0); + assert_compare_versions("1.+1.5", "1.+2", 0); + assert_compare_versions("1.+1.5", "1.+2.5", 0); - assert_compare_version("1.+1.5", "2.0.5", -1); - assert_compare_version("1.+1.5", "0.0.5", 1); + assert_compare_versions("1.+1.5", "2.0.5", -1); + assert_compare_versions("1.+1.5", "0.0.5", 1); } static void hex_digits(void **state) { // Equal to self - assert_compare_version("a", "a", 0); + assert_compare_versions("a", "a", 0); // Hex digits > 9 are garbage - assert_compare_version("a", "0", 0); - assert_compare_version("a111", "0", 0); - assert_compare_version("a", "1", -1); - assert_compare_version("a111", "1", -1); - - assert_compare_version("1a", "1", 0); - assert_compare_version("1a111", "1", 0); - assert_compare_version("1a", "2", -1); - assert_compare_version("1a111", "2", -1); - assert_compare_version("1a", "0", 1); - assert_compare_version("1a111", "0", 1); + assert_compare_versions("a", "0", 0); + assert_compare_versions("a111", "0", 0); + assert_compare_versions("a", "1", -1); + assert_compare_versions("a111", "1", -1); + + assert_compare_versions("1a", "1", 0); + assert_compare_versions("1a111", "1", 0); + assert_compare_versions("1a", "2", -1); + assert_compare_versions("1a111", "2", -1); + assert_compare_versions("1a", "0", 1); + assert_compare_versions("1a111", "0", 1); } static void bare_dot(void **state) { // Equal to self - assert_compare_version(".", ".", 0); + assert_compare_versions(".", ".", 0); // Bare dot is treated as 0 - assert_compare_version(".", "0", 0); - assert_compare_version(".", "0.1", -1); - assert_compare_version(".", "1.0", -1); + assert_compare_versions(".", "0", 0); + assert_compare_versions(".", "0.1", -1); + assert_compare_versions(".", "1.0", -1); } static void leading_dot(void **state) { // Equal to self - assert_compare_version(".0", ".0", 0); - assert_compare_version(".1", ".1", 0); + assert_compare_versions(".0", ".0", 0); + assert_compare_versions(".1", ".1", 0); // Version with leading dot is treated as 0 (invalid) - assert_compare_version(".0", "0", 0); - assert_compare_version(".0", "0.0", 0); - assert_compare_version(".0", "0.0.0", 0); - assert_compare_version(".0", "0.1", -1); - - assert_compare_version(".1", "0", 0); - assert_compare_version(".1", "0.0", 0); - assert_compare_version(".1", "0.0.0", 0); - assert_compare_version(".1", "0.1", -1); - assert_compare_version(".1", "0.1.0", -1); + assert_compare_versions(".0", "0", 0); + assert_compare_versions(".0", "0.0", 0); + assert_compare_versions(".0", "0.0.0", 0); + assert_compare_versions(".0", "0.1", -1); + + assert_compare_versions(".1", "0", 0); + assert_compare_versions(".1", "0.0", 0); + assert_compare_versions(".1", "0.0.0", 0); + assert_compare_versions(".1", "0.1", -1); + assert_compare_versions(".1", "0.1.0", -1); } static void trailing_dot(void **state) { // Equal to self - assert_compare_version("0.", "0.", 0); - assert_compare_version("0.1.", "0.1.", 0); + assert_compare_versions("0.", "0.", 0); + assert_compare_versions("0.1.", "0.1.", 0); // Trailing dot is ignored - assert_compare_version("0.", "0", 0); - assert_compare_version("0.", "0.0", 0); - assert_compare_version("0.", "0.1", -1); - assert_compare_version("0.1.", "0.1", 0); - assert_compare_version("0.1.", "0.1.0", 0); - assert_compare_version("0.1.", "0.2", -1); - assert_compare_version("0.1.", "0", 1); + assert_compare_versions("0.", "0", 0); + assert_compare_versions("0.", "0.0", 0); + assert_compare_versions("0.", "0.1", -1); + assert_compare_versions("0.1.", "0.1", 0); + assert_compare_versions("0.1.", "0.1.0", 0); + assert_compare_versions("0.1.", "0.2", -1); + assert_compare_versions("0.1.", "0", 1); } static void leading_spaces(void **state) { // Equal to self - assert_compare_version(" ", " ", 0); - assert_compare_version(" 1", " 1", 0); + assert_compare_versions(" ", " ", 0); + assert_compare_versions(" 1", " 1", 0); // Leading spaces are ignored - assert_compare_version(" 1", "1.0", 0); - assert_compare_version("1", " 1.0", 0); - assert_compare_version(" 1", " 1.0", 0); - assert_compare_version(" 1", "1.1", -1); - assert_compare_version("1", " 1.1", -1); - assert_compare_version(" 1", " 1.1", -1); + assert_compare_versions(" 1", "1.0", 0); + assert_compare_versions("1", " 1.0", 0); + assert_compare_versions(" 1", " 1.0", 0); + assert_compare_versions(" 1", "1.1", -1); + assert_compare_versions("1", " 1.1", -1); + assert_compare_versions(" 1", " 1.1", -1); } static void trailing_spaces(void **state) { // Equal to self - assert_compare_version("1 ", "1 ", 0); + assert_compare_versions("1 ", "1 ", 0); // Trailing spaces are ignored - assert_compare_version("1 ", "1.0", 0); - assert_compare_version("1", "1.0 ", 0); - assert_compare_version("1 ", "1.0 ", 0); - assert_compare_version("1 ", "1.1", -1); - assert_compare_version("1", "1.1 ", -1); - assert_compare_version("1 ", "1.1 ", -1); + assert_compare_versions("1 ", "1.0", 0); + assert_compare_versions("1", "1.0 ", 0); + assert_compare_versions("1 ", "1.0 ", 0); + assert_compare_versions("1 ", "1.1", -1); + assert_compare_versions("1", "1.1 ", -1); + assert_compare_versions("1 ", "1.1 ", -1); } static void leading_garbage(void **state) { // Equal to self - assert_compare_version("@1", "@1", 0); + assert_compare_versions("@1", "@1", 0); // Version with leading garbage is treated as 0 - assert_compare_version("@1", "0", 0); - assert_compare_version("@1", "1", -1); + assert_compare_versions("@1", "0", 0); + assert_compare_versions("@1", "1", -1); - assert_compare_version("@0.1", "0", 0); - assert_compare_version("@0.1", "1", -1); + assert_compare_versions("@0.1", "0", 0); + assert_compare_versions("@0.1", "1", -1); } static void trailing_garbage(void **state) { // Equal to self - assert_compare_version("0.1@", "0.1@", 0); + assert_compare_versions("0.1@", "0.1@", 0); // Trailing garbage is ignored - assert_compare_version("0.1@", "0.1", 0); - assert_compare_version("0.1.@", "0.1", 0); - assert_compare_version("0.1 @", "0.1", 0); - assert_compare_version("0.1. @", "0.1", 0); - assert_compare_version("0.1 .@", "0.1", 0); + assert_compare_versions("0.1@", "0.1", 0); + assert_compare_versions("0.1.@", "0.1", 0); + assert_compare_versions("0.1 @", "0.1", 0); + assert_compare_versions("0.1. @", "0.1", 0); + assert_compare_versions("0.1 .@", "0.1", 0); // This includes more numbers after spaces - assert_compare_version("0.1 1", "0.1", 0); - assert_compare_version("0.1. 1", "0.1", 0); - assert_compare_version("0.1 .1", "0.1", 0); + assert_compare_versions("0.1 1", "0.1", 0); + assert_compare_versions("0.1. 1", "0.1", 0); + assert_compare_versions("0.1 .1", "0.1", 0); // Second consecutive dot is treated as garbage - assert_compare_version("1..", "1", 0); - assert_compare_version("1..1", "1", 0); - assert_compare_version("1..", "1.0.0", 0); - assert_compare_version("1..1", "1.0.0", 0); - assert_compare_version("1..", "1.0.1", -1); - assert_compare_version("1..1", "1.0.1", -1); + assert_compare_versions("1..", "1", 0); + assert_compare_versions("1..1", "1", 0); + assert_compare_versions("1..", "1.0.0", 0); + assert_compare_versions("1..1", "1.0.0", 0); + assert_compare_versions("1..", "1.0.1", -1); + assert_compare_versions("1..1", "1.0.1", -1); } PCMK__UNIT_TEST(NULL, NULL, From 8fc94da1a427c689ac54ff9820f98ba1546ae2e5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 15:51:06 -0800 Subject: [PATCH 20/40] Refactor: libcrmcommon: Split unit test helper into success/fail cases With a function, the CMocka assert macros showed unhelpful line numbers on error. We want to convert these to macros. These splits have two goals: * Make each helper a bit easier to read. * Avoid complaints from the compiler or Coverity. I started making splits after compilation failed due to a NULL strcmp() argument, even though strcmp() would have never actually been *called* with a NULL argument. Macro expansion has unpleasant results sometimes. Signed-off-by: Reid Wahl --- .../tests/nvpair/pcmk__scan_nvpair_test.c | 82 ++++++------- .../tests/strings/pcmk__parse_bool_test.c | 110 ++++++++++-------- 2 files changed, 106 insertions(+), 86 deletions(-) diff --git a/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c b/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c index c8cf464369c..ecae94564c2 100644 --- a/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c +++ b/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c @@ -14,31 +14,33 @@ #include static void -assert_scan_nvpair(const gchar *input, int expected_rc, - const gchar *expected_name, const gchar *expected_value) +assert_scan_nvpair_success(const gchar *input, const gchar *expected_name, + const gchar *expected_value) { gchar *name = NULL; gchar *value = NULL; + int rc = pcmk__scan_nvpair(input, &name, &value); - assert_int_equal(pcmk__scan_nvpair(input, &name, &value), - expected_rc); - - if (expected_name == NULL) { - assert_null(name); - } else { - assert_string_equal(name, expected_name); - } - - if (expected_value == NULL) { - assert_null(value); - } else { - assert_string_equal(value, expected_value); - } + assert_int_equal(rc, pcmk_rc_ok); + assert_string_equal(name, expected_name); + assert_string_equal(value, expected_value); g_free(name); g_free(value); } +static void +assert_scan_nvpair_failure(const gchar *input) +{ + gchar *name = NULL; + gchar *value = NULL; + int rc = pcmk__scan_nvpair(input, &name, &value); + + assert_int_equal(rc, pcmk_rc_bad_nvpair); + assert_null(name); + assert_null(value); +} + static void null_asserts(void **state) { @@ -67,60 +69,60 @@ already_allocated_asserts(void **state) static void empty_input(void **state) { - assert_scan_nvpair("", pcmk_rc_bad_nvpair, NULL, NULL); + assert_scan_nvpair_failure(""); } static void equal_sign_only(void **state) { - assert_scan_nvpair("=", pcmk_rc_bad_nvpair, NULL, NULL); + assert_scan_nvpair_failure("="); } static void name_only(void **state) { - assert_scan_nvpair("name", pcmk_rc_bad_nvpair, NULL, NULL); + assert_scan_nvpair_failure("name"); } static void value_only(void **state) { - assert_scan_nvpair("=value", pcmk_rc_bad_nvpair, NULL, NULL); + assert_scan_nvpair_failure("=value"); } static void valid(void **state) { - assert_scan_nvpair("name=value", pcmk_rc_ok, "name", "value"); + assert_scan_nvpair_success("name=value", "name", "value"); // Empty value - assert_scan_nvpair("name=", pcmk_rc_ok, "name", ""); + assert_scan_nvpair_success("name=", "name", ""); // Whitespace is kept (checking only space characters here) - assert_scan_nvpair(" name=value", pcmk_rc_ok, " name", "value"); - assert_scan_nvpair("name =value", pcmk_rc_ok, "name ", "value"); - assert_scan_nvpair("name= value", pcmk_rc_ok, "name", " value"); - assert_scan_nvpair("name=value ", pcmk_rc_ok, "name", "value "); - assert_scan_nvpair("name = value", pcmk_rc_ok, "name ", " value"); + assert_scan_nvpair_success(" name=value", " name", "value"); + assert_scan_nvpair_success("name =value", "name ", "value"); + assert_scan_nvpair_success("name= value", "name", " value"); + assert_scan_nvpair_success("name=value ", "name", "value "); + assert_scan_nvpair_success("name = value", "name ", " value"); // Trailing characters are kept - assert_scan_nvpair("name=value=", pcmk_rc_ok, "name", "value="); - assert_scan_nvpair("name=value=\n\n", pcmk_rc_ok, "name", "value=\n\n"); - assert_scan_nvpair("name=value=e", pcmk_rc_ok, "name", "value=e"); - assert_scan_nvpair("name=value=e\n\n", pcmk_rc_ok, "name", "value=e\n\n"); + assert_scan_nvpair_success("name=value=", "name", "value="); + assert_scan_nvpair_success("name=value=\n\n", "name", "value=\n\n"); + assert_scan_nvpair_success("name=value=e", "name", "value=e"); + assert_scan_nvpair_success("name=value=e\n\n", "name", "value=e\n\n"); // Quotes are not treated specially - assert_scan_nvpair("name=''", pcmk_rc_ok, "name", "''"); - assert_scan_nvpair("name='value'", pcmk_rc_ok, "name", "'value'"); - assert_scan_nvpair("'name'=value", pcmk_rc_ok, "'name'", "value"); - assert_scan_nvpair("'name=value'", pcmk_rc_ok, "'name", "value'"); - assert_scan_nvpair("name=\"value\"", pcmk_rc_ok, "name", "\"value\""); - assert_scan_nvpair("\"name\"=value", pcmk_rc_ok, "\"name\"", "value"); - assert_scan_nvpair("\"name=value\"", pcmk_rc_ok, "\"name", "value\""); + assert_scan_nvpair_success("name=''", "name", "''"); + assert_scan_nvpair_success("name='value'", "name", "'value'"); + assert_scan_nvpair_success("'name'=value", "'name'", "value"); + assert_scan_nvpair_success("'name=value'", "'name", "value'"); + assert_scan_nvpair_success("name=\"value\"", "name", "\"value\""); + assert_scan_nvpair_success("\"name\"=value", "\"name\"", "value"); + assert_scan_nvpair_success("\"name=value\"", "\"name", "value\""); // Other special characters are not treated specially (small sample) - assert_scan_nvpair("!@#$%=^&*()", pcmk_rc_ok, "!@#$%", "^&*()"); - assert_scan_nvpair("name=$value", pcmk_rc_ok, "name", "$value"); + assert_scan_nvpair_success("!@#$%=^&*()", "!@#$%", "^&*()"); + assert_scan_nvpair_success("name=$value", "name", "$value"); } PCMK__UNIT_TEST(NULL, NULL, diff --git a/lib/common/tests/strings/pcmk__parse_bool_test.c b/lib/common/tests/strings/pcmk__parse_bool_test.c index d1d12666cb1..196bf04ae0b 100644 --- a/lib/common/tests/strings/pcmk__parse_bool_test.c +++ b/lib/common/tests/strings/pcmk__parse_bool_test.c @@ -15,27 +15,21 @@ /*! * \internal - * \brief Check a call with given input against expected return value and result + * \brief Check \c pcmk__parse_bool() succeeds and parses the input as expected * * \param[in] input Input string - * \param[in] expected_rc Expected return code - * \param[in] expected_result Expected parsed value (ignored unless - * \p expected_rc is \c pcmk_rc_ok) + * \param[in] expected_result Expected parsed value */ static void -assert_parse_bool(const char *input, int expected_rc, bool expected_result) +assert_parse_bool(const char *input, bool expected_result) { bool result = false; // Ensure we still validate the string with a NULL result argument - assert_int_equal(pcmk__parse_bool(input, NULL), expected_rc); + assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); - if (expected_rc != pcmk_rc_ok) { - // Make sure the value of result does not change on failure - expected_result = result; - } + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); if (expected_result) { assert_true(result); } else { @@ -44,11 +38,9 @@ assert_parse_bool(const char *input, int expected_rc, bool expected_result) // Repeat with result initially set to true result = true; - if (expected_rc != pcmk_rc_ok) { - expected_result = result; - } - assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); + if (expected_result) { assert_true(result); } else { @@ -56,62 +48,88 @@ assert_parse_bool(const char *input, int expected_rc, bool expected_result) } } +/*! + * \internal + * \brief Check that \c pcmk__parse_bool() fails and returns the expected value + * + * \param[in] input Input string + * \param[in] expected_rc Expected return code + */ +static void +assert_parse_bool_failure(const char *input, int expected_rc) +{ + bool result = false; + + // Ensure we still validate the string with a NULL result argument + assert_int_equal(pcmk__parse_bool(input, NULL), expected_rc); + + // Make sure the value of result does not change on failure + assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); + assert_false(result); + + // Repeat with result initially set to true + result = true; + + assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); + assert_true(result); +} + static void bad_input(void **state) { // Dumps core via CRM_CHECK() - assert_parse_bool(NULL, EINVAL, false); + assert_parse_bool_failure(NULL, EINVAL); - assert_parse_bool("", pcmk_rc_bad_input, false); - assert_parse_bool("blahblah", pcmk_rc_bad_input, false); + assert_parse_bool_failure("", pcmk_rc_bad_input); + assert_parse_bool_failure("blahblah", pcmk_rc_bad_input); } static void is_true(void **state) { - assert_parse_bool("true", pcmk_rc_ok, true); - assert_parse_bool("TrUe", pcmk_rc_ok, true); - assert_parse_bool("on", pcmk_rc_ok, true); - assert_parse_bool("ON", pcmk_rc_ok, true); - assert_parse_bool("yes", pcmk_rc_ok, true); - assert_parse_bool("yES", pcmk_rc_ok, true); - assert_parse_bool("y", pcmk_rc_ok, true); - assert_parse_bool("Y", pcmk_rc_ok, true); - assert_parse_bool("1", pcmk_rc_ok, true); + assert_parse_bool("true", true); + assert_parse_bool("TrUe", true); + assert_parse_bool("on", true); + assert_parse_bool("ON", true); + assert_parse_bool("yes", true); + assert_parse_bool("yES", true); + assert_parse_bool("y", true); + assert_parse_bool("Y", true); + assert_parse_bool("1", true); } static void is_not_true(void **state) { - assert_parse_bool("truedat", pcmk_rc_bad_input, false); - assert_parse_bool("onnn", pcmk_rc_bad_input, false); - assert_parse_bool("yep", pcmk_rc_bad_input, false); - assert_parse_bool("Y!", pcmk_rc_bad_input, false); - assert_parse_bool("100", pcmk_rc_bad_input, false); + assert_parse_bool_failure("truedat", pcmk_rc_bad_input); + assert_parse_bool_failure("onnn", pcmk_rc_bad_input); + assert_parse_bool_failure("yep", pcmk_rc_bad_input); + assert_parse_bool_failure("Y!", pcmk_rc_bad_input); + assert_parse_bool_failure("100", pcmk_rc_bad_input); } static void is_false(void **state) { - assert_parse_bool("false", pcmk_rc_ok, false); - assert_parse_bool("fAlSe", pcmk_rc_ok, false); - assert_parse_bool("off", pcmk_rc_ok, false); - assert_parse_bool("OFF", pcmk_rc_ok, false); - assert_parse_bool("no", pcmk_rc_ok, false); - assert_parse_bool("No", pcmk_rc_ok, false); - assert_parse_bool("n", pcmk_rc_ok, false); - assert_parse_bool("N", pcmk_rc_ok, false); - assert_parse_bool("0", pcmk_rc_ok, false); + assert_parse_bool("false", false); + assert_parse_bool("fAlSe", false); + assert_parse_bool("off", false); + assert_parse_bool("OFF", false); + assert_parse_bool("no", false); + assert_parse_bool("No", false); + assert_parse_bool("n", false); + assert_parse_bool("N", false); + assert_parse_bool("0", false); } static void is_not_false(void **state) { - assert_parse_bool("falseee", pcmk_rc_bad_input, false); - assert_parse_bool("of", pcmk_rc_bad_input, false); - assert_parse_bool("nope", pcmk_rc_bad_input, false); - assert_parse_bool("N!", pcmk_rc_bad_input, false); - assert_parse_bool("000", pcmk_rc_bad_input, false); + assert_parse_bool_failure("falseee", pcmk_rc_bad_input); + assert_parse_bool_failure("of", pcmk_rc_bad_input); + assert_parse_bool_failure("nope", pcmk_rc_bad_input); + assert_parse_bool_failure("N!", pcmk_rc_bad_input); + assert_parse_bool_failure("000", pcmk_rc_bad_input); } PCMK__UNIT_TEST(NULL, NULL, From 5ba7d5b4ef2e6ca42aa0c5635ed5050a7e41801e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 17:00:05 -0800 Subject: [PATCH 21/40] Refactor: libcrmcommon: Split part of assert_comment() into macro helper This is a step toward replacing assert_comment() with a macro completely. With a function, the CMocka assert macros show unhelpful line numbers on error. We'll need to split up assert_comment() into a NULL case and a non-NULL case. The code that gets split out in this commit will be shared between them. Signed-off-by: Reid Wahl --- .../tests/xml_comment/pcmk__xc_create_test.c | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/common/tests/xml_comment/pcmk__xc_create_test.c b/lib/common/tests/xml_comment/pcmk__xc_create_test.c index 280c50ae420..e5afc0d2730 100644 --- a/lib/common/tests/xml_comment/pcmk__xc_create_test.c +++ b/lib/common/tests/xml_comment/pcmk__xc_create_test.c @@ -18,20 +18,36 @@ * hassle. */ +#define assert_create_comment(content, doc_ptr, node_ptr) \ + do { \ + xml_doc_private_t *docpriv = NULL; \ + xml_node_private_t *nodepriv = NULL; \ + \ + *(doc_ptr) = pcmk__xml_new_doc(); \ + pcmk__xml_doc_set_flags(*(doc_ptr), pcmk__xf_tracking); \ + \ + *(node_ptr) = pcmk__xc_create(*(doc_ptr), content); \ + assert_non_null(*(node_ptr)); \ + assert_int_equal((*(node_ptr))->type, XML_COMMENT_NODE); \ + assert_ptr_equal((*(node_ptr))->doc, *(doc_ptr)); \ + \ + docpriv = (*(doc_ptr))->_private; \ + assert_true(pcmk__is_set(docpriv->flags, pcmk__xf_dirty)); \ + \ + nodepriv = (*(node_ptr))->_private; \ + assert_non_null(nodepriv); \ + assert_int_equal(nodepriv->check, PCMK__XML_NODE_PRIVATE_MAGIC); \ + assert_true(pcmk__all_flags_set(nodepriv->flags, \ + pcmk__xf_dirty|pcmk__xf_created)); \ + } while (0) + static void assert_comment(const char *content) { - xmlDoc *doc = pcmk__xml_new_doc(); - xml_doc_private_t *docpriv = doc->_private; + xmlDoc *doc = NULL; xmlNode *node = NULL; - xml_node_private_t *nodepriv = NULL; - - pcmk__xml_doc_set_flags(doc, pcmk__xf_tracking); - node = pcmk__xc_create(doc, content); - assert_non_null(node); - assert_int_equal(node->type, XML_COMMENT_NODE); - assert_ptr_equal(node->doc, doc); + assert_create_comment(content, &doc, &node); if (content == NULL) { assert_null(node->content); @@ -40,14 +56,6 @@ assert_comment(const char *content) assert_string_equal((const char *) node->content, content); } - nodepriv = node->_private; - assert_non_null(nodepriv); - assert_int_equal(nodepriv->check, PCMK__XML_NODE_PRIVATE_MAGIC); - assert_true(pcmk__all_flags_set(nodepriv->flags, - pcmk__xf_dirty|pcmk__xf_created)); - - assert_true(pcmk__is_set(docpriv->flags, pcmk__xf_dirty)); - pcmk__xml_free(node); pcmk__xml_free_doc(doc); } From f22f72cc5a617872064501a6727dc64fe16aa2ac Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 18 Dec 2025 23:14:16 -0800 Subject: [PATCH 22/40] Refactor: libcrmcommon: Split unit test helpers into NULL/non-NULL cases This is a step toward converting the assertion helpers into macros. Splitting into multiple helpers has two goals. * Make each helper a bit easier to read. * Avoid complaints from the compiler or Coverity. I started making splits after compilation failed due to a NULL strcmp() argument, even though strcmp() would have never actually been *called* with a NULL argument. Macro expansion has unpleasant results sometimes. In the case of the pcmk__xc_create() tests, there's no need to even keep wrapper functions for the NULL and non-NULL cases, since each would be used only once. Signed-off-by: Reid Wahl --- .../tests/procfs/pcmk__procfs_pid2path_test.c | 35 +-- .../pcmk__evaluate_date_expression_test.c | 230 +++++++++--------- .../tests/xml_comment/pcmk__xc_create_test.c | 38 ++- 3 files changed, 153 insertions(+), 150 deletions(-) diff --git a/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c index 4cd1bd7e871..a32a51c1b36 100644 --- a/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c +++ b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c @@ -36,26 +36,33 @@ assert_pid2path_one(int errno_to_set, const char *link_contents, char **dest, } static void -assert_pid2path(int errno_to_set, const char *link_contents, int reference_rc, - const char *reference_result) +assert_pid2path_null(int errno_to_set, const char *link_contents, + int expected_rc) { char *dest = NULL; - assert_pid2path_one(errno_to_set, link_contents, NULL, reference_rc); - assert_pid2path_one(errno_to_set, link_contents, &dest, reference_rc); + assert_pid2path_one(errno_to_set, link_contents, NULL, expected_rc); + assert_pid2path_one(errno_to_set, link_contents, &dest, expected_rc); + assert_null(dest); +} + +static void +assert_pid2path_equals(int errno_to_set, const char *link_contents, + int expected_rc, const char *expected_result) +{ + char *dest = NULL; + + assert_pid2path_one(errno_to_set, link_contents, NULL, expected_rc); + assert_pid2path_one(errno_to_set, link_contents, &dest, expected_rc); - if (reference_result == NULL) { - assert_null(dest); - } else { - assert_string_equal(dest, reference_result); - free(dest); - } + assert_string_equal(dest, expected_result); + free(dest); } static void no_exe_file(void **state) { - assert_pid2path(ENOENT, NULL, ENOENT, NULL); + assert_pid2path_null(ENOENT, NULL, ENOENT); } static void @@ -64,7 +71,7 @@ contents_too_long(void **state) // String length equals PATH_MAX char *long_path = pcmk__assert_asprintf("%0*d", PATH_MAX, 0); - assert_pid2path(0, long_path, ENAMETOOLONG, NULL); + assert_pid2path_null(0, long_path, ENAMETOOLONG); free(long_path); } @@ -73,13 +80,13 @@ contents_ok(void **state) { char *real_path = pcmk__str_copy("/ok"); - assert_pid2path(0, real_path, pcmk_rc_ok, real_path); + assert_pid2path_equals(0, real_path, pcmk_rc_ok, real_path); free(real_path); // String length equals PATH_MAX - 1 real_path = pcmk__assert_asprintf("%0*d", PATH_MAX - 1, 0); - assert_pid2path(0, real_path, pcmk_rc_ok, real_path); + assert_pid2path_equals(0, real_path, pcmk_rc_ok, real_path); free(real_path); } diff --git a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c index cfb6bdbf7f5..de7247c76a1 100644 --- a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c @@ -19,43 +19,50 @@ /*! * \internal - * \brief Run one test, comparing return value and output argument + * \brief Run one test, checking return value * - * \param[in] xml Date expression XML - * \param[in] now_s Time to evaluate expression with (as string) - * \param[in] next_change_s If this and \p reference_s are not NULL, initialize - * next change time with this time (as string), - * and assert that its value after evaluation is the - * reference - * \param[in] reference_s If not NULL, time (as string) that next change - * should be after expression evaluation - * \param[in] reference_rc Assert that evaluation result equals this + * \param[in] xml Date expression XML + * \param[in] now_s Time to evaluate expression with + * \param[in] expected_rc Assert that evaluation result equals this */ static void -assert_date_expression(const xmlNode *xml, const char *now_s, - const char *next_change_s, const char *reference_s, - int reference_rc) +assert_date_expr(const xmlNode *xml, const char *now_s, int expected_rc) { - crm_time_t *now = NULL; - crm_time_t *next_change = NULL; - bool check_next_change = (next_change_s != NULL) && (reference_s != NULL); + crm_time_t *now = crm_time_new(now_s); - if (check_next_change) { - next_change = crm_time_new(next_change_s); - } + assert_int_equal(pcmk__evaluate_date_expression(xml, now, NULL), + expected_rc); + crm_time_free(now); +} + +/*! + * \internal + * \brief Run one test, checking return value and output argument + * + * \param[in] xml Date expression XML + * \param[in] now_s Time to evaluate expression with + * \param[in] next_change_s Initialize next change time with this time + * \param[in] expected_s Time that next change should be after expression + * evaluation + * \param[in] expected_rc Assert that evaluation result equals this + */ +static void +assert_date_expr_change(const xmlNode *xml, const char *now_s, + const char *next_change_s, const char *expected_s, + int expected_rc) +{ + crm_time_t *now = crm_time_new(now_s); + crm_time_t *next_change = crm_time_new(next_change_s); + crm_time_t *expected = crm_time_new(expected_s); - now = crm_time_new(now_s); assert_int_equal(pcmk__evaluate_date_expression(xml, now, next_change), - reference_rc); - crm_time_free(now); + expected_rc); - if (check_next_change) { - crm_time_t *reference = crm_time_new(reference_s); + assert_int_equal(crm_time_compare(next_change, expected), 0); - assert_int_equal(crm_time_compare(next_change, reference), 0); - crm_time_free(reference); - crm_time_free(next_change); - } + crm_time_free(now); + crm_time_free(next_change); + crm_time_free(expected); } #define EXPR_LT_VALID \ @@ -82,7 +89,7 @@ null_next_change_ok(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_within_range); + assert_date_expr(xml, "2024-01-01", pcmk_rc_within_range); pcmk__xml_free(xml); } @@ -96,7 +103,7 @@ id_missing(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_ID_MISSING); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -109,7 +116,7 @@ op_invalid(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_OP_INVALID); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -122,7 +129,7 @@ lt_missing_end(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_MISSING_END); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -136,7 +143,7 @@ lt_invalid_end(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_INVALID_END); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -146,20 +153,20 @@ lt_valid(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID); // Now and next change are both before end - assert_date_expression(xml, "2023-01-01 05:00:00", "2024-02-01 10:00:00", - "2024-02-01 10:00:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2023-01-01 05:00:00", "2024-02-01 10:00:00", + "2024-02-01 10:00:00", pcmk_rc_within_range); // Now is before end, next change is after end - assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00", - "2024-02-01 15:00:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00", + "2024-02-01 15:00:00", pcmk_rc_within_range); // Now is equal to end, next change is after end - assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 20:00:00", - "2024-02-01 20:00:00", pcmk_rc_after_range); + assert_date_expr_change(xml, "2024-02-01 15:00:00", "2024-02-01 20:00:00", + "2024-02-01 20:00:00", pcmk_rc_after_range); // Now and next change are both after end - assert_date_expression(xml, "2024-03-01 12:00:00", "2024-02-01 20:00:00", - "2024-02-01 20:00:00", pcmk_rc_after_range); + assert_date_expr_change(xml, "2024-03-01 12:00:00", "2024-02-01 20:00:00", + "2024-02-01 20:00:00", pcmk_rc_after_range); pcmk__xml_free(xml); } @@ -173,7 +180,7 @@ gt_missing_start(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_MISSING_START); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -187,7 +194,7 @@ gt_invalid_start(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_INVALID_START); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -202,24 +209,24 @@ gt_valid(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_VALID); // Now and next change are both before start - assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", - "2024-01-01 11:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", + "2024-01-01 11:00:00", pcmk_rc_before_range); // Now is before start, next change is after start - assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00", - "2024-02-01 12:00:01", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00", + "2024-02-01 12:00:01", pcmk_rc_before_range); // Now is equal to start, next change is after start - assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00", - "2024-02-01 12:00:01", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00", + "2024-02-01 12:00:01", pcmk_rc_before_range); // Now is one second after start, next change is after start - assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 18:00:00", - "2024-02-01 18:00:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 12:00:01", "2024-02-01 18:00:00", + "2024-02-01 18:00:00", pcmk_rc_within_range); // t is after start, next change is after start - assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04", - "2024-04-04 04:04:04", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04", + "2024-04-04 04:04:04", pcmk_rc_within_range); pcmk__xml_free(xml); } @@ -252,7 +259,7 @@ range_invalid_start_invalid_end(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_INVALID_END); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -266,7 +273,7 @@ range_invalid_start_only(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_ONLY); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -281,20 +288,20 @@ range_valid_start_only(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_ONLY); // Now and next change are before start - assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", - "2024-01-01 11:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", + "2024-01-01 11:00:00", pcmk_rc_before_range); // Now is before start, next change is after start - assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00", - "2024-02-01 12:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00", + "2024-02-01 12:00:00", pcmk_rc_before_range); // Now is equal to start, next change is after start - assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00", - "2024-02-01 18:00:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00", + "2024-02-01 18:00:00", pcmk_rc_within_range); // Now and next change are after start - assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04", - "2024-04-04 04:04:04", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04", + "2024-04-04 04:04:04", pcmk_rc_within_range); pcmk__xml_free(xml); } @@ -309,7 +316,7 @@ range_invalid_end_only(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_END_ONLY); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -324,20 +331,20 @@ range_valid_end_only(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_END_ONLY); // Now and next change are before end - assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", - "2024-01-01 11:00:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", + "2024-01-01 11:00:00", pcmk_rc_within_range); // Now is before end, next change is after end - assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now is equal to end, next change is after end - assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now and next change are after end - assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04", - "2024-04-04 04:04:04", pcmk_rc_after_range); + assert_date_expr_change(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04", + "2024-04-04 04:04:04", pcmk_rc_after_range); pcmk__xml_free(xml); } @@ -353,8 +360,7 @@ range_valid_start_invalid_end(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_END); - assert_date_expression(xml, "2024-01-01 04:30:05", NULL, NULL, - pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01 04:30:05", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -369,8 +375,7 @@ range_invalid_start_valid_end(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_VALID_END); - assert_date_expression(xml, "2024-01-01 04:30:05", NULL, NULL, - pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01 04:30:05", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -386,28 +391,28 @@ range_valid_start_valid_end(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_END); // Now and next change are before start - assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", - "2024-01-01 11:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", + "2024-01-01 11:00:00", pcmk_rc_before_range); // Now is before start, next change is between start and end - assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00", - "2024-02-01 12:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00", + "2024-02-01 12:00:00", pcmk_rc_before_range); // Now is equal to start, next change is between start and end - assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00", - "2024-02-01 14:30:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00", + "2024-02-01 14:30:00", pcmk_rc_within_range); // Now is between start and end, next change is after end - assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now is equal to end, next change is after end - assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now and next change are after end - assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04", - "2028-04-04 04:04:04", pcmk_rc_after_range); + assert_date_expr_change(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04", + "2028-04-04 04:04:04", pcmk_rc_after_range); pcmk__xml_free(xml); } @@ -425,8 +430,7 @@ range_valid_start_invalid_duration(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_DURATION); - assert_date_expression(xml, "2024-02-01 04:30:05", NULL, NULL, - pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-02-01 04:30:05", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -444,28 +448,28 @@ range_valid_start_valid_duration(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_DURATION); // Now and next change are before start - assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", - "2024-01-01 11:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00", + "2024-01-01 11:00:00", pcmk_rc_before_range); // Now is before start, next change is between start and end - assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00", - "2024-02-01 12:00:00", pcmk_rc_before_range); + assert_date_expr_change(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00", + "2024-02-01 12:00:00", pcmk_rc_before_range); // Now is equal to start, next change is between start and end - assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00", - "2024-02-01 14:30:00", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00", + "2024-02-01 14:30:00", pcmk_rc_within_range); // Now is between start and end, next change is after end - assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now is equal to end, next change is after end - assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04", - "2024-02-01 15:00:01", pcmk_rc_within_range); + assert_date_expr_change(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04", + "2024-02-01 15:00:01", pcmk_rc_within_range); // Now and next change are after end - assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04", - "2028-04-04 04:04:04", pcmk_rc_after_range); + assert_date_expr_change(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04", + "2028-04-04 04:04:04", pcmk_rc_after_range); pcmk__xml_free(xml); } @@ -484,8 +488,7 @@ range_valid_start_duration_missing_id(void **state) xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_DURATION_MISSING_ID); - assert_date_expression(xml, "2024-02-01 04:30:05", NULL, NULL, - pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-02-01 04:30:05", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -498,7 +501,7 @@ spec_missing(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -514,7 +517,7 @@ spec_invalid(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_INVALID); - assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01", pcmk_rc_unpack_error); pcmk__xml_free(xml); } @@ -532,21 +535,19 @@ spec_valid(void **state) xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_VALID); // Now is just before spec start - assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL, - pcmk_rc_before_range); + assert_date_expr(xml, "2024-01-01 23:59:59", pcmk_rc_before_range); // Now matches spec start - assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok); + assert_date_expr(xml, "2024-02-01 00:00:00", pcmk_rc_ok); // Now is within spec range - assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok); + assert_date_expr(xml, "2024-02-22 22:22:22", pcmk_rc_ok); // Now matches spec end - assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok); + assert_date_expr(xml, "2024-02-29 23:59:59", pcmk_rc_ok); // Now is just past spec end - assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL, - pcmk_rc_after_range); + assert_date_expr(xml, "2024-03-01 00:00:00", pcmk_rc_after_range); pcmk__xml_free(xml); } @@ -563,8 +564,7 @@ spec_missing_id(void **state) { xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING_ID); - assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL, - pcmk_rc_unpack_error); + assert_date_expr(xml, "2024-01-01 23:59:59", pcmk_rc_unpack_error); pcmk__xml_free(xml); } diff --git a/lib/common/tests/xml_comment/pcmk__xc_create_test.c b/lib/common/tests/xml_comment/pcmk__xc_create_test.c index e5afc0d2730..c61bba845de 100644 --- a/lib/common/tests/xml_comment/pcmk__xc_create_test.c +++ b/lib/common/tests/xml_comment/pcmk__xc_create_test.c @@ -18,6 +18,8 @@ * hassle. */ +#define CONTENT "some content" + #define assert_create_comment(content, doc_ptr, node_ptr) \ do { \ xml_doc_private_t *docpriv = NULL; \ @@ -41,25 +43,6 @@ pcmk__xf_dirty|pcmk__xf_created)); \ } while (0) -static void -assert_comment(const char *content) -{ - xmlDoc *doc = NULL; - xmlNode *node = NULL; - - assert_create_comment(content, &doc, &node); - - if (content == NULL) { - assert_null(node->content); - } else { - assert_non_null(node->content); - assert_string_equal((const char *) node->content, content); - } - - pcmk__xml_free(node); - pcmk__xml_free_doc(doc); -} - static void null_doc(void **state) { @@ -70,8 +53,21 @@ null_doc(void **state) static void with_doc(void **state) { - assert_comment(NULL); - assert_comment("some content"); + xmlDoc *doc = NULL; + xmlNode *node = NULL; + + assert_create_comment(NULL, &doc, &node); + assert_null(node->content); + + g_clear_pointer(&node, pcmk__xml_free); + g_clear_pointer(&doc, pcmk__xml_free_doc); + + assert_create_comment(CONTENT, &doc, &node); + assert_non_null(node->content); + assert_string_equal((const char *) node->content, CONTENT); + + g_clear_pointer(&node, pcmk__xml_free); + g_clear_pointer(&doc, pcmk__xml_free_doc); } PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group, From 41e66b3cc92adb342166b8990dd2b52c7e572ebc Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 11:03:26 -0800 Subject: [PATCH 23/40] Refactor: libcrmcommon: Split unit test helpers into true/false cases With a function, the CMocka assert macros showed unhelpful line numbers on error. We want to convert these to macros. Splitting into multiple helpers has two goals. * Make each helper a bit easier to read. * Avoid complaints from the compiler or Coverity. I started making splits after compilation failed due to a NULL strcmp() argument, even though strcmp() would have never actually been *called* with a NULL argument. Macro expansion has unpleasant results sometimes. Signed-off-by: Reid Wahl --- .../pcmk__cib_element_in_patchset_test.c | 85 +++++++++------- .../tests/strings/pcmk__parse_bool_test.c | 79 ++++++++------- .../tests/xml/pcmk__xml_is_name_char_test.c | 98 ++++++++++--------- .../xml/pcmk__xml_is_name_start_char_test.c | 91 +++++++++-------- 4 files changed, 200 insertions(+), 153 deletions(-) diff --git a/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c b/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c index 56cca4e99e1..cf8bfa48bd4 100644 --- a/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c +++ b/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c @@ -30,9 +30,8 @@ "<" PCMK_XE_STATUS "/>" \ "" -static void -assert_in_patchset(const char *source_s, const char *target_s, - const char *element, bool reference) +static xmlNode * +create_patchset(const char *source_s, const char *target_s) { xmlNode *source = pcmk__xml_parse(source_s); xmlNode *target = pcmk__xml_parse(target_s); @@ -42,14 +41,30 @@ assert_in_patchset(const char *source_s, const char *target_s, pcmk__xml_mark_changes(source, target); patchset = xml_create_patchset(2, source, target, NULL, false); - if (reference) { - assert_true(pcmk__cib_element_in_patchset(patchset, element)); - } else { - assert_false(pcmk__cib_element_in_patchset(patchset, element)); - } - pcmk__xml_free(source); pcmk__xml_free(target); + return patchset; +} + +static void +assert_in_patchset(const char *source_s, const char *target_s, + const char *element) +{ + xmlNode *patchset = create_patchset(source_s, target_s); + + assert_true(pcmk__cib_element_in_patchset(patchset, element)); + + pcmk__xml_free(patchset); +} + +static void +assert_not_in_patchset(const char *source_s, const char *target_s, + const char *element) +{ + xmlNode *patchset = create_patchset(source_s, target_s); + + assert_false(pcmk__cib_element_in_patchset(patchset, element)); + pcmk__xml_free(patchset); } @@ -82,28 +97,28 @@ static void create_op(void **state) { // Requested element was created - assert_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_ALERTS, true); + assert_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_ALERTS); // Requested element's descendant was created - assert_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_CONFIGURATION, true); - assert_in_patchset(ORIG_CIB, CREATE_CIB, NULL, true); + assert_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_CONFIGURATION); + assert_in_patchset(ORIG_CIB, CREATE_CIB, NULL); // Requested element was not changed - assert_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_STATUS, false); + assert_not_in_patchset(ORIG_CIB, CREATE_CIB, PCMK_XE_STATUS); } static void delete_op(void **state) { // Requested element was deleted - assert_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_ALERTS, true); + assert_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_ALERTS); // Requested element's descendant was deleted - assert_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_CONFIGURATION, true); - assert_in_patchset(CREATE_CIB, ORIG_CIB, NULL, true); + assert_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_CONFIGURATION); + assert_in_patchset(CREATE_CIB, ORIG_CIB, NULL); // Requested element was not changed - assert_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_STATUS, false); + assert_not_in_patchset(CREATE_CIB, ORIG_CIB, PCMK_XE_STATUS); } // PCMK_XE_CIB XML attribute was added relative to ORIG_CIB @@ -180,31 +195,31 @@ static void modify_op(void **state) { // Requested element was modified (attribute added) - assert_in_patchset(ORIG_CIB, MODIFY_ADD_CIB, PCMK_XE_CIB, true); + assert_in_patchset(ORIG_CIB, MODIFY_ADD_CIB, PCMK_XE_CIB); // Requested element was modified (attribute updated) - assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_CIB, PCMK_XE_CIB, true); + assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_CIB, PCMK_XE_CIB); // Requested element was modified (attribute deleted) - assert_in_patchset(MODIFY_ADD_CIB, ORIG_CIB, PCMK_XE_CIB, true); + assert_in_patchset(MODIFY_ADD_CIB, ORIG_CIB, PCMK_XE_CIB); // Requested element's descendant was modified (attribute added) - assert_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, PCMK_XE_CIB, true); - assert_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, NULL, true); + assert_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, PCMK_XE_CIB); + assert_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, NULL); // Requested element's descendant was modified (attribute updated) - assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, PCMK_XE_CIB, true); - assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, NULL, true); + assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, PCMK_XE_CIB); + assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, NULL); // Requested element's descenant was modified (attribute deleted) - assert_in_patchset(MODIFY_ADD_NODE_CIB, ORIG_CIB, PCMK_XE_CIB, true); - assert_in_patchset(MODIFY_ADD_NODE_CIB, ORIG_CIB, NULL, true); + assert_in_patchset(MODIFY_ADD_NODE_CIB, ORIG_CIB, PCMK_XE_CIB); + assert_in_patchset(MODIFY_ADD_NODE_CIB, ORIG_CIB, NULL); // Requested element was not changed - assert_in_patchset(ORIG_CIB, MODIFY_ADD_CIB, PCMK_XE_STATUS, false); - assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_CIB, PCMK_XE_STATUS, false); - assert_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, PCMK_XE_STATUS, false); - assert_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, PCMK_XE_STATUS, false); + assert_not_in_patchset(ORIG_CIB, MODIFY_ADD_CIB, PCMK_XE_STATUS); + assert_not_in_patchset(ORIG_CIB, MODIFY_UPDATE_CIB, PCMK_XE_STATUS); + assert_not_in_patchset(ORIG_CIB, MODIFY_ADD_NODE_CIB, PCMK_XE_STATUS); + assert_not_in_patchset(ORIG_CIB, MODIFY_UPDATE_NODE_CIB, PCMK_XE_STATUS); } // PCMK_XE_RESOURCES and PCMK_XE_CONSTRAINTS are swapped relative to ORIG_CIB @@ -225,15 +240,15 @@ static void move_op(void **state) { // Requested element was moved - assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_RESOURCES, true); - assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_CONSTRAINTS, true); + assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_RESOURCES); + assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_CONSTRAINTS); // Requested element's descendant was moved - assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_CONFIGURATION, true); - assert_in_patchset(ORIG_CIB, MOVE_CIB, NULL, true); + assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_CONFIGURATION); + assert_in_patchset(ORIG_CIB, MOVE_CIB, NULL); // Requested element was not changed - assert_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_STATUS, false); + assert_not_in_patchset(ORIG_CIB, MOVE_CIB, PCMK_XE_STATUS); } PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group, diff --git a/lib/common/tests/strings/pcmk__parse_bool_test.c b/lib/common/tests/strings/pcmk__parse_bool_test.c index 196bf04ae0b..f0d15556585 100644 --- a/lib/common/tests/strings/pcmk__parse_bool_test.c +++ b/lib/common/tests/strings/pcmk__parse_bool_test.c @@ -15,13 +15,12 @@ /*! * \internal - * \brief Check \c pcmk__parse_bool() succeeds and parses the input as expected + * \brief Check \c pcmk__parse_bool() succeeds and parses the input to true * - * \param[in] input Input string - * \param[in] expected_result Expected parsed value + * \param[in] input Input string */ static void -assert_parse_bool(const char *input, bool expected_result) +assert_parse_bool_true(const char *input) { bool result = false; @@ -29,23 +28,37 @@ assert_parse_bool(const char *input, bool expected_result) assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - - if (expected_result) { - assert_true(result); - } else { - assert_false(result); - } + assert_true(result); // Repeat with result initially set to true result = true; assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); + assert_true(result); +} + +/*! + * \internal + * \brief Check \c pcmk__parse_bool() succeeds and parses the input to false + * + * \param[in] input Input string + */ +static void +assert_parse_bool_false(const char *input) +{ + bool result = false; - if (expected_result) { - assert_true(result); - } else { - assert_false(result); - } + // Ensure we still validate the string with a NULL result argument + assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); + + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); + assert_false(result); + + // Repeat with result initially set to true + result = true; + + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); + assert_false(result); } /*! @@ -87,15 +100,15 @@ bad_input(void **state) static void is_true(void **state) { - assert_parse_bool("true", true); - assert_parse_bool("TrUe", true); - assert_parse_bool("on", true); - assert_parse_bool("ON", true); - assert_parse_bool("yes", true); - assert_parse_bool("yES", true); - assert_parse_bool("y", true); - assert_parse_bool("Y", true); - assert_parse_bool("1", true); + assert_parse_bool_true("true"); + assert_parse_bool_true("TrUe"); + assert_parse_bool_true("on"); + assert_parse_bool_true("ON"); + assert_parse_bool_true("yes"); + assert_parse_bool_true("yES"); + assert_parse_bool_true("y"); + assert_parse_bool_true("Y"); + assert_parse_bool_true("1"); } static void @@ -111,15 +124,15 @@ is_not_true(void **state) static void is_false(void **state) { - assert_parse_bool("false", false); - assert_parse_bool("fAlSe", false); - assert_parse_bool("off", false); - assert_parse_bool("OFF", false); - assert_parse_bool("no", false); - assert_parse_bool("No", false); - assert_parse_bool("n", false); - assert_parse_bool("N", false); - assert_parse_bool("0", false); + assert_parse_bool_false("false"); + assert_parse_bool_false("fAlSe"); + assert_parse_bool_false("off"); + assert_parse_bool_false("OFF"); + assert_parse_bool_false("no"); + assert_parse_bool_false("No"); + assert_parse_bool_false("n"); + assert_parse_bool_false("N"); + assert_parse_bool_false("0"); } static void diff --git a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c index 2187fb99683..333fd2bdcf9 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c @@ -19,27 +19,37 @@ /*! * \internal - * \brief Assert that a Unicode character is (not) a valid XML \c NameChar + * \brief Assert that a Unicode character is a valid XML \c NameChar * - * \param[in] c Unicode code point of character to check - * \param[in] reference If \c true, \p c should be considered a valid - * \c NameChar; if \c false, it should not + * \param[in] code_pt Unicode code point of character to check */ static void -assert_name_char(int c, bool reference) +assert_name_char(int code_pt) { gchar utf8_buf[6] = { 0, }; int len = 4; - int ref_len = g_unichar_to_utf8(c, utf8_buf); - bool result = pcmk__xml_is_name_char(utf8_buf, &len); + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - if (reference) { - assert_true(result); - } else { - assert_false(result); - } + assert_true(pcmk__xml_is_name_char(utf8_buf, &len)); + assert_int_equal(len, ref_len); +} + +/*! + * \internal + * \brief Assert that a Unicode character is not a valid XML \c NameChar + * + * \param[in] code_pt Unicode code point of character to check + */ +static void +assert_not_name_char(int code_pt) +{ + gchar utf8_buf[6] = { 0, }; + int len = 4; + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); + + assert_false(pcmk__xml_is_name_char(utf8_buf, &len)); - if ((c < 0xD800) || (c > 0xDFFF)) { + if ((code_pt < 0xD800) || (code_pt > 0xDFFF)) { /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate * pair halves. They can be represented in UTF-8, but they shouldn't * appear in valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they @@ -70,9 +80,9 @@ ascii(void **state) if (g_ascii_isalnum(c) || c == ':' || c == '_' || c == '-' || c == '.') { - assert_name_char(c, true); + assert_name_char(c); } else { - assert_name_char(c, false); + assert_not_name_char(c); } } } @@ -81,21 +91,21 @@ static void unicode_0x80_to_0xB6(void **state) { for (int c = 0x80; c <= 0xB6; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } static void unicode_0xB7(void **state) { - assert_name_char(0xB7, true); + assert_name_char(0xB7); } static void unicode_0xB8_to_0xBF(void **state) { for (int c = 0xB8; c <= 0xBF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -103,35 +113,35 @@ static void unicode_0xC0_to_0xD6(void **state) { for (int c = 0xC0; c <= 0xD6; c++) { - assert_name_char(c, true); + assert_name_char(c); } } static void unicode_0xD7(void **state) { - assert_name_char(0xD7, false); + assert_not_name_char(0xD7); } static void unicode_0xD8_to_0xF6(void **state) { for (int c = 0xD8; c <= 0xF6; c++) { - assert_name_char(c, true); + assert_name_char(c); } } static void unicode_0xF7(void **state) { - assert_name_char(0xF7, false); + assert_not_name_char(0xF7); } static void unicode_0xF8_to_0x2FF(void **state) { for (int c = 0xF8; c <= 0x2FF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -139,7 +149,7 @@ static void unicode_0x300_to_0x36F(void **state) { for (int c = 0x300; c <= 0x36F; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -147,21 +157,21 @@ static void unicode_0x370_to_0x37D(void **state) { for (int c = 0x370; c <= 0x37D; c++) { - assert_name_char(c, true); + assert_name_char(c); } } static void unicode_0x37E(void **state) { - assert_name_char(0x37E, false); + assert_not_name_char(0x37E); } static void unicode_0x37F_to_0x1FFF(void **state) { for (int c = 0x37F; c <= 0x1FFF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -169,7 +179,7 @@ static void unicode_0x2000_to_0x200B(void **state) { for (int c = 0x2000; c <= 0x200B; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -177,7 +187,7 @@ static void unicode_0x200C_to_0x200D(void **state) { for (int c = 0x200C; c <= 0x200D; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -185,7 +195,7 @@ static void unicode_0x200E_to_0x203E(void **state) { for (int c = 0x200E; c <= 0x203E; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -193,7 +203,7 @@ static void unicode_0x203F_to_0x2040(void **state) { for (int c = 0x203F; c <= 0x2040; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -201,7 +211,7 @@ static void unicode_0x2041_to_0x206F(void **state) { for (int c = 0x2041; c <= 0x206F; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -209,7 +219,7 @@ static void unicode_0x2070_to_0x218F(void **state) { for (int c = 0x2070; c <= 0x218F; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -217,7 +227,7 @@ static void unicode_0x2190_to_0x2BFF(void **state) { for (int c = 0x2190; c <= 0x2BFF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -225,7 +235,7 @@ static void unicode_0x2C00_to_0x2FEF(void **state) { for (int c = 0x2C00; c <= 0x2FEF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -233,7 +243,7 @@ static void unicode_0x2FF0_to_0x3000(void **state) { for (int c = 0x2FF0; c <= 0x3000; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -241,7 +251,7 @@ static void unicode_0x3001_to_0xD7FF(void **state) { for (int c = 0x3001; c <= 0xD7FF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -249,7 +259,7 @@ static void unicode_0xD800_to_0xF8FF(void **state) { for (int c = 0xD800; c <= 0xF8FF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -257,7 +267,7 @@ static void unicode_0xF900_to_0xFDCF(void **state) { for (int c = 0xF900; c <= 0xFDCF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -265,7 +275,7 @@ static void unicode_0xFDD0_to_0xFDEF(void **state) { for (int c = 0xFDD0; c <= 0xFDEF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -273,7 +283,7 @@ static void unicode_0xFDF0_to_0xFFFD(void **state) { for (int c = 0xFDF0; c <= 0xFFFD; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -281,7 +291,7 @@ static void unicode_0xFFFE_to_0xFFFF(void **state) { for (int c = 0xFFFE; c <= 0xFFFF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } @@ -289,7 +299,7 @@ static void unicode_0x10000_to_0xEFFFF(void **state) { for (int c = 0x10000; c <= 0xEFFFF; c++) { - assert_name_char(c, true); + assert_name_char(c); } } @@ -297,7 +307,7 @@ static void unicode_0xF0000_to_0x10FFFF(void **state) { for (int c = 0xF0000; c <= 0x10FFFF; c++) { - assert_name_char(c, false); + assert_not_name_char(c); } } diff --git a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c index 5d264a6c67a..978f217f879 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c @@ -12,7 +12,6 @@ #include #include // gchar, g_ascii_isalpha(), etc. -#include // xmlGetUTF8Char() #include @@ -20,27 +19,37 @@ /*! * \internal - * \brief Assert that a Unicode character is (not) a valid XML \c NameStartChar + * \brief Assert that a Unicode character is a valid XML \c NameStartChar * - * \param[in] c Unicode code point of character to check - * \param[in] reference If \c true, \p c should be considered a valid - * \c NameStartChar; if \c false, it should not + * \param[in] code_pt Unicode code point of character to check */ static void -assert_name_start_char(int c, bool reference) +assert_name_start_char(int code_pt) { gchar utf8_buf[6] = { 0, }; int len = 4; - int ref_len = g_unichar_to_utf8(c, utf8_buf); - bool result = pcmk__xml_is_name_start_char(utf8_buf, &len); + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - if (reference) { - assert_true(result); - } else { - assert_false(result); - } + assert_true(pcmk__xml_is_name_start_char(utf8_buf, &len)); + assert_int_equal(len, ref_len); +} + +/*! + * \internal + * \brief Assert that a Unicode character is not a valid XML \c NameStartChar + * + * \param[in] code_pt Unicode code point of character to check + */ +static void +assert_not_name_start_char(int code_pt) +{ + gchar utf8_buf[6] = { 0, }; + int len = 4; + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); + + assert_false(pcmk__xml_is_name_start_char(utf8_buf, &len)); - if ((c < 0xD800) || (c > 0xDFFF)) { + if ((code_pt < 0xD800) || (code_pt > 0xDFFF)) { /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate * pair halves. They can be represented in UTF-8, but they shouldn't * appear in valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they @@ -69,9 +78,9 @@ ascii(void **state) { for (int c = 0x00; c <= 0x7F; c++) { if (g_ascii_isalpha(c) || c == ':' || c == '_') { - assert_name_start_char(c, true); + assert_name_start_char(c); } else { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } } @@ -80,7 +89,7 @@ static void unicode_0x80_to_0xBF(void **state) { for (int c = 0x80; c <= 0xBF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -88,35 +97,35 @@ static void unicode_0xC0_to_0xD6(void **state) { for (int c = 0xC0; c <= 0xD6; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } static void unicode_0xD7(void **state) { - assert_name_start_char(0xD7, false); + assert_not_name_start_char(0xD7); } static void unicode_0xD8_to_0xF6(void **state) { for (int c = 0xD8; c <= 0xF6; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } static void unicode_0xF7(void **state) { - assert_name_start_char(0xF7, false); + assert_not_name_start_char(0xF7); } static void unicode_0xF8_to_0x2FF(void **state) { for (int c = 0xF8; c <= 0x2FF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -124,7 +133,7 @@ static void unicode_0x300_to_0x36F(void **state) { for (int c = 0x300; c <= 0x36F; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -132,21 +141,21 @@ static void unicode_0x370_to_0x37D(void **state) { for (int c = 0x370; c <= 0x37D; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } static void unicode_0x37E(void **state) { - assert_name_start_char(0x37E, false); + assert_not_name_start_char(0x37E); } static void unicode_0x37F_to_0x1FFF(void **state) { for (int c = 0x37F; c <= 0x1FFF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -154,7 +163,7 @@ static void unicode_0x2000_to_0x200B(void **state) { for (int c = 0x2000; c <= 0x200B; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -162,7 +171,7 @@ static void unicode_0x200C_to_0x200D(void **state) { for (int c = 0x200C; c <= 0x200D; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -170,7 +179,7 @@ static void unicode_0x200E_to_0x206F(void **state) { for (int c = 0x200E; c <= 0x206F; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -178,7 +187,7 @@ static void unicode_0x2070_to_0x218F(void **state) { for (int c = 0x2070; c <= 0x218F; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -186,7 +195,7 @@ static void unicode_0x2190_to_0x2BFF(void **state) { for (int c = 0x2190; c <= 0x2BFF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -194,7 +203,7 @@ static void unicode_0x2C00_to_0x2FEF(void **state) { for (int c = 0x2C00; c <= 0x2FEF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -202,7 +211,7 @@ static void unicode_0x2FF0_to_0x3000(void **state) { for (int c = 0x2FF0; c <= 0x3000; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -210,7 +219,7 @@ static void unicode_0x3001_to_0xD7FF(void **state) { for (int c = 0x3001; c <= 0xD7FF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -218,7 +227,7 @@ static void unicode_0xD800_to_0xF8FF(void **state) { for (int c = 0xD800; c <= 0xF8FF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -226,7 +235,7 @@ static void unicode_0xF900_to_0xFDCF(void **state) { for (int c = 0xF900; c <= 0xFDCF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -234,7 +243,7 @@ static void unicode_0xFDD0_to_0xFDEF(void **state) { for (int c = 0xFDD0; c <= 0xFDEF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -242,7 +251,7 @@ static void unicode_0xFDF0_to_0xFFFD(void **state) { for (int c = 0xFDF0; c <= 0xFFFD; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -250,7 +259,7 @@ static void unicode_0xFFFE_to_0xFFFF(void **state) { for (int c = 0xFFFE; c <= 0xFFFF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } @@ -258,7 +267,7 @@ static void unicode_0x10000_to_0xEFFFF(void **state) { for (int c = 0x10000; c <= 0xEFFFF; c++) { - assert_name_start_char(c, true); + assert_name_start_char(c); } } @@ -266,7 +275,7 @@ static void unicode_0xF0000_to_0x10FFFF(void **state) { for (int c = 0xF0000; c <= 0x10FFFF; c++) { - assert_name_start_char(c, false); + assert_not_name_start_char(c); } } From c2d1fb6b2d9283c81790f94c2ab2a849a15e2bc1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 11:27:46 -0800 Subject: [PATCH 24/40] Refactor: libcrmcommon: Split out unit tests for 0xD800 to 0xDFFF ...in pcmk__is_name_char() and pcmk__is_name_start_char() unit tests. We need to treat these specially (see comments). The end goal is to convert the helper functions to macros. With a function, the CMocka assert macros show unhelpful line numbers on error. I'm doing this with two goals: * Make the helpers a bit easier to read. * Avoid complaints from the compiler or Coverity. I started making splits after compilation failed due to a NULL strcmp() argument, even though strcmp() would have never actually been *called* with a NULL argument. Macro expansion has unpleasant results sometimes. I'm paranoid that more things like this might appear. Signed-off-by: Reid Wahl --- .../tests/xml/pcmk__xml_is_name_char_test.c | 48 +++++++++++-------- .../xml/pcmk__xml_is_name_start_char_test.c | 48 +++++++++++-------- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c index 333fd2bdcf9..0e4c45859ad 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c @@ -48,22 +48,7 @@ assert_not_name_char(int code_pt) int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); assert_false(pcmk__xml_is_name_char(utf8_buf, &len)); - - if ((code_pt < 0xD800) || (code_pt > 0xDFFF)) { - /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate - * pair halves. They can be represented in UTF-8, but they shouldn't - * appear in valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they - * should be treated as invalid: - * https://en.wikipedia.org/wiki/UTF-8#Invalid_sequences_and_error_handling. - * - * GLib treats these characters as valid and returns a length of 3 - * bytes. So did libxml until v2.12 (commit 845bd99). Since that commit, - * libxml treats these characters as invalid and returns a length of 0. - * To avoid version-dependent testing behavior, skip the length check - * for code points in that range. - */ - assert_int_equal(len, ref_len); - } + assert_int_equal(len, ref_len); } static void @@ -256,9 +241,33 @@ unicode_0x3001_to_0xD7FF(void **state) } static void -unicode_0xD800_to_0xF8FF(void **state) +unicode_0xD800_to_0xDFFF(void **state) +{ + /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate pair + * halves. They can be represented in UTF-8, but they shouldn't appear in + * valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they should be treated + * as invalid: + * https://en.wikipedia.org/wiki/UTF-8#Invalid_sequences_and_error_handling. + * + * GLib treats these characters as valid and returns a length of 3 bytes. So + * did libxml until v2.12 (commit 845bd99). Since that commit, libxml treats + * these characters as invalid and returns a length of 0. To avoid version- + * dependent testing behavior, skip the length check for code points in that + * range. This means we don't use the helper. + */ + for (int c = 0xD800; c <= 0xDFFF; c++) { + gchar utf8_buf[6] = { 0, }; + + g_unichar_to_utf8(c, utf8_buf); + + assert_false(pcmk__xml_is_name_char(utf8_buf, NULL)); + } +} + +static void +unicode_0xE000_to_0xF8FF(void **state) { - for (int c = 0xD800; c <= 0xF8FF; c++) { + for (int c = 0xE000; c <= 0xF8FF; c++) { assert_not_name_char(c); } } @@ -336,7 +345,8 @@ PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(unicode_0x2C00_to_0x2FEF), cmocka_unit_test(unicode_0x2FF0_to_0x3000), cmocka_unit_test(unicode_0x3001_to_0xD7FF), - cmocka_unit_test(unicode_0xD800_to_0xF8FF), + cmocka_unit_test(unicode_0xD800_to_0xDFFF), + cmocka_unit_test(unicode_0xE000_to_0xF8FF), cmocka_unit_test(unicode_0xF900_to_0xFDCF), cmocka_unit_test(unicode_0xFDD0_to_0xFDEF), cmocka_unit_test(unicode_0xFDF0_to_0xFFFD), diff --git a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c index 978f217f879..dfc2d785abe 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c @@ -48,22 +48,7 @@ assert_not_name_start_char(int code_pt) int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); assert_false(pcmk__xml_is_name_start_char(utf8_buf, &len)); - - if ((code_pt < 0xD800) || (code_pt > 0xDFFF)) { - /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate - * pair halves. They can be represented in UTF-8, but they shouldn't - * appear in valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they - * should be treated as invalid: - * https://en.wikipedia.org/wiki/UTF-8#Invalid_sequences_and_error_handling. - * - * GLib treats these characters as valid and returns a length of 3 - * bytes. So did libxml until v2.12 (commit 845bd99). Since that commit, - * libxml treats these characters as invalid and returns a length of 0. - * To avoid version-dependent testing behavior, skip the length check - * for code points in that range. - */ - assert_int_equal(len, ref_len); - } + assert_int_equal(len, ref_len); } static void @@ -224,9 +209,33 @@ unicode_0x3001_to_0xD7FF(void **state) } static void -unicode_0xD800_to_0xF8FF(void **state) +unicode_0xD800_to_0xDFFF(void **state) +{ + /* Unicode code points in the range D800 to DFFF are UTF-16 surrogate pair + * halves. They can be represented in UTF-8, but they shouldn't appear in + * valid UTF-8-encoded text. RFC 3629 (Nov 2003) says they should be treated + * as invalid: + * https://en.wikipedia.org/wiki/UTF-8#Invalid_sequences_and_error_handling. + * + * GLib treats these characters as valid and returns a length of 3 bytes. So + * did libxml until v2.12 (commit 845bd99). Since that commit, libxml treats + * these characters as invalid and returns a length of 0. To avoid version- + * dependent testing behavior, skip the length check for code points in that + * range. This means we don't use the helper. + */ + for (int c = 0xD800; c <= 0xDFFF; c++) { + gchar utf8_buf[6] = { 0, }; + + g_unichar_to_utf8(c, utf8_buf); + + assert_false(pcmk__xml_is_name_start_char(utf8_buf, NULL)); + } +} + +static void +unicode_0xE000_to_0xF8FF(void **state) { - for (int c = 0xD800; c <= 0xF8FF; c++) { + for (int c = 0xE000; c <= 0xF8FF; c++) { assert_not_name_start_char(c); } } @@ -300,7 +309,8 @@ PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(unicode_0x2C00_to_0x2FEF), cmocka_unit_test(unicode_0x2FF0_to_0x3000), cmocka_unit_test(unicode_0x3001_to_0xD7FF), - cmocka_unit_test(unicode_0xD800_to_0xF8FF), + cmocka_unit_test(unicode_0xD800_to_0xDFFF), + cmocka_unit_test(unicode_0xE000_to_0xF8FF), cmocka_unit_test(unicode_0xF900_to_0xFDCF), cmocka_unit_test(unicode_0xFDD0_to_0xFDEF), cmocka_unit_test(unicode_0xFDF0_to_0xFFFD), From 138cd0fa50b3bf6e391b6081b60682e4d8e89e45 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 17:20:39 -0800 Subject: [PATCH 25/40] Refactor: libcrmcommon: Use constant in pcmk__xe_get_score() test And drop redundant extern declarations. They're already part of the included headers. Signed-off-by: Reid Wahl --- .../xml_element/pcmk__xe_get_score_test.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/common/tests/xml_element/pcmk__xe_get_score_test.c b/lib/common/tests/xml_element/pcmk__xe_get_score_test.c index ef2acce9ae5..66a7743a700 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_score_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_score_test.c @@ -14,9 +14,7 @@ #include #include -extern int pcmk__score_red; -extern int pcmk__score_green; -extern int pcmk__score_yellow; +#define ATTR_NAME "test_attr" static int default_score = 99; @@ -27,8 +25,8 @@ assert_score(const char *score_s, int expected_rc, int expected_score) int rc = pcmk_rc_ok; xmlNode *xml = pcmk__xe_create(NULL, __func__); - pcmk__xe_set(xml, "test_attr", score_s); - rc = pcmk__xe_get_score(xml, "test_attr", &score, default_score); + pcmk__xe_set(xml, ATTR_NAME, score_s); + rc = pcmk__xe_get_score(xml, ATTR_NAME, &score, default_score); assert_int_equal(rc, expected_rc); assert_int_equal(score, expected_score); pcmk__xml_free(xml); @@ -70,15 +68,15 @@ null_score(void **state) { xmlNode *xml = pcmk__xe_create(NULL, __func__); - assert_int_equal(pcmk__xe_get_score(xml, "test_attr", NULL, default_score), + assert_int_equal(pcmk__xe_get_score(xml, ATTR_NAME, NULL, default_score), pcmk_rc_ok); - pcmk__xe_set(xml, "test_attr", "0"); - assert_int_equal(pcmk__xe_get_score(xml, "test_attr", NULL, default_score), + pcmk__xe_set(xml, ATTR_NAME, "0"); + assert_int_equal(pcmk__xe_get_score(xml, ATTR_NAME, NULL, default_score), pcmk_rc_ok); - pcmk__xe_set(xml, "test_attr", "foo"); - assert_int_equal(pcmk__xe_get_score(xml, "test_attr", NULL, default_score), + pcmk__xe_set(xml, ATTR_NAME, "foo"); + assert_int_equal(pcmk__xe_get_score(xml, ATTR_NAME, NULL, default_score), pcmk_rc_bad_input); pcmk__xml_free(xml); From f88248ace98ae3a5fb0397f4a05c056f937cbf08 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 17:31:43 -0800 Subject: [PATCH 26/40] Refactor: libcrmcommon: Use constant in pcmk__xe_set_score() test Signed-off-by: Reid Wahl --- .../xml_element/pcmk__xe_set_score_test.c | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c index 08b1a8d3c88..d8c24e0bb1d 100644 --- a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c @@ -15,11 +15,13 @@ #include "crmcommon_private.h" // pcmk__xe_set_score() +#define ATTR_NAME "test_attr" + /*! * \internal * \brief Update an XML attribute value and check it against a reference value * - * The attribute name is hard-coded as \c "X". + * The attribute name is hard-coded as \c ATTR_NAME. * * \param[in] initial Initial value * \param[in] new Value to set @@ -30,12 +32,11 @@ static void assert_set_score(const char *initial, const char *new, const char *reference_val, int reference_rc) { - const char *name = "X"; xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); - pcmk__xe_set(test_xml, name, initial); - assert_int_equal(pcmk__xe_set_score(test_xml, name, new), reference_rc); - assert_string_equal(pcmk__xe_get(test_xml, name), reference_val); + pcmk__xe_set(test_xml, ATTR_NAME, initial); + assert_int_equal(pcmk__xe_set_score(test_xml, ATTR_NAME, new), reference_rc); + assert_string_equal(pcmk__xe_get(test_xml, ATTR_NAME), reference_val); pcmk__xml_free(test_xml); } @@ -43,13 +44,13 @@ assert_set_score(const char *initial, const char *new, static void value_is_name_plus_plus(void **state) { - assert_set_score("5", "X++", "6", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "++", "6", pcmk_rc_ok); } static void value_is_name_plus_equals_integer(void **state) { - assert_set_score("5", "X+=2", "7", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=2", "7", pcmk_rc_ok); } // NULL input @@ -58,7 +59,8 @@ static void target_is_NULL(void **state) { // Dumps core via CRM_CHECK() - assert_int_equal(pcmk__xe_set_score(NULL, "X", "X++"), EINVAL); + assert_int_equal(pcmk__xe_set_score(NULL, ATTR_NAME, ATTR_NAME "++"), + EINVAL); } static void @@ -66,11 +68,12 @@ name_is_NULL(void **state) { xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); - pcmk__xe_set(test_xml, "X", "5"); + pcmk__xe_set(test_xml, ATTR_NAME, "5"); // Dumps core via CRM_CHECK() - assert_int_equal(pcmk__xe_set_score(test_xml, NULL, "X++"), EINVAL); - assert_string_equal(pcmk__xe_get(test_xml, "X"), "5"); + assert_int_equal(pcmk__xe_set_score(test_xml, NULL, ATTR_NAME "++"), + EINVAL); + assert_string_equal(pcmk__xe_get(test_xml, ATTR_NAME), "5"); pcmk__xml_free(test_xml); } @@ -86,7 +89,8 @@ value_is_NULL(void **state) static void value_is_wrong_name(void **state) { - assert_set_score("5", "Y++", "Y++", pcmk_rc_ok); + assert_set_score("5", "garbage" ATTR_NAME "++", "garbage" ATTR_NAME "++", + pcmk_rc_ok); } static void @@ -100,55 +104,55 @@ value_is_only_an_integer(void **state) static void variable_is_initialized_to_be_non_numeric(void **state) { - assert_set_score("hello", "X++", "1", pcmk_rc_ok); + assert_set_score("hello", ATTR_NAME "++", "1", pcmk_rc_ok); } static void variable_is_initialized_to_be_non_numeric_2(void **state) { - assert_set_score("hello", "X+=2", "2", pcmk_rc_ok); + assert_set_score("hello", ATTR_NAME "+=2", "2", pcmk_rc_ok); } static void variable_is_initialized_to_be_numeric_and_decimal_point_containing(void **state) { - assert_set_score("5.01", "X++", "6", pcmk_rc_ok); + assert_set_score("5.01", ATTR_NAME "++", "6", pcmk_rc_ok); } static void variable_is_initialized_to_be_numeric_and_decimal_point_containing_2(void **state) { - assert_set_score("5.50", "X++", "6", pcmk_rc_ok); + assert_set_score("5.50", ATTR_NAME "++", "6", pcmk_rc_ok); } static void variable_is_initialized_to_be_numeric_and_decimal_point_containing_3(void **state) { - assert_set_score("5.99", "X++", "6", pcmk_rc_ok); + assert_set_score("5.99", ATTR_NAME "++", "6", pcmk_rc_ok); } static void value_is_non_numeric(void **state) { - assert_set_score("5", "X+=hello", "5", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=hello", "5", pcmk_rc_ok); } static void value_is_numeric_and_decimal_point_containing(void **state) { - assert_set_score("5", "X+=2.01", "7", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=2.01", "7", pcmk_rc_ok); } static void value_is_numeric_and_decimal_point_containing_2(void **state) { - assert_set_score("5", "X+=1.50", "6", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=1.50", "6", pcmk_rc_ok); } static void value_is_numeric_and_decimal_point_containing_3(void **state) { - assert_set_score("5", "X+=1.99", "6", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=1.99", "6", pcmk_rc_ok); } // undefined input @@ -156,7 +160,7 @@ value_is_numeric_and_decimal_point_containing_3(void **state) static void name_is_undefined(void **state) { - assert_set_score(NULL, "X++", "X++", pcmk_rc_ok); + assert_set_score(NULL, ATTR_NAME "++", ATTR_NAME "++", pcmk_rc_ok); } // large input @@ -164,7 +168,7 @@ name_is_undefined(void **state) static void assignment_result_is_too_large(void **state) { - assert_set_score("5", "X+=100000000000", "1000000", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=100000000000", "1000000", pcmk_rc_ok); } PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group, From 703a0cf9a48c22d7c055c2a6648c574e7a7e49e2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 17:40:35 -0800 Subject: [PATCH 27/40] Refactor: libcrmcommon: Shorten test names for pcmk__xe_set_score() Signed-off-by: Reid Wahl --- .../xml_element/pcmk__xe_set_score_test.c | 91 +++++++------------ 1 file changed, 31 insertions(+), 60 deletions(-) diff --git a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c index d8c24e0bb1d..440737ce52d 100644 --- a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c @@ -42,13 +42,13 @@ assert_set_score(const char *initial, const char *new, } static void -value_is_name_plus_plus(void **state) +new_value_name_plus_plus(void **state) { assert_set_score("5", ATTR_NAME "++", "6", pcmk_rc_ok); } static void -value_is_name_plus_equals_integer(void **state) +new_value_name_plus_equals_integer(void **state) { assert_set_score("5", ATTR_NAME "+=2", "7", pcmk_rc_ok); } @@ -56,7 +56,7 @@ value_is_name_plus_equals_integer(void **state) // NULL input static void -target_is_NULL(void **state) +null_target(void **state) { // Dumps core via CRM_CHECK() assert_int_equal(pcmk__xe_set_score(NULL, ATTR_NAME, ATTR_NAME "++"), @@ -64,7 +64,7 @@ target_is_NULL(void **state) } static void -name_is_NULL(void **state) +null_name(void **state) { xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); @@ -79,7 +79,7 @@ name_is_NULL(void **state) } static void -value_is_NULL(void **state) +null_new_value(void **state) { assert_set_score("5", NULL, "5", pcmk_rc_ok); } @@ -87,14 +87,14 @@ value_is_NULL(void **state) // the value input doesn't start with the name input static void -value_is_wrong_name(void **state) +new_value_wrong_name(void **state) { assert_set_score("5", "garbage" ATTR_NAME "++", "garbage" ATTR_NAME "++", pcmk_rc_ok); } static void -value_is_only_an_integer(void **state) +new_value_bare_integer(void **state) { assert_set_score("5", "2", "2", pcmk_rc_ok); } @@ -102,91 +102,62 @@ value_is_only_an_integer(void **state) // non-integers static void -variable_is_initialized_to_be_non_numeric(void **state) +initial_value_non_numeric(void **state) { assert_set_score("hello", ATTR_NAME "++", "1", pcmk_rc_ok); -} - -static void -variable_is_initialized_to_be_non_numeric_2(void **state) -{ assert_set_score("hello", ATTR_NAME "+=2", "2", pcmk_rc_ok); } static void -variable_is_initialized_to_be_numeric_and_decimal_point_containing(void **state) +initial_value_decimal(void **state) { assert_set_score("5.01", ATTR_NAME "++", "6", pcmk_rc_ok); -} - -static void -variable_is_initialized_to_be_numeric_and_decimal_point_containing_2(void **state) -{ assert_set_score("5.50", ATTR_NAME "++", "6", pcmk_rc_ok); -} - -static void -variable_is_initialized_to_be_numeric_and_decimal_point_containing_3(void **state) -{ assert_set_score("5.99", ATTR_NAME "++", "6", pcmk_rc_ok); } static void -value_is_non_numeric(void **state) +new_value_non_numeric(void **state) { assert_set_score("5", ATTR_NAME "+=hello", "5", pcmk_rc_ok); } static void -value_is_numeric_and_decimal_point_containing(void **state) +new_value_decimal(void **state) { assert_set_score("5", ATTR_NAME "+=2.01", "7", pcmk_rc_ok); -} - -static void -value_is_numeric_and_decimal_point_containing_2(void **state) -{ assert_set_score("5", ATTR_NAME "+=1.50", "6", pcmk_rc_ok); -} - -static void -value_is_numeric_and_decimal_point_containing_3(void **state) -{ assert_set_score("5", ATTR_NAME "+=1.99", "6", pcmk_rc_ok); } -// undefined input - static void -name_is_undefined(void **state) +initial_value_unset(void **state) { assert_set_score(NULL, ATTR_NAME "++", ATTR_NAME "++", pcmk_rc_ok); } -// large input +// https://gcc.gnu.org/onlinedocs/gcc-15.2.0/cpp/Stringizing.html +#define xstr(s) str(s) +#define str(s) #s static void -assignment_result_is_too_large(void **state) +new_value_overflows(void **state) { - assert_set_score("5", ATTR_NAME "+=100000000000", "1000000", pcmk_rc_ok); + assert_set_score("5", ATTR_NAME "+=100000000000", xstr(PCMK_SCORE_INFINITY), + pcmk_rc_ok); } PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group, - cmocka_unit_test(value_is_name_plus_plus), - cmocka_unit_test(value_is_name_plus_equals_integer), - cmocka_unit_test(target_is_NULL), - cmocka_unit_test(name_is_NULL), - cmocka_unit_test(value_is_NULL), - cmocka_unit_test(value_is_wrong_name), - cmocka_unit_test(value_is_only_an_integer), - cmocka_unit_test(variable_is_initialized_to_be_non_numeric), - cmocka_unit_test(variable_is_initialized_to_be_non_numeric_2), - cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing), - cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing_2), - cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing_3), - cmocka_unit_test(value_is_non_numeric), - cmocka_unit_test(value_is_numeric_and_decimal_point_containing), - cmocka_unit_test(value_is_numeric_and_decimal_point_containing_2), - cmocka_unit_test(value_is_numeric_and_decimal_point_containing_3), - cmocka_unit_test(name_is_undefined), - cmocka_unit_test(assignment_result_is_too_large)) + cmocka_unit_test(new_value_name_plus_plus), + cmocka_unit_test(new_value_name_plus_equals_integer), + cmocka_unit_test(null_target), + cmocka_unit_test(null_name), + cmocka_unit_test(null_new_value), + cmocka_unit_test(new_value_wrong_name), + cmocka_unit_test(new_value_bare_integer), + cmocka_unit_test(initial_value_non_numeric), + cmocka_unit_test(initial_value_decimal), + cmocka_unit_test(new_value_non_numeric), + cmocka_unit_test(new_value_decimal), + cmocka_unit_test(initial_value_unset), + cmocka_unit_test(new_value_overflows)) From e7361aa2ab07040a9e27c9408965a636e59652f5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 18:11:57 -0800 Subject: [PATCH 28/40] Refactor: libcrmcommon: Functionize table creation in assert_deref() Signed-off-by: Reid Wahl --- .../pcmk__xe_dereference_children_test.c | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 103b0121f4b..87681e8a9aa 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -13,6 +13,23 @@ #include +static GHashTable * +create_id_table(va_list args) +{ + GHashTable *table = NULL; + + for (const char *value = va_arg(args, const char *); value != NULL; + value = va_arg(args, const char *)) { + + if (table == NULL) { + table = pcmk__strkey_table(NULL, NULL); + } + g_hash_table_add(table, (gpointer) value); + } + + return table; +} + /*! * \internal * \brief Test an invocation of pcmk__xe_dereference_children() @@ -27,8 +44,8 @@ static void assert_deref(const char *xml_string, const char *element_name, ...) { xmlNode *xml = NULL; - GList *list = NULL; GHashTable *table = NULL; + GList *list = NULL; va_list ap; // Parse given XML @@ -39,13 +56,7 @@ assert_deref(const char *xml_string, const char *element_name, ...) // Create a hash table with all expected child IDs va_start(ap, element_name); - for (const char *value = va_arg(ap, const char *); - value != NULL; value = va_arg(ap, const char *)) { - if (table == NULL) { - table = pcmk__strkey_table(NULL, NULL); - } - g_hash_table_add(table, (gpointer) value); - } + table = create_id_table(ap); va_end(ap); // Call tested function on "test" child @@ -65,12 +76,10 @@ assert_deref(const char *xml_string, const char *element_name, ...) list = list->next; } assert_int_equal(g_hash_table_size(table), 0); + g_hash_table_destroy(table); } g_list_free(list); - if (table != NULL) { - g_hash_table_destroy(table); - } pcmk__xml_free(xml); } From 0467827a187983a34474d0a7dd0acab92bc54f61 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 18:18:28 -0800 Subject: [PATCH 29/40] Refactor: libcrmcommon: Use TEST_ATTR constant in deref test Signed-off-by: Reid Wahl --- .../pcmk__xe_dereference_children_test.c | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 87681e8a9aa..07a2bc5ccaf 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -13,6 +13,8 @@ #include +#define TEST_ATTR "test_attr" + static GHashTable * create_id_table(va_list args) { @@ -37,7 +39,7 @@ create_id_table(va_list args) * \param[in] xml_string XML to parse, with "test" child to pass to tested * function * \param[in] element_name Element name to pass to tested function - * \param[in] ... NULL-terminated list of child "testattr" values to + * \param[in] ... NULL-terminated list of child \c TEST_ATTR values to * expect in tested function's returned list */ static void @@ -69,8 +71,7 @@ assert_deref(const char *xml_string, const char *element_name, ...) assert_null(list); } else { while (list != NULL) { - const char *value = pcmk__xe_get((xmlNode *) list->data, - "testattr"); + const char *value = pcmk__xe_get((xmlNode *) list->data, TEST_ATTR); assert_true(g_hash_table_remove(table, value)); list = list->next; @@ -102,17 +103,17 @@ null_for_no_children(void **state) assert_deref(XML_NO_ELEMENT_CHILDREN, "test", NULL); } -#define XML_NO_IDREF \ - "\n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ +#define XML_NO_IDREF \ + "\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ "\n" static void @@ -131,19 +132,19 @@ without_idref(void **state) assert_deref(XML_NO_IDREF, "nonexistent", NULL); } -#define XML_WITH_IDREF \ - "\n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ +#define XML_WITH_IDREF \ + "\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ "\n" static void @@ -162,17 +163,17 @@ with_idref(void **state) assert_deref(XML_WITH_IDREF, "nonexistent", NULL); } -#define XML_WITH_BROKEN_IDREF \ - "\n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ +#define XML_WITH_BROKEN_IDREF \ + "\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ "\n" static void From 43a120abdc20cb975ba7bf4c79426d346af70a75 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 20:50:23 -0800 Subject: [PATCH 30/40] Refactor: libcrmcommon: Use TEST_ELEMENT constant in deref test Signed-off-by: Reid Wahl --- .../pcmk__xe_dereference_children_test.c | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 07a2bc5ccaf..82877746c02 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -13,6 +13,7 @@ #include +#define TEST_ELEMENT "test" #define TEST_ATTR "test_attr" static GHashTable * @@ -36,8 +37,8 @@ create_id_table(va_list args) * \internal * \brief Test an invocation of pcmk__xe_dereference_children() * - * \param[in] xml_string XML to parse, with "test" child to pass to tested - * function + * \param[in] xml_string XML to parse, with \c TEST_ELEMENT child to pass to + * tested function * \param[in] element_name Element name to pass to tested function * \param[in] ... NULL-terminated list of child \c TEST_ATTR values to * expect in tested function's returned list @@ -46,6 +47,7 @@ static void assert_deref(const char *xml_string, const char *element_name, ...) { xmlNode *xml = NULL; + const xmlNode *test_element = NULL; GHashTable *table = NULL; GList *list = NULL; va_list ap; @@ -61,10 +63,9 @@ assert_deref(const char *xml_string, const char *element_name, ...) table = create_id_table(ap); va_end(ap); - // Call tested function on "test" child - list = pcmk__xe_dereference_children(pcmk__xe_first_child(xml, "test", - NULL, NULL), - element_name); + // Call tested function on TEST_ELEMENT child + test_element = pcmk__xe_first_child(xml, TEST_ELEMENT, NULL, NULL); + list = pcmk__xe_dereference_children(test_element, element_name); // Ensure returned list has exactly the expected child IDs if (table == NULL) { @@ -88,24 +89,25 @@ static void null_for_null(void **state) { assert_deref(NULL, NULL, NULL); - assert_deref(NULL, "test", NULL); + assert_deref(NULL, TEST_ELEMENT, NULL); } -#define XML_NO_CHILDREN "" -#define XML_NO_ELEMENT_CHILDREN "text" +#define XML_NO_CHILDREN "<" TEST_ELEMENT "/>" +#define XML_NO_ELEMENT_CHILDREN \ + "<" TEST_ELEMENT ">text" static void null_for_no_children(void **state) { assert_deref(XML_NO_CHILDREN, NULL, NULL); - assert_deref(XML_NO_CHILDREN, "test", NULL); + assert_deref(XML_NO_CHILDREN, TEST_ELEMENT, NULL); assert_deref(XML_NO_ELEMENT_CHILDREN, NULL, NULL); - assert_deref(XML_NO_ELEMENT_CHILDREN, "test", NULL); + assert_deref(XML_NO_ELEMENT_CHILDREN, TEST_ELEMENT, NULL); } #define XML_NO_IDREF \ "\n" \ - " \n" \ + " <" TEST_ELEMENT ">\n" \ " \n" \ " \n" \ " \n" \ @@ -113,7 +115,7 @@ null_for_no_children(void **state) " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ "\n" static void @@ -136,7 +138,7 @@ without_idref(void **state) "\n" \ " \n" \ " \n" \ - " \n" \ + " <" TEST_ELEMENT ">\n" \ " \n" \ " \n" \ " \n" \ @@ -144,7 +146,7 @@ without_idref(void **state) " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ "\n" static void @@ -165,7 +167,7 @@ with_idref(void **state) #define XML_WITH_BROKEN_IDREF \ "\n" \ - " \n" \ + " <" TEST_ELEMENT ">\n" \ " \n" \ " \n" \ " \n" \ @@ -173,7 +175,7 @@ with_idref(void **state) " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ "\n" static void From 4b92b61469a4f79e40a5f0420166db0210032368 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 20:57:01 -0800 Subject: [PATCH 31/40] Low: libcrmcommon: Avoid memory leak in deref test By the time we were freeing list, it was already NULL. Signed-off-by: Reid Wahl --- .../tests/xml_idref/pcmk__xe_dereference_children_test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 82877746c02..acc0fcd5ff9 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -70,13 +70,15 @@ assert_deref(const char *xml_string, const char *element_name, ...) // Ensure returned list has exactly the expected child IDs if (table == NULL) { assert_null(list); + } else { - while (list != NULL) { - const char *value = pcmk__xe_get((xmlNode *) list->data, TEST_ATTR); + for (GList *iter = list; iter != NULL; iter = iter->next) { + const xmlNode *node = iter->data; + const char *value = pcmk__xe_get(node, TEST_ATTR); assert_true(g_hash_table_remove(table, value)); - list = list->next; } + assert_int_equal(g_hash_table_size(table), 0); g_hash_table_destroy(table); } From 1999fae8ea21ac3d707f114c6bf857ac4551c570 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 21:07:12 -0800 Subject: [PATCH 32/40] Refactor: libcrmcommon: Ensure xml_string is non-NULL in deref test This will make some planned changes easier. Signed-off-by: Reid Wahl --- .../xml_idref/pcmk__xe_dereference_children_test.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index acc0fcd5ff9..7c159c74f65 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -53,10 +53,8 @@ assert_deref(const char *xml_string, const char *element_name, ...) va_list ap; // Parse given XML - if (xml_string != NULL) { - xml = pcmk__xml_parse(xml_string); - assert_non_null(xml); - } + xml = pcmk__xml_parse(xml_string); + assert_non_null(xml); // Create a hash table with all expected child IDs va_start(ap, element_name); @@ -90,8 +88,8 @@ assert_deref(const char *xml_string, const char *element_name, ...) static void null_for_null(void **state) { - assert_deref(NULL, NULL, NULL); - assert_deref(NULL, TEST_ELEMENT, NULL); + assert_null(pcmk__xe_dereference_children(NULL, NULL)); + assert_null(pcmk__xe_dereference_children(NULL, TEST_ELEMENT)); } #define XML_NO_CHILDREN "<" TEST_ELEMENT "/>" From 1865031840aa191dea7dd776528cff895ac58896 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 21:10:42 -0800 Subject: [PATCH 33/40] Refactor: libcrmcommon: Unindent block in deref test Signed-off-by: Reid Wahl --- .../pcmk__xe_dereference_children_test.c | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 7c159c74f65..1b10a319fb8 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -66,21 +66,23 @@ assert_deref(const char *xml_string, const char *element_name, ...) list = pcmk__xe_dereference_children(test_element, element_name); // Ensure returned list has exactly the expected child IDs + if (table == NULL) { assert_null(list); + pcmk__xml_free(xml); + return; + } - } else { - for (GList *iter = list; iter != NULL; iter = iter->next) { - const xmlNode *node = iter->data; - const char *value = pcmk__xe_get(node, TEST_ATTR); + for (GList *iter = list; iter != NULL; iter = iter->next) { + const xmlNode *node = iter->data; + const char *value = pcmk__xe_get(node, TEST_ATTR); - assert_true(g_hash_table_remove(table, value)); - } - - assert_int_equal(g_hash_table_size(table), 0); - g_hash_table_destroy(table); + assert_true(g_hash_table_remove(table, value)); } + assert_int_equal(g_hash_table_size(table), 0); + + g_hash_table_destroy(table); g_list_free(list); pcmk__xml_free(xml); } From 1a5f55d2a2a2814faaca0749d0646274ae67a524 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 22:45:37 -0800 Subject: [PATCH 34/40] Refactor: libcrmcommon: Simplify assert_submatch() ...by ensuring that reference is non-NULL in all callers. Signed-off-by: Reid Wahl --- .../tests/rules/pcmk__replace_submatches_test.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/common/tests/rules/pcmk__replace_submatches_test.c b/lib/common/tests/rules/pcmk__replace_submatches_test.c index 5f3b2fd837f..0f4e20ed900 100644 --- a/lib/common/tests/rules/pcmk__replace_submatches_test.c +++ b/lib/common/tests/rules/pcmk__replace_submatches_test.c @@ -25,15 +25,10 @@ static const int nmatches = 3; static void assert_submatch(const char *string, const char *reference) { - char *expanded = NULL; + char *expanded = pcmk__replace_submatches(string, match, submatches, + nmatches); - expanded = pcmk__replace_submatches(string, match, submatches, nmatches); - if ((expanded == NULL) || (reference == NULL)) { - assert_null(expanded); - assert_null(reference); - } else { - assert_string_equal(expanded, reference); - } + assert_string_equal(expanded, reference); free(expanded); } @@ -41,8 +36,8 @@ static void no_source(void **state) { assert_null(pcmk__replace_submatches(NULL, NULL, NULL, 0)); - assert_submatch(NULL, NULL); - assert_submatch("", NULL); + assert_null(pcmk__replace_submatches(NULL, match, submatches, nmatches)); + assert_null(pcmk__replace_submatches("", match, submatches, nmatches)); } static void From 8f423c363010ca08166e14d5d7d306b4b83ca0f6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 14:39:38 -0800 Subject: [PATCH 35/40] Low: libcrmcommon: Convert unit test assertion helpers to macros With a function, the CMocka assert macros showed unhelpful line numbers on error. Ref T222 Signed-off-by: Reid Wahl --- .../tests/cmdline/pcmk__quote_cmdline_test.c | 18 ++- .../tests/iso8601/crm_time_add_days_test.c | 30 +++-- .../tests/iso8601/crm_time_add_seconds_test.c | 32 +++-- .../tests/iso8601/crm_time_add_years_test.c | 30 +++-- .../tests/iso8601/pcmk__time_format_hr_test.c | 117 +++++++++--------- .../tests/nvpair/pcmk__scan_nvpair_test.c | 51 ++++---- .../pcmk__cib_element_in_patchset_test.c | 36 +++--- .../tests/procfs/pcmk__procfs_pid2path_test.c | 76 ++++++------ .../pcmk__evaluate_attr_expression_test.c | 24 ++-- .../pcmk__evaluate_date_expression_test.c | 63 +++++----- .../rules/pcmk__evaluate_op_expression_test.c | 25 ++-- .../pcmk__evaluate_rsc_expression_test.c | 25 ++-- .../rules/pcmk__replace_submatches_test.c | 17 ++- .../pcmk__update_recheck_time_test.c | 25 ++-- .../schemas/pcmk__find_x_0_schema_test.c | 31 +++-- .../tests/schemas/pcmk__get_schema_test.c | 27 ++-- .../tests/schemas/pcmk__schema_init_test.c | 27 ++-- .../tests/scores/pcmk_parse_score_test.c | 17 ++- .../tests/strings/pcmk__parse_bool_test.c | 109 ++++++++-------- .../tests/strings/pcmk__parse_ms_test.c | 15 ++- .../tests/utils/pcmk__compare_versions_test.c | 15 +-- .../tests/utils/pcmk__lookup_user_test.c | 78 ++++++------ lib/common/tests/xml/pcmk__xml_escape_test.c | 18 ++- .../tests/xml/pcmk__xml_is_name_char_test.c | 42 +++---- .../xml/pcmk__xml_is_name_start_char_test.c | 42 +++---- .../tests/xml/pcmk__xml_sanitize_id_test.c | 19 ++- .../xml_element/pcmk__xe_get_flags_test.c | 45 ++++--- .../xml_element/pcmk__xe_get_score_test.c | 26 ++-- .../xml_element/pcmk__xe_set_score_test.c | 37 +++--- .../xml_element/pcmk__xe_sort_attrs_test.c | 116 +++++++++-------- .../pcmk__xe_dereference_children_test.c | 104 ++++++++-------- 31 files changed, 657 insertions(+), 680 deletions(-) diff --git a/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c index 3392ed490a1..1f40fd7474e 100644 --- a/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c +++ b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c @@ -17,16 +17,14 @@ * says "The quoting style used is undefined (single or double quotes may be * used)." */ -static void -assert_quote_cmdline(const char **argv, const gchar *expected_single, - const gchar *expected_double) -{ - gchar *processed = pcmk__quote_cmdline((const char *const *) argv); - - assert_true(pcmk__str_any_of(processed, expected_single, expected_double, - NULL)); - g_free(processed); -} +#define assert_quote_cmdline(argv, expected_single, expected_double) \ + do { \ + gchar *processed = pcmk__quote_cmdline(argv); \ + \ + assert_true(pcmk__str_any_of(processed, expected_single, \ + expected_double, NULL)); \ + g_free(processed); \ + } while (0) static void empty_input(void **state) diff --git a/lib/common/tests/iso8601/crm_time_add_days_test.c b/lib/common/tests/iso8601/crm_time_add_days_test.c index c9ad3616d78..74b3d3cfc0b 100644 --- a/lib/common/tests/iso8601/crm_time_add_days_test.c +++ b/lib/common/tests/iso8601/crm_time_add_days_test.c @@ -16,22 +16,20 @@ #include -static void -assert_add_days(const char *orig_date_time, int days, - const char *expected_date_time) -{ - crm_time_t *orig = crm_time_new(orig_date_time); - crm_time_t *expected = crm_time_new(expected_date_time); - - assert_non_null(orig); - assert_non_null(expected); - - crm_time_add_days(orig, days); - assert_int_equal(crm_time_compare(orig, expected), 0); - - crm_time_free(orig); - crm_time_free(expected); -} +#define assert_add_days(orig_date_time, days, expected_date_time) \ + do { \ + crm_time_t *orig = crm_time_new(orig_date_time); \ + crm_time_t *expected = crm_time_new(expected_date_time); \ + \ + assert_non_null(orig); \ + assert_non_null(expected); \ + \ + crm_time_add_days(orig, days); \ + assert_int_equal(crm_time_compare(orig, expected), 0); \ + \ + crm_time_free(orig); \ + crm_time_free(expected); \ + } while (0) static void invalid_argument(void **state) diff --git a/lib/common/tests/iso8601/crm_time_add_seconds_test.c b/lib/common/tests/iso8601/crm_time_add_seconds_test.c index 4315d7dcb5d..b8990cb5286 100644 --- a/lib/common/tests/iso8601/crm_time_add_seconds_test.c +++ b/lib/common/tests/iso8601/crm_time_add_seconds_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -16,22 +16,20 @@ #include -static void -assert_add_seconds(const char *orig_date_time, int seconds, - const char *expected_date_time) -{ - crm_time_t *orig = crm_time_new(orig_date_time); - crm_time_t *expected = crm_time_new(expected_date_time); - - assert_non_null(orig); - assert_non_null(expected); - - crm_time_add_seconds(orig, seconds); - assert_int_equal(crm_time_compare(orig, expected), 0); - - crm_time_free(orig); - crm_time_free(expected); -} +#define assert_add_seconds(orig_date_time, seconds, expected_date_time) \ + do { \ + crm_time_t *orig = crm_time_new(orig_date_time); \ + crm_time_t *expected = crm_time_new(expected_date_time); \ + \ + assert_non_null(orig); \ + assert_non_null(expected); \ + \ + crm_time_add_seconds(orig, seconds); \ + assert_int_equal(crm_time_compare(orig, expected), 0); \ + \ + crm_time_free(orig); \ + crm_time_free(expected); \ + } while (0) static void invalid_argument(void **state) diff --git a/lib/common/tests/iso8601/crm_time_add_years_test.c b/lib/common/tests/iso8601/crm_time_add_years_test.c index 8ea6b4d1c46..828150411cc 100644 --- a/lib/common/tests/iso8601/crm_time_add_years_test.c +++ b/lib/common/tests/iso8601/crm_time_add_years_test.c @@ -16,22 +16,20 @@ #include -static void -assert_add_years(const char *orig_date_time, int years, - const char *expected_date_time) -{ - crm_time_t *orig = crm_time_new(orig_date_time); - crm_time_t *expected = crm_time_new(expected_date_time); - - assert_non_null(orig); - assert_non_null(expected); - - crm_time_add_years(orig, years); - assert_int_equal(crm_time_compare(orig, expected), 0); - - crm_time_free(orig); - crm_time_free(expected); -} +#define assert_add_years(orig_date_time, years, expected_date_time) \ + do { \ + crm_time_t *orig = crm_time_new(orig_date_time); \ + crm_time_t *expected = crm_time_new(expected_date_time); \ + \ + assert_non_null(orig); \ + assert_non_null(expected); \ + \ + crm_time_add_years(orig, years); \ + assert_int_equal(crm_time_compare(orig, expected), 0); \ + \ + crm_time_free(orig); \ + crm_time_free(expected); \ + } while (0) static void invalid_argument(void **state) diff --git a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c index c26325a5301..889dd74f88b 100644 --- a/lib/common/tests/iso8601/pcmk__time_format_hr_test.c +++ b/lib/common/tests/iso8601/pcmk__time_format_hr_test.c @@ -29,83 +29,78 @@ * \internal * \brief Check that \c pcmk__time_format_hr() produced expected result * - * \param[in] format Time format string - * \param[in] expected Check succeeds if result matches this + * \param[in] format Time format string (const char *) + * \param[in] expected Succeed if result matches this (const char *) */ -static void -assert_hr_format(const char *format, const char *expected) -{ - crm_time_t *dt = NULL; - char *result = NULL; - - dt = crm_time_new(DATE_TIME_S); - assert_non_null(dt); - - result = pcmk__time_format_hr(format, dt, 0); - assert_non_null(result); - - assert_string_equal(result, expected); - - crm_time_free(dt); - free(result); -} +#define assert_hr_format(format, expected) \ + do { \ + crm_time_t *dt = NULL; \ + char *result = NULL; \ + \ + dt = crm_time_new(DATE_TIME_S); \ + assert_non_null(dt); \ + \ + result = pcmk__time_format_hr(format, dt, 0); \ + assert_non_null(result); \ + assert_string_equal(result, expected); \ + \ + crm_time_free(dt); \ + free(result); \ + } while (0) /*! * \internal * \brief Check that \c pcmk__time_format_hr() produced expected result (or alt) * - * \param[in] format Time format string - * \param[in] expected Check succeeds if result matches this - * \param[in] alternate Check also succeeds if result matches this + * \param[in] format Time format string (const char *) + * \param[in] expected Succeed if result matches this (const char *) + * \param[in] alternate Succeed if result matches this (const char *) * * \note This allows two possible results because different \c strftime() * implementations handle certain format syntax differently. */ -static void -assert_hr_format_alt(const char *format, const char *expected, - const char *alternate) -{ - crm_time_t *dt = NULL; - char *result = NULL; - - dt = crm_time_new(DATE_TIME_S); - assert_non_null(dt); - - result = pcmk__time_format_hr(format, dt, 0); - assert_non_null(result); - - // CMocka has no abstraction for comparing to multiple strings - assert_true((strcmp(result, expected) == 0) - || (strcmp(result, alternate) == 0)); - - crm_time_free(dt); - free(result); -} +#define assert_hr_format_alt(format, expected, alternate) \ + do { \ + crm_time_t *dt = NULL; \ + char *result = NULL; \ + \ + dt = crm_time_new(DATE_TIME_S); \ + assert_non_null(dt); \ + \ + result = pcmk__time_format_hr(format, dt, 0); \ + assert_non_null(result); \ + \ + /* CMocka has no abstraction for comparing to multiple strings */ \ + assert_true((strcmp(result, expected) == 0) \ + || (strcmp(result, alternate) == 0)); \ + \ + crm_time_free(dt); \ + free(result); \ + } while (0) /*! * \internal * \brief Check that \c pcmk__time_format_hr() produced expected high-res result * - * \param[in] format Time format string - * \param[in] expected Check succeeds if result matches this - * \param[in] usec Microseconds component of the reference time + * \param[in] format Time format string (const char *) + * \param[in] expected Succeed if result matches this (const char *) + * \param[in] usec Microseconds component of the reference time (\c int) */ -static void -assert_hr_format_usec(const char *format, const char *expected, int usec) -{ - crm_time_t *dt = NULL; - char *result = NULL; - - dt = crm_time_new(DATE_TIME_S); - assert_non_null(dt); - - result = pcmk__time_format_hr(format, dt, usec); - assert_non_null(result); - assert_string_equal(result, expected); - - crm_time_free(dt); - free(result); -} +#define assert_hr_format_usec(format, expected, usec) \ + do { \ + crm_time_t *dt = NULL; \ + char *result = NULL; \ + \ + dt = crm_time_new(DATE_TIME_S); \ + assert_non_null(dt); \ + \ + result = pcmk__time_format_hr(format, dt, usec); \ + assert_non_null(result); \ + assert_string_equal(result, expected); \ + \ + crm_time_free(dt); \ + free(result); \ + } while (0) static void null_format(void **state) diff --git a/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c b/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c index ecae94564c2..506383c2b03 100644 --- a/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c +++ b/lib/common/tests/nvpair/pcmk__scan_nvpair_test.c @@ -13,33 +13,30 @@ #include -static void -assert_scan_nvpair_success(const gchar *input, const gchar *expected_name, - const gchar *expected_value) -{ - gchar *name = NULL; - gchar *value = NULL; - int rc = pcmk__scan_nvpair(input, &name, &value); - - assert_int_equal(rc, pcmk_rc_ok); - assert_string_equal(name, expected_name); - assert_string_equal(value, expected_value); - - g_free(name); - g_free(value); -} - -static void -assert_scan_nvpair_failure(const gchar *input) -{ - gchar *name = NULL; - gchar *value = NULL; - int rc = pcmk__scan_nvpair(input, &name, &value); - - assert_int_equal(rc, pcmk_rc_bad_nvpair); - assert_null(name); - assert_null(value); -} +#define assert_scan_nvpair_success(input, expected_name, expected_value) \ + do { \ + gchar *name = NULL; \ + gchar *value = NULL; \ + int rc = pcmk__scan_nvpair(input, &name, &value); \ + \ + assert_int_equal(rc, pcmk_rc_ok); \ + assert_string_equal(name, expected_name); \ + assert_string_equal(value, expected_value); \ + \ + g_free(name); \ + g_free(value); \ + } while (0) + +#define assert_scan_nvpair_failure(input) \ + do { \ + gchar *name = NULL; \ + gchar *value = NULL; \ + int rc = pcmk__scan_nvpair(input, &name, &value); \ + \ + assert_int_equal(rc, pcmk_rc_bad_nvpair); \ + assert_null(name); \ + assert_null(value); \ + } while (0) static void null_asserts(void **state) diff --git a/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c b/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c index cf8bfa48bd4..930611c6311 100644 --- a/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c +++ b/lib/common/tests/patchset/pcmk__cib_element_in_patchset_test.c @@ -46,27 +46,21 @@ create_patchset(const char *source_s, const char *target_s) return patchset; } -static void -assert_in_patchset(const char *source_s, const char *target_s, - const char *element) -{ - xmlNode *patchset = create_patchset(source_s, target_s); - - assert_true(pcmk__cib_element_in_patchset(patchset, element)); - - pcmk__xml_free(patchset); -} - -static void -assert_not_in_patchset(const char *source_s, const char *target_s, - const char *element) -{ - xmlNode *patchset = create_patchset(source_s, target_s); - - assert_false(pcmk__cib_element_in_patchset(patchset, element)); - - pcmk__xml_free(patchset); -} +#define assert_in_patchset(source_s, target_s, element) \ + do { \ + xmlNode *patchset = create_patchset(source_s, target_s); \ + \ + assert_true(pcmk__cib_element_in_patchset(patchset, element)); \ + pcmk__xml_free(patchset); \ + } while (0) + +#define assert_not_in_patchset(source_s, target_s, element) \ + do { \ + xmlNode *patchset = create_patchset(source_s, target_s); \ + \ + assert_false(pcmk__cib_element_in_patchset(patchset, element)); \ + pcmk__xml_free(patchset); \ + } while (0) static void null_patchset_asserts(void **state) diff --git a/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c index a32a51c1b36..1dbfe102811 100644 --- a/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c +++ b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c @@ -19,45 +19,43 @@ #include #include -static void -assert_pid2path_one(int errno_to_set, const char *link_contents, char **dest, - int reference_rc) -{ - pcmk__mock_readlink = true; - - expect_string(__wrap_readlink, path, "/proc/1000/exe"); - expect_uint_value(__wrap_readlink, bufsize, PATH_MAX); - will_return(__wrap_readlink, errno_to_set); - will_return(__wrap_readlink, link_contents); - - assert_int_equal(pcmk__procfs_pid2path(1000, dest), reference_rc); - - pcmk__mock_readlink = false; -} - -static void -assert_pid2path_null(int errno_to_set, const char *link_contents, - int expected_rc) -{ - char *dest = NULL; - - assert_pid2path_one(errno_to_set, link_contents, NULL, expected_rc); - assert_pid2path_one(errno_to_set, link_contents, &dest, expected_rc); - assert_null(dest); -} - -static void -assert_pid2path_equals(int errno_to_set, const char *link_contents, - int expected_rc, const char *expected_result) -{ - char *dest = NULL; - - assert_pid2path_one(errno_to_set, link_contents, NULL, expected_rc); - assert_pid2path_one(errno_to_set, link_contents, &dest, expected_rc); - - assert_string_equal(dest, expected_result); - free(dest); -} +#define assert_pid2path_one(errno_to_set, link_contents, dest, expected_rc) \ + do { \ + pcmk__mock_readlink = true; \ + \ + expect_string(__wrap_readlink, path, "/proc/1000/exe"); \ + expect_uint_value(__wrap_readlink, bufsize, PATH_MAX); \ + will_return(__wrap_readlink, errno_to_set); \ + will_return(__wrap_readlink, link_contents); \ + \ + assert_int_equal(pcmk__procfs_pid2path(1000, dest), expected_rc); \ + \ + pcmk__mock_readlink = false; \ + } while (0) + +#define assert_pid2path_null(errno_to_set, link_contents, expected_rc) \ + do { \ + char *dest = NULL; \ + \ + assert_pid2path_one(errno_to_set, link_contents, NULL, \ + expected_rc); \ + assert_pid2path_one(errno_to_set, link_contents, &dest, \ + expected_rc); \ + assert_null(dest); \ + } while (0) + +#define assert_pid2path_equals(errno_to_set, link_contents, expected_rc, \ + expected_result) \ + do { \ + char *dest = NULL; \ + \ + assert_pid2path_one(errno_to_set, link_contents, NULL, \ + expected_rc); \ + assert_pid2path_one(errno_to_set, link_contents, &dest, \ + expected_rc); \ + assert_string_equal(dest, expected_result); \ + free(dest); \ + } while (0) static void no_exe_file(void **state) diff --git a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c index b229893aa59..747ef9995dd 100644 --- a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -79,18 +79,18 @@ teardown(void **state) * \internal * \brief Run one test, comparing return value * - * \param[in] xml_string Node attribute expression XML as string - * \param[in] reference_rc Assert that evaluation result equals this + * \param[in] xml_string Node attribute expression XML as string + * (const char *) + * \param[in] expected_rc Assert that evaluation result equals this (\c int) */ -static void -assert_attr_expression(const char *xml_string, int reference_rc) -{ - xmlNode *xml = pcmk__xml_parse(xml_string); - - assert_int_equal(pcmk__evaluate_attr_expression(xml, &rule_input), - reference_rc); - pcmk__xml_free(xml); -} +#define assert_attr_expression(xml_string, expected_rc) \ + do { \ + xmlNode *xml = pcmk__xml_parse(xml_string); \ + \ + assert_int_equal(pcmk__evaluate_attr_expression(xml, &rule_input), \ + expected_rc); \ + pcmk__xml_free(xml); \ + } while (0) /* diff --git a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c index de7247c76a1..39b0cdaebd0 100644 --- a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c @@ -21,49 +21,48 @@ * \internal * \brief Run one test, checking return value * - * \param[in] xml Date expression XML + * \param[in] xml Date expression XML (const xmlNode *) * \param[in] now_s Time to evaluate expression with - * \param[in] expected_rc Assert that evaluation result equals this + * (const char *) + * \param[in] expected_rc Assert that evaluation result equals this (\c int) */ -static void -assert_date_expr(const xmlNode *xml, const char *now_s, int expected_rc) -{ - crm_time_t *now = crm_time_new(now_s); - - assert_int_equal(pcmk__evaluate_date_expression(xml, now, NULL), - expected_rc); - crm_time_free(now); -} +#define assert_date_expr(xml, now_s, expected_rc) \ + do { \ + crm_time_t *now = crm_time_new(now_s); \ + int rc = pcmk__evaluate_date_expression(xml, now, NULL); \ + \ + assert_int_equal(rc, expected_rc); \ + crm_time_free(now); \ + } while (0) /*! * \internal * \brief Run one test, checking return value and output argument * - * \param[in] xml Date expression XML + * \param[in] xml Date expression XML (const xmlNode *) * \param[in] now_s Time to evaluate expression with + * (const char *) * \param[in] next_change_s Initialize next change time with this time + * (const char *) * \param[in] expected_s Time that next change should be after expression - * evaluation - * \param[in] expected_rc Assert that evaluation result equals this + * evaluation (const char *) + * \param[in] expected_rc Assert that evaluation result equals this (\c int) */ -static void -assert_date_expr_change(const xmlNode *xml, const char *now_s, - const char *next_change_s, const char *expected_s, - int expected_rc) -{ - crm_time_t *now = crm_time_new(now_s); - crm_time_t *next_change = crm_time_new(next_change_s); - crm_time_t *expected = crm_time_new(expected_s); - - assert_int_equal(pcmk__evaluate_date_expression(xml, now, next_change), - expected_rc); - - assert_int_equal(crm_time_compare(next_change, expected), 0); - - crm_time_free(now); - crm_time_free(next_change); - crm_time_free(expected); -} +#define assert_date_expr_change(xml, now_s, next_change_s, expected_s, \ + expected_rc) \ + do { \ + crm_time_t *now = crm_time_new(now_s); \ + crm_time_t *next_change = crm_time_new(next_change_s); \ + crm_time_t *expected = crm_time_new(expected_s); \ + int rc = pcmk__evaluate_date_expression(xml, now, next_change); \ + \ + assert_int_equal(rc, expected_rc); \ + assert_int_equal(crm_time_compare(next_change, expected), 0); \ + \ + crm_time_free(now); \ + crm_time_free(next_change); \ + crm_time_free(expected); \ + } while (0) #define EXPR_LT_VALID \ "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \ diff --git a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c index e04497f22f2..2a2047a7ac0 100644 --- a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -28,20 +28,19 @@ static pcmk_rule_input_t rule_input = { /*! * \internal - * \brief Run one test, comparing return value + * \brief Run one test, checking return value * - * \param[in] xml_string Operation expression XML as string - * \param[in] reference_rc Assert that evaluation result equals this + * \param[in] xml_string Operation expression XML (const char *) + * \param[in] expected_rc Assert that evaluation result equals this (\c int) */ -static void -assert_op_expression(const char *xml_string, int reference_rc) -{ - xmlNode *xml = pcmk__xml_parse(xml_string); - - assert_int_equal(pcmk__evaluate_op_expression(xml, &rule_input), - reference_rc); - pcmk__xml_free(xml); -} +#define assert_op_expression(xml_string, expected_rc) \ + do { \ + xmlNode *xml = pcmk__xml_parse(xml_string); \ + \ + assert_int_equal(pcmk__evaluate_op_expression(xml, &rule_input), \ + expected_rc); \ + pcmk__xml_free(xml); \ + } while (0) /* diff --git a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c index e1d24853e5c..fb953ca6cc5 100644 --- a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -29,20 +29,19 @@ static pcmk_rule_input_t rule_input = { /*! * \internal - * \brief Run one test, comparing return value + * \brief Run one test, checking return value * - * \param[in] xml_string Resource expression XML as string - * \param[in] reference_rc Assert that evaluation result equals this + * \param[in] xml_string Resource expression XML (const char *) + * \param[in] expected_rc Assert that evaluation result equals this (\c int) */ -static void -assert_rsc_expression(const char *xml_string, int reference_rc) -{ - xmlNode *xml = pcmk__xml_parse(xml_string); - - assert_int_equal(pcmk__evaluate_rsc_expression(xml, &rule_input), - reference_rc); - pcmk__xml_free(xml); -} +#define assert_rsc_expression(xml_string, expected_rc) \ + do { \ + xmlNode *xml = pcmk__xml_parse(xml_string); \ + \ + assert_int_equal(pcmk__evaluate_rsc_expression(xml, &rule_input), \ + expected_rc); \ + pcmk__xml_free(xml); \ + } while (0) /* diff --git a/lib/common/tests/rules/pcmk__replace_submatches_test.c b/lib/common/tests/rules/pcmk__replace_submatches_test.c index 0f4e20ed900..ee34815397c 100644 --- a/lib/common/tests/rules/pcmk__replace_submatches_test.c +++ b/lib/common/tests/rules/pcmk__replace_submatches_test.c @@ -22,15 +22,14 @@ static const regmatch_t submatches[] = { }; static const int nmatches = 3; -static void -assert_submatch(const char *string, const char *reference) -{ - char *expanded = pcmk__replace_submatches(string, match, submatches, - nmatches); - - assert_string_equal(expanded, reference); - free(expanded); -} +#define assert_submatch(string, expected) \ + do { \ + char *expanded = pcmk__replace_submatches(string, match, \ + submatches, nmatches); \ + \ + assert_string_equal(expanded, expected); \ + free(expanded); \ + } while (0) static void no_source(void **state) diff --git a/lib/common/tests/scheduler/pcmk__update_recheck_time_test.c b/lib/common/tests/scheduler/pcmk__update_recheck_time_test.c index 9da185802f9..38ddacafe55 100644 --- a/lib/common/tests/scheduler/pcmk__update_recheck_time_test.c +++ b/lib/common/tests/scheduler/pcmk__update_recheck_time_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -15,18 +15,17 @@ #include #include -static void -assert_recheck(time_t now_time, time_t orig_time, time_t update_time, - time_t expected_time, const char *reason) -{ - pcmk_scheduler_t *scheduler = pcmk_new_scheduler(); - - scheduler->priv->now = pcmk__copy_timet(now_time); - scheduler->priv->recheck_by = orig_time; - pcmk__update_recheck_time(update_time, scheduler, reason); - assert_int_equal(scheduler->priv->recheck_by, expected_time); - pcmk_free_scheduler(scheduler); -} +#define assert_recheck(now_time, orig_time, update_time, expected_time, \ + reason) \ + do { \ + pcmk_scheduler_t *scheduler = pcmk_new_scheduler(); \ + \ + scheduler->priv->now = pcmk__copy_timet(now_time); \ + scheduler->priv->recheck_by = orig_time; \ + pcmk__update_recheck_time(update_time, scheduler, reason); \ + assert_int_equal(scheduler->priv->recheck_by, expected_time); \ + pcmk_free_scheduler(scheduler); \ + } while (0) // A NULL scheduler argument is invalid and should assert static void diff --git a/lib/common/tests/schemas/pcmk__find_x_0_schema_test.c b/lib/common/tests/schemas/pcmk__find_x_0_schema_test.c index 0dda558071d..3fa5b5ea73c 100644 --- a/lib/common/tests/schemas/pcmk__find_x_0_schema_test.c +++ b/lib/common/tests/schemas/pcmk__find_x_0_schema_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the Pacemaker project contributors + * Copyright 2023-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -33,21 +33,20 @@ teardown(void **state) return 0; } -static void -assert_schema_0(int schema_index, const char *schema_name) -{ - GList *entry = NULL; - pcmk__schema_t *schema = NULL; - - entry = pcmk__find_x_0_schema(); - assert_non_null(entry); - - schema = entry->data; - assert_non_null(schema); - - assert_int_equal(schema->schema_index, schema_index); - assert_string_equal(schema->name, schema_name); -} +#define assert_schema_0(schema_idx, schema_name) \ + do { \ + GList *entry = NULL; \ + pcmk__schema_t *schema = NULL; \ + \ + entry = pcmk__find_x_0_schema(); \ + assert_non_null(entry); \ + \ + schema = entry->data; \ + assert_non_null(schema); \ + \ + assert_int_equal(schema->schema_index, schema_idx); \ + assert_string_equal(schema->name, schema_name); \ + } while (0) static void last_is_0(void **state) diff --git a/lib/common/tests/schemas/pcmk__get_schema_test.c b/lib/common/tests/schemas/pcmk__get_schema_test.c index d9c999fca1e..a5fd836f09f 100644 --- a/lib/common/tests/schemas/pcmk__get_schema_test.c +++ b/lib/common/tests/schemas/pcmk__get_schema_test.c @@ -29,20 +29,19 @@ teardown(void **state) return 0; } -static void -assert_schema(const char *name, int expected_index) -{ - GList *schema_entry = NULL; - pcmk__schema_t *schema = NULL; - - schema_entry = pcmk__get_schema(name); - assert_non_null(schema_entry); - - schema = schema_entry->data; - assert_non_null(schema); - - assert_int_equal(schema->schema_index, expected_index); -} +#define assert_schema(name, expected_index) \ + do { \ + GList *schema_entry = NULL; \ + pcmk__schema_t *schema = NULL; \ + \ + schema_entry = pcmk__get_schema(name); \ + assert_non_null(schema_entry); \ + \ + schema = schema_entry->data; \ + assert_non_null(schema); \ + \ + assert_int_equal(schema->schema_index, expected_index); \ + } while (0) static void unknown_schema(void **state) diff --git a/lib/common/tests/schemas/pcmk__schema_init_test.c b/lib/common/tests/schemas/pcmk__schema_init_test.c index 2b2196a69cf..0afbbc02d11 100644 --- a/lib/common/tests/schemas/pcmk__schema_init_test.c +++ b/lib/common/tests/schemas/pcmk__schema_init_test.c @@ -109,20 +109,19 @@ teardown(void **state) return rc; } -static void -assert_schema(const char *schema_name, int schema_index) -{ - GList *entry = NULL; - pcmk__schema_t *schema = NULL; - - entry = pcmk__get_schema(schema_name); - assert_non_null(entry); - - schema = entry->data; - assert_non_null(schema); - - assert_int_equal(schema_index, schema->schema_index); -} +#define assert_schema(schema_name, schema_idx) \ + do { \ + GList *entry = NULL; \ + pcmk__schema_t *schema = NULL; \ + \ + entry = pcmk__get_schema(schema_name); \ + assert_non_null(entry); \ + \ + schema = entry->data; \ + assert_non_null(schema); \ + \ + assert_int_equal(schema_idx, schema->schema_index); \ + } while (0) static void extra_schema_files(void **state) diff --git a/lib/common/tests/scores/pcmk_parse_score_test.c b/lib/common/tests/scores/pcmk_parse_score_test.c index a79a1f74450..16989420dec 100644 --- a/lib/common/tests/scores/pcmk_parse_score_test.c +++ b/lib/common/tests/scores/pcmk_parse_score_test.c @@ -20,15 +20,14 @@ extern int pcmk__score_yellow; static int default_score = 99; -static void -assert_score(const char *score_s, int expected_rc, int expected_score) -{ - int score = 0; - int rc = pcmk_parse_score(score_s, &score, default_score); - - assert_int_equal(rc, expected_rc); - assert_int_equal(score, expected_score); -} +#define assert_score(score_s, expected_rc, expected_score) \ + do { \ + int score = 0; \ + int rc = pcmk_parse_score(score_s, &score, default_score); \ + \ + assert_int_equal(rc, expected_rc); \ + assert_int_equal(score, expected_score); \ + } while (0) static void null_score_string(void **state) diff --git a/lib/common/tests/strings/pcmk__parse_bool_test.c b/lib/common/tests/strings/pcmk__parse_bool_test.c index f0d15556585..0c5b7799367 100644 --- a/lib/common/tests/strings/pcmk__parse_bool_test.c +++ b/lib/common/tests/strings/pcmk__parse_bool_test.c @@ -17,75 +17,72 @@ * \internal * \brief Check \c pcmk__parse_bool() succeeds and parses the input to true * - * \param[in] input Input string + * \param[in] input Input string (const char *) */ -static void -assert_parse_bool_true(const char *input) -{ - bool result = false; - - // Ensure we still validate the string with a NULL result argument - assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); - - assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - assert_true(result); - - // Repeat with result initially set to true - result = true; - - assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - assert_true(result); -} +#define assert_parse_bool_true(input) \ + do { \ + bool result = false; \ + \ + /* Test with NULL result argument (for validation only) */ \ + assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); \ + \ + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); \ + assert_true(result); \ + \ + /* Repeat with result initially set to true */ \ + result = true; \ + \ + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); \ + assert_true(result); \ + } while (0) /*! * \internal * \brief Check \c pcmk__parse_bool() succeeds and parses the input to false * - * \param[in] input Input string + * \param[in] input Input string (const char *) */ -static void -assert_parse_bool_false(const char *input) -{ - bool result = false; - - // Ensure we still validate the string with a NULL result argument - assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); - - assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - assert_false(result); - - // Repeat with result initially set to true - result = true; - - assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); - assert_false(result); -} +#define assert_parse_bool_false(input) \ + do { \ + bool result = false; \ + \ + /* Test with NULL result argument (for validation only) */ \ + assert_int_equal(pcmk__parse_bool(input, NULL), pcmk_rc_ok); \ + \ + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); \ + assert_false(result); \ + \ + /* Repeat with result initially set to true */ \ + result = true; \ + \ + assert_int_equal(pcmk__parse_bool(input, &result), pcmk_rc_ok); \ + assert_false(result); \ + } while (0) /*! * \internal * \brief Check that \c pcmk__parse_bool() fails and returns the expected value * - * \param[in] input Input string - * \param[in] expected_rc Expected return code + * \param[in] input Input string (const char *) + * \param[in] expected_rc Expected return code (\c int) */ -static void -assert_parse_bool_failure(const char *input, int expected_rc) -{ - bool result = false; - - // Ensure we still validate the string with a NULL result argument - assert_int_equal(pcmk__parse_bool(input, NULL), expected_rc); - - // Make sure the value of result does not change on failure - assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); - assert_false(result); - - // Repeat with result initially set to true - result = true; - - assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); - assert_true(result); -} +#define assert_parse_bool_failure(input, expected_rc) \ + do { \ + bool result = false; \ + \ + /* Test with NULL result argument (for validation only) */ \ + assert_int_equal(pcmk__parse_bool(input, NULL), expected_rc); \ + \ + /* Make sure the value of result does not change on failure */ \ + assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); \ + assert_false(result); \ + \ + /* Repeat with result initially set to true */ \ + result = true; \ + \ + assert_int_equal(pcmk__parse_bool(input, &result), expected_rc); \ + assert_true(result); \ + } while (0) static void bad_input(void **state) diff --git a/lib/common/tests/strings/pcmk__parse_ms_test.c b/lib/common/tests/strings/pcmk__parse_ms_test.c index 2a2c29fa88c..d3f0a565d04 100644 --- a/lib/common/tests/strings/pcmk__parse_ms_test.c +++ b/lib/common/tests/strings/pcmk__parse_ms_test.c @@ -14,14 +14,13 @@ //! Magic initial value to test whether a "result" output variable has changed static const long long magic = -12345678; -static void -assert_parse_ms(const char *input, int expected_rc, long long expected_result) -{ - long long result = magic; - - assert_int_equal(pcmk__parse_ms(input, &result), expected_rc); - assert_int_equal(result, expected_result); -} +#define assert_parse_ms(input, expected_rc, expected_result) \ + do { \ + long long result = magic; \ + \ + assert_int_equal(pcmk__parse_ms(input, &result), expected_rc); \ + assert_int_equal(result, expected_result); \ + } while (0) static void bad_input(void **state) diff --git a/lib/common/tests/utils/pcmk__compare_versions_test.c b/lib/common/tests/utils/pcmk__compare_versions_test.c index a6d99a8ac95..9ddeb6afd3f 100644 --- a/lib/common/tests/utils/pcmk__compare_versions_test.c +++ b/lib/common/tests/utils/pcmk__compare_versions_test.c @@ -16,16 +16,17 @@ * \brief Compare two version strings in both directions * * \param[in] v1 First argument for \c pcmk__compare_versions() + * (const char *) * \param[in] v2 Second argument for \c pcmk__compare_versions() + * (const char *) * \param[in] expected_rc Expected return code from - * pcmk__compare_versions(v1, v2) + * pcmk__compare_versions(v1, v2) (\c int) */ -static void -assert_compare_versions(const char *v1, const char *v2, int expected_rc) -{ - assert_int_equal(pcmk__compare_versions(v1, v2), expected_rc); - assert_int_equal(pcmk__compare_versions(v2, v1), -expected_rc); -} +#define assert_compare_versions(v1, v2, expected_rc) \ + do { \ + assert_int_equal(pcmk__compare_versions(v1, v2), expected_rc); \ + assert_int_equal(pcmk__compare_versions(v2, v1), -expected_rc); \ + } while (0) static void empty_params(void **state) diff --git a/lib/common/tests/utils/pcmk__lookup_user_test.c b/lib/common/tests/utils/pcmk__lookup_user_test.c index a74c37c5aef..9ed65ac23ee 100644 --- a/lib/common/tests/utils/pcmk__lookup_user_test.c +++ b/lib/common/tests/utils/pcmk__lookup_user_test.c @@ -21,53 +21,59 @@ #define USER_NAME "ha_user" -static void -assert_lookup_user_one(int errno_to_set, struct passwd *returned_ent, - uid_t *uid, gid_t *gid, int expected_rc) -{ - expect_string(__wrap_getpwnam, name, USER_NAME); - will_return(__wrap_getpwnam, errno_to_set); - will_return(__wrap_getpwnam, returned_ent); - assert_int_equal(pcmk__lookup_user(USER_NAME, uid, gid), expected_rc); -} +#define assert_lookup_user_one(errno_to_set, returned_ent, uid, gid, \ + expected_rc) \ + do { \ + expect_string(__wrap_getpwnam, name, USER_NAME); \ + will_return(__wrap_getpwnam, errno_to_set); \ + will_return(__wrap_getpwnam, returned_ent); \ + assert_int_equal(pcmk__lookup_user(USER_NAME, uid, gid), \ + expected_rc); \ + } while (0) /*! * \internal * \brief Perform one test of \c pcmk__lookup_user() with non-NULL name * * \param[in] errno_to_set Value that \c getpwnam() should set \c errno to + * (\c int) * \param[in] returned_ent Passwd entry that \c getpwnam() should return + * (struct passwd *) * \param[in] expected_rc Expected return code of \c pcmk__lookup_user() + * (\c int) * \param[in] expected_uid Expected value at \p *uid after - * \c pcmk__lookup_user() call + * \c pcmk__lookup_user() call (\c uid_t) * \param[in] expected_gid Expected value at \p *gid after - * \c pcmk__lookup_user() call + * \c pcmk__lookup_user() call (\c gid_t) */ -static void -assert_lookup_user(int errno_to_set, struct passwd *returned_ent, - int expected_rc, uid_t expected_uid, gid_t expected_gid) -{ - uid_t uid = 0; - gid_t gid = 0; - - pcmk__mock_getpwnam = true; - - assert_lookup_user_one(errno_to_set, returned_ent, NULL, NULL, expected_rc); - - assert_lookup_user_one(errno_to_set, returned_ent, &uid, NULL, expected_rc); - assert_int_equal(uid, expected_uid); - uid = 0; - - assert_lookup_user_one(errno_to_set, returned_ent, NULL, &gid, expected_rc); - assert_int_equal(gid, expected_gid); - gid = 0; - - assert_lookup_user_one(errno_to_set, returned_ent, &uid, &gid, expected_rc); - assert_int_equal(uid, expected_uid); - assert_int_equal(gid, expected_gid); - - pcmk__mock_getpwnam = false; -} +#define assert_lookup_user(errno_to_set, returned_ent, expected_rc, \ + expected_uid, expected_gid) \ + do { \ + uid_t uid = 0; \ + gid_t gid = 0; \ + \ + pcmk__mock_getpwnam = true; \ + \ + assert_lookup_user_one(errno_to_set, returned_ent, NULL, NULL, \ + expected_rc); \ + \ + assert_lookup_user_one(errno_to_set, returned_ent, &uid, NULL, \ + expected_rc); \ + assert_int_equal(uid, expected_uid); \ + uid = 0; \ + \ + assert_lookup_user_one(errno_to_set, returned_ent, NULL, &gid, \ + expected_rc); \ + assert_int_equal(gid, expected_gid); \ + gid = 0; \ + \ + assert_lookup_user_one(errno_to_set, returned_ent, &uid, &gid, \ + expected_rc); \ + assert_int_equal(uid, expected_uid); \ + assert_int_equal(gid, expected_gid); \ + \ + pcmk__mock_getpwnam = false; \ + } while (0) static void null_name(void **state) diff --git a/lib/common/tests/xml/pcmk__xml_escape_test.c b/lib/common/tests/xml/pcmk__xml_escape_test.c index 39972cdfa1d..cbdad568beb 100644 --- a/lib/common/tests/xml/pcmk__xml_escape_test.c +++ b/lib/common/tests/xml/pcmk__xml_escape_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -13,15 +13,13 @@ #include "crmcommon_private.h" -static void -assert_escape(const char *str, const char *reference, - enum pcmk__xml_escape_type type) -{ - gchar *buf = pcmk__xml_escape(str, type); - - assert_string_equal(buf, reference); - g_free(buf); -} +#define assert_escape(str, reference, type) \ + do { \ + gchar *buf = pcmk__xml_escape(str, type); \ + \ + assert_string_equal(buf, reference); \ + g_free(buf); \ + } while (0) static void null_empty(void **state) diff --git a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c index 0e4c45859ad..f4bb9ff1480 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_char_test.c @@ -21,35 +21,33 @@ * \internal * \brief Assert that a Unicode character is a valid XML \c NameChar * - * \param[in] code_pt Unicode code point of character to check + * \param[in] code_pt Unicode code point of character to check (\c int) */ -static void -assert_name_char(int code_pt) -{ - gchar utf8_buf[6] = { 0, }; - int len = 4; - int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - - assert_true(pcmk__xml_is_name_char(utf8_buf, &len)); - assert_int_equal(len, ref_len); -} +#define assert_name_char(code_pt) \ + do { \ + gchar utf8_buf[6] = { 0, }; \ + int len = 4; \ + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); \ + \ + assert_true(pcmk__xml_is_name_char(utf8_buf, &len)); \ + assert_int_equal(len, ref_len); \ + } while (0) /*! * \internal * \brief Assert that a Unicode character is not a valid XML \c NameChar * - * \param[in] code_pt Unicode code point of character to check + * \param[in] code_pt Unicode code point of character to check (\c int) */ -static void -assert_not_name_char(int code_pt) -{ - gchar utf8_buf[6] = { 0, }; - int len = 4; - int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - - assert_false(pcmk__xml_is_name_char(utf8_buf, &len)); - assert_int_equal(len, ref_len); -} +#define assert_not_name_char(code_pt) \ + do { \ + gchar utf8_buf[6] = { 0, }; \ + int len = 4; \ + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); \ + \ + assert_false(pcmk__xml_is_name_char(utf8_buf, &len)); \ + assert_int_equal(len, ref_len); \ + } while (0) static void null_len(void **state) diff --git a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c index dfc2d785abe..6abfd0f9f4d 100644 --- a/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c +++ b/lib/common/tests/xml/pcmk__xml_is_name_start_char_test.c @@ -21,35 +21,33 @@ * \internal * \brief Assert that a Unicode character is a valid XML \c NameStartChar * - * \param[in] code_pt Unicode code point of character to check + * \param[in] code_pt Unicode code point of character to check (\c int) */ -static void -assert_name_start_char(int code_pt) -{ - gchar utf8_buf[6] = { 0, }; - int len = 4; - int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - - assert_true(pcmk__xml_is_name_start_char(utf8_buf, &len)); - assert_int_equal(len, ref_len); -} +#define assert_name_start_char(code_pt) \ + do { \ + gchar utf8_buf[6] = { 0, }; \ + int len = 4; \ + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); \ + \ + assert_true(pcmk__xml_is_name_start_char(utf8_buf, &len)); \ + assert_int_equal(len, ref_len); \ + } while (0) /*! * \internal * \brief Assert that a Unicode character is not a valid XML \c NameStartChar * - * \param[in] code_pt Unicode code point of character to check + * \param[in] code_pt Unicode code point of character to check (\c int) */ -static void -assert_not_name_start_char(int code_pt) -{ - gchar utf8_buf[6] = { 0, }; - int len = 4; - int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); - - assert_false(pcmk__xml_is_name_start_char(utf8_buf, &len)); - assert_int_equal(len, ref_len); -} +#define assert_not_name_start_char(code_pt) \ + do { \ + gchar utf8_buf[6] = { 0, }; \ + int len = 4; \ + int ref_len = g_unichar_to_utf8(code_pt, utf8_buf); \ + \ + assert_false(pcmk__xml_is_name_start_char(utf8_buf, &len)); \ + assert_int_equal(len, ref_len); \ + } while (0) static void null_len(void **state) diff --git a/lib/common/tests/xml/pcmk__xml_sanitize_id_test.c b/lib/common/tests/xml/pcmk__xml_sanitize_id_test.c index cdf2ed9ed87..95976122ed3 100644 --- a/lib/common/tests/xml/pcmk__xml_sanitize_id_test.c +++ b/lib/common/tests/xml/pcmk__xml_sanitize_id_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -11,15 +11,14 @@ #include -static void -assert_sanitized(const char *str, const char *reference) -{ - char *buf = pcmk__str_copy(str); - - pcmk__xml_sanitize_id(buf); - assert_string_equal(buf, reference); - free(buf); -} +#define assert_sanitized(str, expected) \ + do { \ + char *buf = pcmk__str_copy(str); \ + \ + pcmk__xml_sanitize_id(buf); \ + assert_string_equal(buf, expected); \ + free(buf); \ + } while (0) static void null_empty(void **state) diff --git a/lib/common/tests/xml_element/pcmk__xe_get_flags_test.c b/lib/common/tests/xml_element/pcmk__xe_get_flags_test.c index 7f26333496b..4fe1533330e 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_flags_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_flags_test.c @@ -17,29 +17,28 @@ #include #include +#define ATTR_NAME "attribute" #define DEFAULT_VALUE 0xfff -static void -assert_flags(const char *value, int expected_rc, unsigned int expected_flags) -{ - int rc = pcmk_rc_ok; - uint32_t flags = 0U; - xmlNode *xml = pcmk__xe_create(NULL, "element"); - - assert_non_null(xml); - pcmk__xe_set(xml, "attribute", value); - - // Without output argument - assert_int_equal(pcmk__xe_get_flags(xml, "attribute", NULL, DEFAULT_VALUE), - expected_rc); - - // With output argument - rc = pcmk__xe_get_flags(xml, "attribute", &flags, DEFAULT_VALUE); - assert_int_equal(rc, expected_rc); - assert_true(flags == expected_flags); - - pcmk__xml_free(xml); -} +#define assert_flags(value, expected_rc, expected_flags) \ + do { \ + int rc = pcmk_rc_ok; \ + uint32_t flags = 0; \ + xmlNode *xml = pcmk__xe_create(NULL, "element"); \ + \ + pcmk__xe_set(xml, ATTR_NAME, value); \ + \ + /* Without output argument */ \ + rc = pcmk__xe_get_flags(xml, ATTR_NAME, NULL, DEFAULT_VALUE); \ + assert_int_equal(rc, expected_rc); \ + \ + /* With output argument */ \ + rc = pcmk__xe_get_flags(xml, ATTR_NAME, &flags, DEFAULT_VALUE); \ + assert_int_equal(rc, expected_rc); \ + assert_true(flags == expected_flags); \ + \ + pcmk__xml_free(xml); \ + } while (0) static void null_name_invalid(void **state) @@ -74,10 +73,10 @@ null_xml_default(void **state) int rc = pcmk_rc_ok; uint32_t flags = 0U; - assert_int_equal(pcmk__xe_get_flags(NULL, "attribute", NULL, DEFAULT_VALUE), + assert_int_equal(pcmk__xe_get_flags(NULL, ATTR_NAME, NULL, DEFAULT_VALUE), pcmk_rc_ok); - rc = pcmk__xe_get_flags(NULL, "attribute", &flags, DEFAULT_VALUE); + rc = pcmk__xe_get_flags(NULL, ATTR_NAME, &flags, DEFAULT_VALUE); assert_int_equal(rc, pcmk_rc_ok); assert_true(flags == DEFAULT_VALUE); } diff --git a/lib/common/tests/xml_element/pcmk__xe_get_score_test.c b/lib/common/tests/xml_element/pcmk__xe_get_score_test.c index 66a7743a700..776b7fa011f 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_score_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_score_test.c @@ -18,19 +18,19 @@ static int default_score = 99; -static void -assert_score(const char *score_s, int expected_rc, int expected_score) -{ - int score = 0; - int rc = pcmk_rc_ok; - xmlNode *xml = pcmk__xe_create(NULL, __func__); - - pcmk__xe_set(xml, ATTR_NAME, score_s); - rc = pcmk__xe_get_score(xml, ATTR_NAME, &score, default_score); - assert_int_equal(rc, expected_rc); - assert_int_equal(score, expected_score); - pcmk__xml_free(xml); -} +#define assert_score(score_s, expected_rc, expected_score) \ + do { \ + int rc = pcmk_rc_ok; \ + int score = 0; \ + xmlNode *xml = pcmk__xe_create(NULL, __func__); \ + \ + pcmk__xe_set(xml, ATTR_NAME, score_s); \ + \ + rc = pcmk__xe_get_score(xml, ATTR_NAME, &score, default_score); \ + assert_int_equal(rc, expected_rc); \ + assert_int_equal(score, expected_score); \ + pcmk__xml_free(xml); \ + } while (0) static void invalid_args(void **state) diff --git a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c index 440737ce52d..356368a958a 100644 --- a/lib/common/tests/xml_element/pcmk__xe_set_score_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_set_score_test.c @@ -19,27 +19,30 @@ /*! * \internal - * \brief Update an XML attribute value and check it against a reference value + * \brief Update an XML attribute value and check it against the expected value * * The attribute name is hard-coded as \c ATTR_NAME. * - * \param[in] initial Initial value - * \param[in] new Value to set - * \param[in] reference_val Expected attribute value after update - * \param[in] reference_rc Expected return code from \c pcmk__xe_set_score() + * \param[in] initial Initial value (const char *) + * \param[in] new Value to set (const char *) + * \param[in] expected_value Expected attribute value after update + * (const char *) + * \param[in] expected_rc Expected return code from \c pcmk__xe_set_score() + * (\c int) */ -static void -assert_set_score(const char *initial, const char *new, - const char *reference_val, int reference_rc) -{ - xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); - - pcmk__xe_set(test_xml, ATTR_NAME, initial); - assert_int_equal(pcmk__xe_set_score(test_xml, ATTR_NAME, new), reference_rc); - assert_string_equal(pcmk__xe_get(test_xml, ATTR_NAME), reference_val); - - pcmk__xml_free(test_xml); -} +#define assert_set_score(initial, new, expected_value, expected_rc) \ + do { \ + xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); \ + \ + pcmk__xe_set(test_xml, ATTR_NAME, initial); \ + \ + assert_int_equal(pcmk__xe_set_score(test_xml, ATTR_NAME, new), \ + expected_rc); \ + assert_string_equal(pcmk__xe_get(test_xml, ATTR_NAME), \ + expected_value); \ + \ + pcmk__xml_free(test_xml); \ + } while (0) static void new_value_name_plus_plus(void **state) diff --git a/lib/common/tests/xml_element/pcmk__xe_sort_attrs_test.c b/lib/common/tests/xml_element/pcmk__xe_sort_attrs_test.c index e7aad245639..31d4267c0c3 100644 --- a/lib/common/tests/xml_element/pcmk__xe_sort_attrs_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_sort_attrs_test.c @@ -25,63 +25,71 @@ * preserved. * * \param[in,out] test_xml XML whose attributes to sort + * (xmlNode *) * \param[in] reference_xml XML whose attribute order to compare against * (attributes must have the same values as in - * \p test_xml) + * \p test_xml) (const xmlNode *) */ -static void -assert_order(xmlNode *test_xml, const xmlNode *reference_xml) -{ - GHashTable *attr_flags = pcmk__strkey_table(free, NULL); - xmlAttr *test_attr = NULL; - xmlAttr *ref_attr = NULL; - - // Save original flags - for (xmlAttr *attr = pcmk__xe_first_attr(test_xml); attr != NULL; - attr = attr->next) { - - xml_node_private_t *nodepriv = attr->_private; - uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none; - - g_hash_table_insert(attr_flags, - pcmk__str_copy((const char *) attr->name), - GUINT_TO_POINTER((guint) flags)); - } - - pcmk__xe_sort_attrs(test_xml); - - test_attr = pcmk__xe_first_attr(test_xml); - ref_attr = pcmk__xe_first_attr(reference_xml); - - for (; (test_attr != NULL) && (ref_attr != NULL); - test_attr = test_attr->next, ref_attr = ref_attr->next) { - - const char *test_name = (const char *) test_attr->name; - xml_node_private_t *nodepriv = test_attr->_private; - uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none; - - gpointer old_flags_ptr = g_hash_table_lookup(attr_flags, test_name); - uint32_t old_flags = pcmk__xf_none; - - if (old_flags_ptr != NULL) { - old_flags = GPOINTER_TO_UINT(old_flags_ptr); - } - - // Flags must not change - assert_true(flags == old_flags); - - // Attributes must be in expected order with expected values - assert_string_equal(test_name, (const char *) ref_attr->name); - assert_string_equal(pcmk__xml_attr_value(test_attr), - pcmk__xml_attr_value(ref_attr)); - } - - // Attribute lists must be the same length - assert_null(test_attr); - assert_null(ref_attr); - - g_hash_table_destroy(attr_flags); -} +#define assert_order(test_xml, reference_xml) \ + do { \ + GHashTable *attr_flags = pcmk__strkey_table(free, NULL); \ + xmlAttr *test_attr = NULL; \ + xmlAttr *ref_attr = NULL; \ + \ + /* Save original flags */ \ + for (xmlAttr *attr = pcmk__xe_first_attr(test_xml); attr != NULL; \ + attr = attr->next) { \ + \ + xml_node_private_t *nodepriv = attr->_private; \ + uint32_t flags = pcmk__xf_none; \ + \ + if (nodepriv != NULL) { \ + flags = nodepriv->flags; \ + } \ + \ + g_hash_table_insert(attr_flags, \ + pcmk__str_copy((const char *) attr->name), \ + GUINT_TO_POINTER((guint) flags)); \ + } \ + \ + pcmk__xe_sort_attrs(test_xml); \ + \ + test_attr = pcmk__xe_first_attr(test_xml); \ + ref_attr = pcmk__xe_first_attr(reference_xml); \ + \ + for (; (test_attr != NULL) && (ref_attr != NULL); \ + test_attr = test_attr->next, ref_attr = ref_attr->next) { \ + \ + const char *test_name = (const char *) test_attr->name; \ + xml_node_private_t *nodepriv = test_attr->_private; \ + gpointer old_flags_ptr = NULL; \ + uint32_t flags = pcmk__xf_none; \ + uint32_t old_flags = pcmk__xf_none; \ + \ + if (nodepriv != NULL) { \ + flags = nodepriv->flags; \ + } \ + \ + old_flags_ptr = g_hash_table_lookup(attr_flags, test_name); \ + if (old_flags_ptr != NULL) { \ + old_flags = GPOINTER_TO_UINT(old_flags_ptr); \ + } \ + \ + /* Flags must not change */ \ + assert_true(flags == old_flags); \ + \ + /* Attributes must be in expected order with expected values */ \ + assert_string_equal(test_name, (const char *) ref_attr->name); \ + assert_string_equal(pcmk__xml_attr_value(test_attr), \ + pcmk__xml_attr_value(ref_attr)); \ + } \ + \ + /* Attribute lists must be the same length */ \ + assert_null(test_attr); \ + assert_null(ref_attr); \ + \ + g_hash_table_destroy(attr_flags); \ + } while (0) static void null_arg(void **state) diff --git a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c index 1b10a319fb8..5f4a8bec0a9 100644 --- a/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c +++ b/lib/common/tests/xml_idref/pcmk__xe_dereference_children_test.c @@ -16,11 +16,15 @@ #define TEST_ELEMENT "test" #define TEST_ATTR "test_attr" +// C requires at least one named argument before a variadic argument list static GHashTable * -create_id_table(va_list args) +create_id_table(const void *dummy, ...) { + va_list args; GHashTable *table = NULL; + va_start(args, dummy); + for (const char *value = va_arg(args, const char *); value != NULL; value = va_arg(args, const char *)) { @@ -30,62 +34,62 @@ create_id_table(va_list args) g_hash_table_add(table, (gpointer) value); } + va_end(args); + return table; } /*! * \internal - * \brief Test an invocation of pcmk__xe_dereference_children() + * \brief Test an invocation of \c pcmk__xe_dereference_children() * - * \param[in] xml_string XML to parse, with \c TEST_ELEMENT child to pass to - * tested function - * \param[in] element_name Element name to pass to tested function - * \param[in] ... NULL-terminated list of child \c TEST_ATTR values to - * expect in tested function's returned list + * \param[in] xml_string XML to parse, with \c TEST_ELEMENT child to pass + * to tested function (const char *) + * \param[in] element_name Element name to pass to tested function + * (const char *) + * \param[in] expected_values NULL-terminated list of child + * \c TEST_ATTR values to expect in tested + * function's returned list (list of + * const char *) */ -static void -assert_deref(const char *xml_string, const char *element_name, ...) -{ - xmlNode *xml = NULL; - const xmlNode *test_element = NULL; - GHashTable *table = NULL; - GList *list = NULL; - va_list ap; - - // Parse given XML - xml = pcmk__xml_parse(xml_string); - assert_non_null(xml); - - // Create a hash table with all expected child IDs - va_start(ap, element_name); - table = create_id_table(ap); - va_end(ap); - - // Call tested function on TEST_ELEMENT child - test_element = pcmk__xe_first_child(xml, TEST_ELEMENT, NULL, NULL); - list = pcmk__xe_dereference_children(test_element, element_name); - - // Ensure returned list has exactly the expected child IDs - - if (table == NULL) { - assert_null(list); - pcmk__xml_free(xml); - return; - } - - for (GList *iter = list; iter != NULL; iter = iter->next) { - const xmlNode *node = iter->data; - const char *value = pcmk__xe_get(node, TEST_ATTR); - - assert_true(g_hash_table_remove(table, value)); - } - - assert_int_equal(g_hash_table_size(table), 0); - - g_hash_table_destroy(table); - g_list_free(list); - pcmk__xml_free(xml); -} +#define assert_deref(xml_string, element_name, expected_values...) \ + do { \ + xmlNode *xml = NULL; \ + const xmlNode *test_element = NULL; \ + GHashTable *table = NULL; \ + GList *list = NULL; \ + \ + xml = pcmk__xml_parse(xml_string); \ + assert_non_null(xml); \ + \ + /* Create a hash table with all expected child IDs */ \ + table = create_id_table(NULL, expected_values); \ + \ + /* Call tested function on TEST_ELEMENT child */ \ + test_element = pcmk__xe_first_child(xml, TEST_ELEMENT, NULL, NULL); \ + list = pcmk__xe_dereference_children(test_element, element_name); \ + \ + /* Ensure returned list has exactly the expected child IDs */ \ + \ + if (table == NULL) { \ + assert_null(list); \ + pcmk__xml_free(xml); \ + break; \ + } \ + \ + for (GList *iter = list; iter != NULL; iter = iter->next) { \ + const xmlNode *node = iter->data; \ + const char *value = pcmk__xe_get(node, TEST_ATTR); \ + \ + assert_true(g_hash_table_remove(table, value)); \ + } \ + \ + assert_int_equal(g_hash_table_size(table), 0); \ + \ + g_hash_table_destroy(table); \ + g_list_free(list); \ + pcmk__xml_free(xml); \ + } while (0) static void null_for_null(void **state) From 39c2e6af5e28956af63973f8bbd01cb93765c549 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:39:44 -0800 Subject: [PATCH 36/40] Refactor: fencer: NULL-check device at start of localhost_is_eligible() All current callers pass non-NULL device. Signed-off-by: Reid Wahl --- daemons/fenced/fenced_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index f0d4d4dbad1..475d10733bf 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -2144,9 +2144,9 @@ localhost_is_eligible(const fenced_device_t *device, const char *action, bool localhost_is_target = pcmk__str_eq(target, fenced_get_local_node(), pcmk__str_casei); - CRM_CHECK(action != NULL, return true); + CRM_CHECK((device != NULL) && (action != NULL), return true); - if ((device != NULL) && (device->on_target_actions != NULL) + if ((device->on_target_actions != NULL) && pcmk__g_strv_contains(device->on_target_actions, action)) { if (!localhost_is_target) { From a881c36175a66182bd21b28cb8fee5c0d1fe07ab Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:41:58 -0800 Subject: [PATCH 37/40] Refactor: libcrmcommon: pcmk__g_strv_contains() takes double-const arg This is to match the signature of g_strv_contains(). Unfortunately, it requires casts at each caller. However, since the plan is to replace this function with g_strv_contains(), we might as well do this now. Signed-off-by: Reid Wahl --- daemons/fenced/fenced_commands.c | 7 +++++-- include/crm/common/strings_internal.h | 2 +- lib/common/logging.c | 12 ++++++++---- lib/common/options.c | 2 +- lib/common/strings.c | 2 +- lib/common/xml_display.c | 3 ++- lib/lrmd/lrmd_alerts.c | 8 +++++--- lib/pacemaker/pcmk_cluster_queries.c | 12 ++++++++---- lib/pengine/pe_digest.c | 2 +- tools/cibsecret.c | 3 ++- 10 files changed, 34 insertions(+), 19 deletions(-) diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 475d10733bf..9ddf07ed055 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -2143,11 +2143,14 @@ localhost_is_eligible(const fenced_device_t *device, const char *action, { bool localhost_is_target = pcmk__str_eq(target, fenced_get_local_node(), pcmk__str_casei); + const gchar *const *on_target_actions = NULL; CRM_CHECK((device != NULL) && (action != NULL), return true); - if ((device->on_target_actions != NULL) - && pcmk__g_strv_contains(device->on_target_actions, action)) { + on_target_actions = (const gchar *const *) device->on_target_actions; + + if ((on_target_actions != NULL) + && pcmk__g_strv_contains(on_target_actions, action)) { if (!localhost_is_target) { pcmk__trace("Operation '%s' using %s can only be executed for " diff --git a/include/crm/common/strings_internal.h b/include/crm/common/strings_internal.h index 33586adf214..930dbf34718 100644 --- a/include/crm/common/strings_internal.h +++ b/include/crm/common/strings_internal.h @@ -164,7 +164,7 @@ pcmk__intkey_table_remove(GHashTable *hash_table, int key) } bool pcmk__str_in_list(const char *str, const GList *list, uint32_t flags); -bool pcmk__g_strv_contains(gchar **strv, const gchar *str); +bool pcmk__g_strv_contains(const gchar *const *strv, const gchar *str); bool pcmk__strcase_any_of(const char *s, ...) G_GNUC_NULL_TERMINATED; bool pcmk__str_any_of(const char *s, ...) G_GNUC_NULL_TERMINATED; diff --git a/lib/common/logging.c b/lib/common/logging.c index 09734ad1ee3..bd22e8ca48f 100644 --- a/lib/common/logging.c +++ b/lib/common/logging.c @@ -624,7 +624,8 @@ crm_log_filter_source(int source, struct qb_log_callsite *cs) char *key = pcmk__assert_asprintf("%s:%d", cs->function, cs->lineno); - if (pcmk__g_strv_contains(trace_blackbox, key)) { + if (pcmk__g_strv_contains((const gchar *const *) trace_blackbox, + key)) { qb_bit_set(cs->targets, source); } free(key); @@ -648,21 +649,24 @@ crm_log_filter_source(int source, struct qb_log_callsite *cs) } if ((trace_files != NULL) - && pcmk__g_strv_contains(trace_files, cs->filename)) { + && pcmk__g_strv_contains((const gchar *const *) trace_files, + cs->filename)) { qb_bit_set(cs->targets, source); return; } if ((trace_functions != NULL) - && pcmk__g_strv_contains(trace_functions, cs->function)) { + && pcmk__g_strv_contains((const gchar *const *) trace_functions, + cs->function)) { qb_bit_set(cs->targets, source); return; } if ((trace_formats != NULL) - && pcmk__g_strv_contains(trace_formats, cs->format)) { + && pcmk__g_strv_contains((const gchar *const *) trace_formats, + cs->format)) { qb_bit_set(cs->targets, source); return; diff --git a/lib/common/options.c b/lib/common/options.c index cea73792e83..2f17bd9c9bb 100644 --- a/lib/common/options.c +++ b/lib/common/options.c @@ -1180,7 +1180,7 @@ pcmk__env_option_enabled(const char *daemon, const char *option) subsystems = g_strsplit(value, ",", 0); - enabled = pcmk__g_strv_contains(subsystems, daemon); + enabled = pcmk__g_strv_contains((const gchar *const *) subsystems, daemon); g_strfreev(subsystems); return enabled; diff --git a/lib/common/strings.c b/lib/common/strings.c index a920a899e3c..e73484da8fb 100644 --- a/lib/common/strings.c +++ b/lib/common/strings.c @@ -984,7 +984,7 @@ pcmk__str_in_list(const char *str, const GList *list, uint32_t flags) * \return \c true if \p str is an element of \p strv, or \c false otherwise */ bool -pcmk__g_strv_contains(gchar **strv, const gchar *str) +pcmk__g_strv_contains(const gchar *const *strv, const gchar *str) { // @COMPAT Replace with calls to g_strv_contains() when we require glib 2.44 CRM_CHECK((strv != NULL) && (str != NULL), return false); diff --git a/lib/common/xml_display.c b/lib/common/xml_display.c index 26dfb7f44ca..4623817b719 100644 --- a/lib/common/xml_display.c +++ b/lib/common/xml_display.c @@ -121,7 +121,8 @@ show_xml_element(pcmk__output_t *out, GString *buffer, const char *prefix, if ((hidden != NULL) && !pcmk__str_empty(p_name)) { gchar **hidden_names = g_strsplit(hidden, ",", 0); - if (pcmk__g_strv_contains(hidden_names, p_name)) { + if (pcmk__g_strv_contains((const gchar *const *) hidden_names, + p_name)) { p_value = "*****"; } g_strfreev(hidden_names); diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index 3fba9d47bd1..da3e86a46fe 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -125,14 +125,16 @@ exec_alert_list(lrmd_t *lrmd, const GList *alert_list, } if (kind == pcmk__alert_attribute) { + const gchar *const *select_attr_name = + (const gchar *const *) entry->select_attribute_name; + if (attr_name == NULL) { CRM_LOG_ASSERT(attr_name != NULL); continue; } - if ((entry->select_attribute_name != NULL) - && !pcmk__g_strv_contains(entry->select_attribute_name, - attr_name)) { + if ((select_attr_name != NULL) + && !pcmk__g_strv_contains(select_attr_name, attr_name)) { pcmk__trace("Filtering unwanted attribute '%s' alert to %s via " "%s", attr_name, entry->recipient, entry->id); diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c index 90438ded189..63270fa6d16 100644 --- a/lib/pacemaker/pcmk_cluster_queries.c +++ b/lib/pacemaker/pcmk_cluster_queries.c @@ -865,24 +865,28 @@ pcmk__list_nodes(pcmk__output_t *out, const char *types, bool bash_export) all = pcmk__str_empty(types); if (!all) { node_types = g_strsplit(types, ",", 0); - all = pcmk__g_strv_contains(node_types, "all"); + all = pcmk__g_strv_contains((const gchar *const *) node_types, "all"); } - if (all || pcmk__g_strv_contains(node_types, "cluster")) { + if (all + || pcmk__g_strv_contains((const gchar *const *) node_types, + "cluster")) { data.field = PCMK_XA_ID; data.type = "cluster"; pcmk__xpath_foreach_result(xml_node->doc, PCMK__XP_MEMBER_NODE_CONFIG, remote_node_print_helper, &data); } - if (all || pcmk__g_strv_contains(node_types, "guest")) { + if (all + || pcmk__g_strv_contains((const gchar *const *) node_types, "guest")) { data.field = PCMK_XA_VALUE; data.type = "guest"; pcmk__xpath_foreach_result(xml_node->doc, PCMK__XP_GUEST_NODE_CONFIG, remote_node_print_helper, &data); } - if (all || pcmk__g_strv_contains(node_types, "remote")) { + if (all + || pcmk__g_strv_contains((const gchar *const *) node_types, "remote")) { data.field = PCMK_XA_ID; data.type = "remote"; pcmk__xpath_foreach_result(xml_node->doc, PCMK__XP_REMOTE_NODE_CONFIG, diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c index 2c809da9b40..1a7ba585193 100644 --- a/lib/pengine/pe_digest.c +++ b/lib/pengine/pe_digest.c @@ -51,7 +51,7 @@ attr_in_strv(xmlAttrPtr a, void *user_data) const char *name = (const char *) a->name; gchar **strv = user_data; - return pcmk__g_strv_contains(strv, name); + return pcmk__g_strv_contains((const gchar *const *) strv, name); } // Return true if XML attribute name is not an element of a given gchar ** array diff --git a/tools/cibsecret.c b/tools/cibsecret.c index bb463f0f514..b5bec35912a 100644 --- a/tools/cibsecret.c +++ b/tools/cibsecret.c @@ -395,7 +395,8 @@ get_live_peers(pcmk__output_t *out) for (const GList *iter = nd.all_nodes; iter != NULL; iter = iter->next) { const char *node_name = iter->data; - if (!pcmk__g_strv_contains(reachable, node_name)) { + if (!pcmk__g_strv_contains((const gchar *const *) reachable, + node_name)) { out->info(out, "Node %s is down - you'll need to update it " "with `cibsecret sync` later", node_name); } From a9e8c44793d49fe56202408e06ef950eb0b504f5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 20 Dec 2025 00:33:35 -0800 Subject: [PATCH 38/40] Refactor: libpacemaker: pcmk__check_rules() takes const char *const * Signed-off-by: Reid Wahl --- include/pacemaker.h | 1 + include/pcmki/pcmki_rule.h | 2 +- lib/pacemaker/pcmk_rule.c | 6 +++--- tools/crm_rule.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/pacemaker.h b/include/pacemaker.h index b2bbff4b047..98135a95bca 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -296,6 +296,7 @@ int pcmk_list_nodes(xmlNode **xml, const char *types); */ int pcmk_status(xmlNodePtr *xml); +// @COMPAT Change rule_ids to type const char *const * at a compatibility break /*! * \brief Check whether each rule in a list is in effect * diff --git a/include/pcmki/pcmki_rule.h b/include/pcmki/pcmki_rule.h index 6694c8ab21b..4867319463a 100644 --- a/include/pcmki/pcmki_rule.h +++ b/include/pcmki/pcmki_rule.h @@ -22,7 +22,7 @@ extern "C" { #endif int pcmk__check_rules(pcmk__output_t *out, xmlNodePtr input, - const crm_time_t *date_time, const char **rule_ids); + const crm_time_t *date_time, const char *const *rule_ids); /*! * \internal diff --git a/lib/pacemaker/pcmk_rule.c b/lib/pacemaker/pcmk_rule.c index 39bd2d97063..7ded5d3aa5a 100644 --- a/lib/pacemaker/pcmk_rule.c +++ b/lib/pacemaker/pcmk_rule.c @@ -161,7 +161,7 @@ eval_rule(pcmk_scheduler_t *scheduler, const char *rule_id, const char **error) */ int pcmk__check_rules(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date, - const char **rule_ids) + const char *const *rule_ids) { pcmk_scheduler_t *scheduler = NULL; int rc = pcmk_rc_ok; @@ -178,7 +178,7 @@ pcmk__check_rules(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date, return rc; } - for (const char **rule_id = rule_ids; *rule_id != NULL; rule_id++) { + for (const char *const *rule_id = rule_ids; *rule_id != NULL; rule_id++) { const char *error = NULL; int last_rc = eval_rule(scheduler, *rule_id, &error); @@ -208,7 +208,7 @@ pcmk_check_rules(xmlNodePtr *xml, xmlNodePtr input, const crm_time_t *date, pcmk__register_lib_messages(out); - rc = pcmk__check_rules(out, input, date, rule_ids); + rc = pcmk__check_rules(out, input, date, (const char *const *) rule_ids); pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); return rc; } diff --git a/tools/crm_rule.c b/tools/crm_rule.c index b0150937788..629c260fc1c 100644 --- a/tools/crm_rule.c +++ b/tools/crm_rule.c @@ -201,7 +201,7 @@ main(int argc, char **argv) switch(options.mode) { case crm_rule_mode_check: rc = pcmk__check_rules(out, input, rule_date, - (const char **) options.rules); + (const char *const *) options.rules); exit_code = pcmk_rc2exitc(rc); break; From bbc66e6378ec27af4c1671bbf7a584398430f7d1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 20 Dec 2025 00:53:58 -0800 Subject: [PATCH 39/40] Refactor: tools: Use const char *const * in cibsecret.c or rsh_fn/rcp_fn Signed-off-by: Reid Wahl --- tools/cibsecret.c | 54 +++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/tools/cibsecret.c b/tools/cibsecret.c index b5bec35912a..a07128a7d30 100644 --- a/tools/cibsecret.c +++ b/tools/cibsecret.c @@ -62,7 +62,8 @@ static GOptionEntry entries[] = { * * \note On error, \p out->err() will be called to record stderr of the process */ -typedef int (*rsh_fn_t)(pcmk__output_t *out, gchar **nodes, const char *cmdline); +typedef int (*rsh_fn_t)(pcmk__output_t *out, const char *const *nodes, + const char *cmdline); /*! * \internal @@ -82,8 +83,8 @@ typedef int (*rsh_fn_t)(pcmk__output_t *out, gchar **nodes, const char *cmdline) * * \note On error, \p out->err() will be called to record stderr of the process */ -typedef int (*rcp_fn_t)(pcmk__output_t *out, gchar **nodes, const char *to, - const char *from); +typedef int (*rcp_fn_t)(pcmk__output_t *out, const char *const *nodes, + const char *to, const char *from); struct subcommand_entry { const char *name; @@ -150,11 +151,11 @@ run_cmdline(pcmk__output_t *out, const char *cmdline, char **standard_out) } static int -pssh(pcmk__output_t *out, gchar **nodes, const char *cmdline) +pssh(pcmk__output_t *out, const char *const *nodes, const char *cmdline) { int rc = pcmk_rc_ok; char *s = NULL; - gchar *hosts = g_strjoinv(" ", nodes); + gchar *hosts = g_strjoinv(" ", (gchar **) nodes); s = pcmk__assert_asprintf("pssh -i -H \"%s\" -x \"" SSH_OPTS "\" -- \"%s\"", hosts, cmdline); @@ -166,11 +167,11 @@ pssh(pcmk__output_t *out, gchar **nodes, const char *cmdline) } static int -pdsh(pcmk__output_t *out, gchar **nodes, const char *cmdline) +pdsh(pcmk__output_t *out, const char *const *nodes, const char *cmdline) { int rc = pcmk_rc_ok; char *s = NULL; - gchar *hosts = g_strjoinv(",", nodes); + gchar *hosts = g_strjoinv(",", (gchar **) nodes); s = pcmk__assert_asprintf("pdsh -w \"%s\" -- \"%s\"", hosts, cmdline); setenv("PDSH_SSH_ARGS_APPEND", SSH_OPTS, 1); @@ -183,11 +184,11 @@ pdsh(pcmk__output_t *out, gchar **nodes, const char *cmdline) } static int -ssh(pcmk__output_t *out, gchar **nodes, const char *cmdline) +ssh(pcmk__output_t *out, const char *const *nodes, const char *cmdline) { int rc = pcmk_rc_ok; - for (gchar **node = nodes; *node != NULL; node++) { + for (const char *const *node = nodes; *node != NULL; node++) { char *s = pcmk__assert_asprintf("ssh " SSH_OPTS " \"%s\" -- \"%s\"", *node, cmdline); @@ -204,11 +205,12 @@ ssh(pcmk__output_t *out, gchar **nodes, const char *cmdline) } static int -pscp(pcmk__output_t *out, gchar **nodes, const char *to, const char *from) +pscp(pcmk__output_t *out, const char *const *nodes, const char *to, + const char *from) { int rc = pcmk_rc_ok; char *s = NULL; - gchar *hosts = g_strjoinv(" ", nodes); + gchar *hosts = g_strjoinv(" ", (gchar **) nodes); s = pcmk__assert_asprintf("pscp.pssh -H \"%s\" -x \"-pr\" " "-x \"" SSH_OPTS "\" -- \"%s\" \"%s\"", @@ -221,11 +223,12 @@ pscp(pcmk__output_t *out, gchar **nodes, const char *to, const char *from) } static int -pdcp(pcmk__output_t *out, gchar **nodes, const char *to, const char *from) +pdcp(pcmk__output_t *out, const char *const *nodes, const char *to, + const char *from) { int rc = pcmk_rc_ok; char *s = NULL; - gchar *hosts = g_strjoinv(",", nodes); + gchar *hosts = g_strjoinv(",", (gchar **) nodes); s = pcmk__assert_asprintf("pdcp -pr -w \"%s\" -- \"%s\" \"%s\"", hosts, from, to); @@ -239,11 +242,12 @@ pdcp(pcmk__output_t *out, gchar **nodes, const char *to, const char *from) } static int -scp(pcmk__output_t *out, gchar **nodes, const char *to, const char *from) +scp(pcmk__output_t *out, const char *const *nodes, const char *to, + const char *from) { int rc = pcmk_rc_ok; - for (gchar **node = nodes; *node != NULL; node++) { + for (const char *const *node = nodes; *node != NULL; node++) { char *s = pcmk__assert_asprintf("scp -pqr " SSH_OPTS " \"%s\" " "\"%s:%s\"", from, *node, to); @@ -299,7 +303,9 @@ reachable_hosts(pcmk__output_t *out, GList *all) run_cmdline(out, cmdline, &standard_out); parts = g_strsplit(standard_out, "\n", 0); - for (gchar **p = parts; *p != NULL; p++) { + for (const char *const *p = (const char *const *) parts; *p != NULL; + p++) { + if (pcmk__str_empty(*p)) { continue; } @@ -440,7 +446,7 @@ sync_one_file(pcmk__output_t *out, rsh_fn_t rsh_fn, rcp_fn_t rcp_fn, dirname = g_path_get_dirname(path); cmdline = pcmk__assert_asprintf("mkdir -p %s", dirname); - rc = rsh_fn(out, peers, cmdline); + rc = rsh_fn(out, (const char *const *) peers, cmdline); if (rc != pcmk_rc_ok) { goto done; } @@ -448,19 +454,19 @@ sync_one_file(pcmk__output_t *out, rsh_fn_t rsh_fn, rcp_fn_t rcp_fn, if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { char *sign_path = NULL; - rc = rcp_fn(out, peers, dirname, path); + rc = rcp_fn(out, (const char *const *) peers, dirname, path); if (rc != pcmk_rc_ok) { goto done; } sign_path = pcmk__assert_asprintf("%s.sign", path); - rc = rcp_fn(out, peers, dirname, sign_path); + rc = rcp_fn(out, (const char *const *) peers, dirname, sign_path); free(sign_path); } else { free(cmdline); cmdline = pcmk__assert_asprintf("rm -f %s %s.sign", path, path); - rc = rsh_fn(out, peers, cmdline); + rc = rsh_fn(out, (const char *const *) peers, cmdline); } done: @@ -893,20 +899,22 @@ subcommand_sync(pcmk__output_t *out, rsh_fn_t rsh_fn, rcp_fn_t rcp_fn) dirname = g_path_get_dirname(PCMK__CIB_SECRETS_DIR); - rc = rsh_fn(out, peers, "rm -rf " PCMK__CIB_SECRETS_DIR); + rc = rsh_fn(out, (const char *const *) peers, + "rm -rf " PCMK__CIB_SECRETS_DIR); if (rc != pcmk_rc_ok) { goto done; } cmdline = pcmk__assert_asprintf("mkdir -p %s", dirname); - rc = rsh_fn(out, peers, cmdline); + rc = rsh_fn(out, (const char *const *) peers, cmdline); free(cmdline); if (rc != pcmk_rc_ok) { goto done; } - rc = rcp_fn(out, peers, dirname, PCMK__CIB_SECRETS_DIR); + rc = rcp_fn(out, (const char *const *) peers, dirname, + PCMK__CIB_SECRETS_DIR); done: g_strfreev(peers); From 28f9d0f04116588098550bc1a166afdfd4eed00f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 19 Dec 2025 23:25:57 -0800 Subject: [PATCH 40/40] Refactor: various: Use const char *const * where possible In the remaining places I could find where it hasn't already been done. This is annoying to look at, but it's correct. char ** and gchar ** are obviously not const, and we should use const where we can. The frustrating thing is that this pointer type is not compatible with char **, so it requires explicit casts. Signed-off-by: Reid Wahl --- daemons/execd/pacemaker-execd.c | 4 +++- daemons/fenced/fenced_commands.c | 12 ++++++++---- daemons/pacemakerd/pacemakerd.c | 4 +++- lib/common/logging.c | 8 ++++++-- lib/common/options_display.c | 8 ++++++-- lib/common/utils.c | 3 ++- lib/services/services.c | 4 +++- lib/services/services_ocf.c | 12 +++++++++--- tools/cibsecret.c | 2 +- tools/crm_mon.c | 10 ++++++---- tools/crm_resource.c | 4 +++- 11 files changed, 50 insertions(+), 21 deletions(-) diff --git a/daemons/execd/pacemaker-execd.c b/daemons/execd/pacemaker-execd.c index 05da4ad822a..030fb349968 100644 --- a/daemons/execd/pacemaker-execd.c +++ b/daemons/execd/pacemaker-execd.c @@ -372,7 +372,9 @@ main(int argc, char **argv) // Open additional log files if (options.log_files != NULL) { - for (gchar **fname = options.log_files; *fname != NULL; fname++) { + for (const char *const *fname = (const char *const *) options.log_files; + *fname != NULL; fname++) { + rc = pcmk__add_logfile(*fname); if (rc != pcmk_rc_ok) { diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 9ddf07ed055..26cae2a5339 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -277,8 +277,8 @@ get_value_for_target(const char *target, const char *values) mappings = g_strsplit_set(values, "; \t", 0); - for (gchar **mapping = mappings; (*mapping != NULL) && (value == NULL); - mapping++) { + for (const char *const *mapping = (const char *const *) mappings; + (*mapping != NULL) && (value == NULL); mapping++) { value = get_value_if_matching(target, *mapping); } @@ -961,7 +961,9 @@ build_port_aliases(const char *hostmap, GList **targets) stripped = g_strstrip(g_strdup(hostmap)); mappings = g_strsplit_set(stripped, "; \t", 0); - for (gchar **mapping = mappings; *mapping != NULL; mapping++) { + for (const char *const *mapping = (const char *const *) mappings; + *mapping != NULL; mapping++) { + gchar **nvpair = NULL; if (pcmk__str_empty(*mapping)) { @@ -1881,7 +1883,9 @@ fenced_register_level(xmlNode *msg, pcmk__action_result_t *result) */ gchar **devices = g_strsplit(value, ",", 0); - for (char **dev = devices; (dev != NULL) && (*dev != NULL); dev++) { + for (const char *const *dev = (const char *const *) devices; + (dev != NULL) && (*dev != NULL); dev++) { + pcmk__trace("Adding device '%s' for %s[%d]", *dev, tp->target, id); tp->levels[id] = g_list_append(tp->levels[id], pcmk__str_copy(*dev)); diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c index 6edfa6d0fcc..eb5ea592497 100644 --- a/daemons/pacemakerd/pacemakerd.c +++ b/daemons/pacemakerd/pacemakerd.c @@ -75,7 +75,9 @@ pacemakerd_features_xml(pcmk__output_t *out, va_list args) { NULL); out->begin_list(out, NULL, NULL, PCMK_XE_FEATURES); - for (char **s = feature_list; *s != NULL; s++) { + for (const char *const *s = (const char *const *) feature_list; *s != NULL; + s++) { + pcmk__output_create_xml_text_node(out, PCMK_XE_FEATURE, *s); } diff --git a/lib/common/logging.c b/lib/common/logging.c index bd22e8ca48f..51bf0de44a2 100644 --- a/lib/common/logging.c +++ b/lib/common/logging.c @@ -720,7 +720,9 @@ init_tracing(void) if (tags != NULL) { gchar **trace_tags = g_strsplit(tags, ",", 0); - for (gchar **tag = trace_tags; *tag != NULL; tag++) { + for (const char *const *tag = (const char *const *) trace_tags; + *tag != NULL; tag++) { + if (pcmk__str_empty(*tag)) { continue; } @@ -1220,7 +1222,9 @@ crm_log_output_fn(const char *file, const char *function, int line, int level, c out_lines = g_strsplit(output, "\n", 0); - for (gchar **out_line = out_lines; *out_line != NULL; out_line++) { + for (const char *const *out_line = (const char *const*) out_lines; + *out_line != NULL; out_line++) { + do_crm_log_alias(level, file, function, line, "%s [ %s ]", prefix, *out_line); } diff --git a/lib/common/options_display.c b/lib/common/options_display.c index 40cc5de75ef..0a35d1dd348 100644 --- a/lib/common/options_display.c +++ b/lib/common/options_display.c @@ -41,7 +41,9 @@ add_possible_values_default(pcmk__output_t *out, gchar **values = g_strsplit(option->values, ", ", 0); - for (gchar **value = values; *value != NULL; value++) { + for (const char *const *value = (const char *const *) values; + *value != NULL; value++) { + if (buf->len > 0) { g_string_append(buf, ", "); } @@ -297,7 +299,9 @@ add_possible_values_xml(pcmk__output_t *out, values = g_strsplit(option->values, ", ", 0); - for (gchar **value = values; *value != NULL; value++) { + for (const char *const *value = (const char *const *) values; + *value != NULL; value++) { + pcmk__output_create_xml_node(out, PCMK_XE_OPTION, PCMK_XA_VALUE, *value, NULL); diff --git a/lib/common/utils.c b/lib/common/utils.c index 9c0c115e5e8..bcb5ec8b856 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -242,7 +242,8 @@ pcmk__compare_versions(const char *version1, const char *version2) segments1 = g_strsplit(pcmk__s(match1, ""), ".", 0); segments2 = g_strsplit(pcmk__s(match2, ""), ".", 0); - for (gchar **segment1 = segments1, **segment2 = segments2; + for (const char *const *segment1 = (const char *const *) segments1, + *const *segment2 = (const char *const *) segments2; (*segment1 != NULL) || (*segment2 != NULL); ) { long long value1 = 0; diff --git a/lib/services/services.c b/lib/services/services.c index 84e0e5afaa3..dff44d4926b 100644 --- a/lib/services/services.c +++ b/lib/services/services.c @@ -1454,7 +1454,9 @@ get_directory_list(const char *root, gboolean files, gboolean executable) dir_paths = g_strsplit(root, ":", 0); - for (gchar **dir = dir_paths; *dir != NULL; dir++) { + for (const char *const *dir = (const char *const *) dir_paths; + *dir != NULL; dir++) { + list = g_list_concat(list, gdl_helper(*dir, files, executable)); } diff --git a/lib/services/services_ocf.c b/lib/services/services_ocf.c index 85f7be9b279..8e755cc3829 100644 --- a/lib/services/services_ocf.c +++ b/lib/services/services_ocf.c @@ -43,7 +43,9 @@ services__list_ocf_providers(void) // NULL dirs should be impossible if PCMK__OCF_RA_PATH is defined correctly CRM_CHECK(dirs != NULL, return NULL); - for (gchar **dir = dirs; *dir != NULL; dir++) { + for (const char *const *dir = (const char *const *) dirs; *dir != NULL; + dir++) { + list = g_list_concat(list, services__list_dir(*dir, false)); } @@ -94,7 +96,9 @@ services__list_ocf_agents(const char *provider) // NULL dirs should be impossible if PCMK__OCF_RA_PATH is defined correctly CRM_CHECK(dirs != NULL, return NULL); - for (gchar **dir = dirs; *dir != NULL; dir++) { + for (const char *const *dir = (const char *const *) dirs; *dir != NULL; + dir++) { + char *buf = pcmk__assert_asprintf("%s/%s", *dir, provider); list = g_list_concat(list, services__list_dir(buf, true)); @@ -140,7 +144,9 @@ services__ocf_agent_exists(const char *provider, const char *agent, char **path) // NULL dirs should be impossible if PCMK__OCF_RA_PATH is defined correctly CRM_CHECK(dirs != NULL, return NULL); - for (gchar **dir = dirs; !found && (*dir != NULL); dir++) { + for (const char *const *dir = (const char *const *) dirs; + !found && (*dir != NULL); dir++) { + char *buf = pcmk__assert_asprintf("%s/%s/%s", *dir, provider, agent); struct stat sb; diff --git a/tools/cibsecret.c b/tools/cibsecret.c index a07128a7d30..c39bfbfa386 100644 --- a/tools/cibsecret.c +++ b/tools/cibsecret.c @@ -321,7 +321,7 @@ reachable_hosts(pcmk__output_t *out, GList *all) g_free(path); g_ptr_array_add(reachable, NULL); - return (char **) g_ptr_array_free(reachable, FALSE); + return (gchar **) g_ptr_array_free(reachable, FALSE); } struct node_data { diff --git a/tools/crm_mon.c b/tools/crm_mon.c index 8d77d45813b..eab0f9bc774 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -302,11 +302,12 @@ find_section_bit(const char *name) { static gboolean apply_exclude(const gchar *excludes, GError **error) { - char **parts = NULL; + gchar **parts = NULL; gboolean result = TRUE; parts = g_strsplit(excludes, ",", 0); - for (char **s = parts; *s != NULL; s++) { + + for (const char *const *s = (const char *const *) parts; *s != NULL; s++) { uint32_t bit = find_section_bit(*s); if (pcmk__str_eq(*s, "all", pcmk__str_none)) { @@ -332,11 +333,12 @@ apply_exclude(const gchar *excludes, GError **error) { static gboolean apply_include(const gchar *includes, GError **error) { - char **parts = NULL; + gchar **parts = NULL; gboolean result = TRUE; parts = g_strsplit(includes, ",", 0); - for (char **s = parts; *s != NULL; s++) { + + for (const char *const *s = (const char *const *) parts; *s != NULL; s++) { uint32_t bit = find_section_bit(*s); if (pcmk__str_eq(*s, "all", pcmk__str_none)) { diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 69f591be740..9de8a612d72 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -2133,7 +2133,9 @@ main(int argc, char **argv) goto done; } - for (gchar **arg = options.remainder; *arg != NULL; arg++) { + for (const char *const *arg = (const char *const *) options.remainder; + *arg != NULL; arg++) { + gchar *name = NULL; gchar *value = NULL; int rc = pcmk__scan_nvpair(*arg, &name, &value);