From b41961d74fe7ff2d4d4abaca92454e87c561e49f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 3 Jun 2024 15:39:29 +0200 Subject: Merging upstream version 2.1.8~rc1. Signed-off-by: Daniel Baumann --- lib/common/tests/xml/Makefile.am | 11 +- lib/common/tests/xml/crm_xml_init_test.c | 230 ++++++++++++++ lib/common/tests/xml/pcmk__xe_copy_attrs_test.c | 188 ++++++++++++ lib/common/tests/xml/pcmk__xe_first_child_test.c | 106 +++++++ lib/common/tests/xml/pcmk__xe_foreach_child_test.c | 20 +- lib/common/tests/xml/pcmk__xe_match_test.c | 106 ------- lib/common/tests/xml/pcmk__xe_set_score_test.c | 188 ++++++++++++ lib/common/tests/xml/pcmk__xml_escape_test.c | 213 +++++++++++++ lib/common/tests/xml/pcmk__xml_needs_escape_test.c | 337 +++++++++++++++++++++ 9 files changed, 1280 insertions(+), 119 deletions(-) create mode 100644 lib/common/tests/xml/crm_xml_init_test.c create mode 100644 lib/common/tests/xml/pcmk__xe_copy_attrs_test.c create mode 100644 lib/common/tests/xml/pcmk__xe_first_child_test.c delete mode 100644 lib/common/tests/xml/pcmk__xe_match_test.c create mode 100644 lib/common/tests/xml/pcmk__xe_set_score_test.c create mode 100644 lib/common/tests/xml/pcmk__xml_escape_test.c create mode 100644 lib/common/tests/xml/pcmk__xml_needs_escape_test.c (limited to 'lib/common/tests/xml') diff --git a/lib/common/tests/xml/Makefile.am b/lib/common/tests/xml/Makefile.am index 465c950..9ed1620 100644 --- a/lib/common/tests/xml/Makefile.am +++ b/lib/common/tests/xml/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2022-2023 the Pacemaker project contributors +# Copyright 2022-2024 the Pacemaker project contributors # # The version control history for this file may have further details. # @@ -11,7 +11,12 @@ include $(top_srcdir)/mk/tap.mk include $(top_srcdir)/mk/unittest.mk # Add "_test" to the end of all test program names to simplify .gitignore. -check_PROGRAMS = pcmk__xe_foreach_child_test \ - pcmk__xe_match_test +check_PROGRAMS = crm_xml_init_test \ + pcmk__xe_copy_attrs_test \ + pcmk__xe_first_child_test \ + pcmk__xe_foreach_child_test \ + pcmk__xe_set_score_test \ + pcmk__xml_escape_test \ + pcmk__xml_needs_escape_test TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/xml/crm_xml_init_test.c b/lib/common/tests/xml/crm_xml_init_test.c new file mode 100644 index 0000000..1f78728 --- /dev/null +++ b/lib/common/tests/xml/crm_xml_init_test.c @@ -0,0 +1,230 @@ +/* + * Copyright 2023-2024 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include +#include +#include + +#include "crmcommon_private.h" + +/* Copied from lib/common/xml.c */ +#define XML_DOC_PRIVATE_MAGIC 0x81726354UL +#define XML_NODE_PRIVATE_MAGIC 0x54637281UL + +static int +setup(void **state) { + crm_xml_init(); + return 0; +} + +static int +teardown(void **state) { + crm_xml_cleanup(); + return 0; +} + +static void +buffer_scheme_test(void **state) { + assert_int_equal(XML_BUFFER_ALLOC_DOUBLEIT, xmlGetBufferAllocationScheme()); +} + +/* These functions also serve as unit tests of the static new_private_data + * function. We can't test free_private_data because libxml will call that as + * part of freeing everything else. By the time we'd get back into a unit test + * where we could check that private members are NULL, the structure containing + * the private data would have been freed. + * + * This could probably be tested with a lot of function mocking, but that + * doesn't seem worth it. + */ + +static void +create_document_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + + /* Double check things */ + assert_non_null(doc); + assert_int_equal(doc->type, XML_DOCUMENT_NODE); + + /* Check that the private data is initialized correctly */ + docpriv = doc->_private; + assert_non_null(docpriv); + assert_int_equal(docpriv->check, XML_DOC_PRIVATE_MAGIC); + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty|pcmk__xf_created)); + + /* Clean up */ + xmlFreeDoc(doc); +} + +static void +create_element_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlNodePtr node = xmlNewDocNode(doc, NULL, (pcmkXmlStr) "test", NULL); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(node); + assert_int_equal(node->type, XML_ELEMENT_NODE); + + /* Check that the private data is initialized correctly */ + priv = node->_private; + assert_non_null(priv); + assert_int_equal(priv->check, XML_NODE_PRIVATE_MAGIC); + assert_true(pcmk_all_flags_set(priv->flags, pcmk__xf_dirty|pcmk__xf_created)); + + /* Clean up */ + xmlFreeNode(node); + xmlFreeDoc(doc); +} + +static void +create_attr_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlNodePtr node = xmlNewDocNode(doc, NULL, (pcmkXmlStr) "test", NULL); + xmlAttrPtr attr = xmlNewProp(node, (pcmkXmlStr) PCMK_XA_NAME, + (pcmkXmlStr) "dummy-value"); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(attr); + assert_int_equal(attr->type, XML_ATTRIBUTE_NODE); + + /* Check that the private data is initialized correctly */ + priv = attr->_private; + assert_non_null(priv); + assert_int_equal(priv->check, XML_NODE_PRIVATE_MAGIC); + assert_true(pcmk_all_flags_set(priv->flags, pcmk__xf_dirty|pcmk__xf_created)); + + /* Clean up */ + xmlFreeNode(node); + xmlFreeDoc(doc); +} + +static void +create_comment_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlNodePtr node = xmlNewDocComment(doc, (pcmkXmlStr) "blahblah"); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(node); + assert_int_equal(node->type, XML_COMMENT_NODE); + + /* Check that the private data is initialized correctly */ + priv = node->_private; + assert_non_null(priv); + assert_int_equal(priv->check, XML_NODE_PRIVATE_MAGIC); + assert_true(pcmk_all_flags_set(priv->flags, pcmk__xf_dirty|pcmk__xf_created)); + + /* Clean up */ + xmlFreeNode(node); + xmlFreeDoc(doc); +} + +static void +create_text_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlNodePtr node = xmlNewDocText(doc, (pcmkXmlStr) "blahblah"); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(node); + assert_int_equal(node->type, XML_TEXT_NODE); + + /* Check that no private data was created */ + priv = node->_private; + assert_null(priv); + + /* Clean up */ + xmlFreeNode(node); + xmlFreeDoc(doc); +} + +static void +create_dtd_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlDtdPtr dtd = xmlNewDtd(doc, (pcmkXmlStr) PCMK_XA_NAME, + (pcmkXmlStr) "externalId", + (pcmkXmlStr) "systemId"); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(dtd); + assert_int_equal(dtd->type, XML_DTD_NODE); + + /* Check that no private data was created */ + priv = dtd->_private; + assert_null(priv); + + /* Clean up */ + /* If you call xmlFreeDtd before xmlFreeDoc, you get a segfault */ + xmlFreeDoc(doc); +} + +static void +create_cdata_node(void **state) { + xml_doc_private_t *docpriv = NULL; + xml_node_private_t *priv = NULL; + xmlDocPtr doc = xmlNewDoc(PCMK__XML_VERSION); + xmlNodePtr node = xmlNewCDataBlock(doc, (pcmkXmlStr) "blahblah", 8); + + /* Adding a node to the document marks it as dirty */ + docpriv = doc->_private; + assert_true(pcmk_all_flags_set(docpriv->flags, pcmk__xf_dirty)); + + /* Double check things */ + assert_non_null(node); + assert_int_equal(node->type, XML_CDATA_SECTION_NODE); + + /* Check that no private data was created */ + priv = node->_private; + assert_null(priv); + + /* Clean up */ + xmlFreeNode(node); + xmlFreeDoc(doc); +} + +PCMK__UNIT_TEST(setup, teardown, + cmocka_unit_test(buffer_scheme_test), + cmocka_unit_test(create_document_node), + cmocka_unit_test(create_element_node), + cmocka_unit_test(create_attr_node), + cmocka_unit_test(create_comment_node), + cmocka_unit_test(create_text_node), + cmocka_unit_test(create_dtd_node), + cmocka_unit_test(create_cdata_node)); diff --git a/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c b/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c new file mode 100644 index 0000000..146317c --- /dev/null +++ b/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c @@ -0,0 +1,188 @@ + /* + * Copyright 2022-2024 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include + +#include + +static void +null_args(void **state) +{ + // This test dumps core via CRM_CHECK() + xmlNode *xml = pcmk__xe_create(NULL, "test"); + + assert_int_equal(pcmk__xe_copy_attrs(NULL, NULL, pcmk__xaf_none), EINVAL); + assert_int_equal(pcmk__xe_copy_attrs(NULL, xml, pcmk__xaf_none), EINVAL); + assert_int_equal(pcmk__xe_copy_attrs(xml, NULL, pcmk__xaf_none), EINVAL); + assert_ptr_equal(xml->properties, NULL); + + free_xml(xml); +} + +static void +no_source_attrs(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + // Ensure copying from empty source doesn't create target properties + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_ptr_equal(target->properties, NULL); + + // Ensure copying from empty source doesn't delete target attributes + crm_xml_add(target, "attr", "value"); + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_string_equal(crm_element_value(target, "attr"), "value"); + + free_xml(src); + free_xml(target); +} + +static void +copy_one(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + crm_xml_add(src, "attr", "value"); + + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_string_equal(crm_element_value(src, "attr"), + crm_element_value(target, "attr")); + + free_xml(src); + free_xml(target); +} + +static void +copy_multiple(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + pcmk__xe_set_props(src, + "attr1", "value1", + "attr2", "value2", + "attr3", "value3", + NULL); + + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_string_equal(crm_element_value(src, "attr1"), + crm_element_value(target, "attr1")); + assert_string_equal(crm_element_value(src, "attr2"), + crm_element_value(target, "attr2")); + assert_string_equal(crm_element_value(src, "attr3"), + crm_element_value(target, "attr3")); + + free_xml(src); + free_xml(target); +} + +static void +overwrite(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + crm_xml_add(src, "attr", "src_value"); + crm_xml_add(target, "attr", "target_value"); + + // Overwrite enabled by default + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_string_equal(crm_element_value(src, "attr"), + crm_element_value(target, "attr")); + free_xml(src); + free_xml(target); +} + +static void +no_overwrite(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + crm_xml_add(src, "attr", "src_value"); + crm_xml_add(target, "attr", "target_value"); + + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_no_overwrite), + pcmk_rc_ok); + assert_string_not_equal(crm_element_value(src, "attr"), + crm_element_value(target, "attr")); + + // no_overwrite doesn't prevent copy if there's no conflict + pcmk__xe_remove_attr(target, "attr"); + + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_no_overwrite), + pcmk_rc_ok); + assert_string_equal(crm_element_value(src, "attr"), + crm_element_value(target, "attr")); + + free_xml(src); + free_xml(target); +} + +static void +score_update(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + crm_xml_add(src, "plus_plus_attr", "plus_plus_attr++"); + crm_xml_add(src, "plus_two_attr", "plus_two_attr+=2"); + crm_xml_add(target, "plus_plus_attr", "1"); + crm_xml_add(target, "plus_two_attr", "1"); + + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_score_update), + pcmk_rc_ok); + assert_string_equal(crm_element_value(target, "plus_plus_attr"), "2"); + assert_string_equal(crm_element_value(target, "plus_two_attr"), "3"); + + free_xml(src); + free_xml(target); +} + +static void +no_score_update(void **state) +{ + xmlNode *src = pcmk__xe_create(NULL, "test"); + xmlNode *target = pcmk__xe_create(NULL, "test"); + + crm_xml_add(src, "plus_plus_attr", "plus_plus_attr++"); + crm_xml_add(src, "plus_two_attr", "plus_two_attr+=2"); + crm_xml_add(target, "plus_plus_attr", "1"); + crm_xml_add(target, "plus_two_attr", "1"); + + // Score update disabled by default + assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none), + pcmk_rc_ok); + assert_string_equal(crm_element_value(target, "plus_plus_attr"), + "plus_plus_attr++"); + assert_string_equal(crm_element_value(target, "plus_two_attr"), + "plus_two_attr+=2"); + + free_xml(src); + free_xml(target); +} + +PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL, + cmocka_unit_test(null_args), + cmocka_unit_test(no_source_attrs), + cmocka_unit_test(copy_one), + cmocka_unit_test(copy_multiple), + cmocka_unit_test(overwrite), + cmocka_unit_test(no_overwrite), + cmocka_unit_test(score_update), + cmocka_unit_test(no_score_update)); diff --git a/lib/common/tests/xml/pcmk__xe_first_child_test.c b/lib/common/tests/xml/pcmk__xe_first_child_test.c new file mode 100644 index 0000000..64b90b0 --- /dev/null +++ b/lib/common/tests/xml/pcmk__xe_first_child_test.c @@ -0,0 +1,106 @@ +/* + * Copyright 2024 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include +#include +#include + +const char *str1 = + "\n" + " \n" + " \n" + " content\n" + " \n" + " \n" + " \n" + " content\n" + " \n" + " \n" + " \n" + " content\n" + " \n" + " \n" + " \n" + " content\n" + " \n" + " \n" + " \n" + " content\n" + " \n" + ""; + +static void +bad_input(void **state) { + xmlNode *xml = pcmk__xml_parse(str1); + + assert_null(pcmk__xe_first_child(NULL, NULL, NULL, NULL)); + assert_null(pcmk__xe_first_child(NULL, NULL, NULL, "attrX")); + + free_xml(xml); +} + +static void +not_found(void **state) { + xmlNode *xml = pcmk__xml_parse(str1); + + /* No node with an attrX attribute */ + assert_null(pcmk__xe_first_child(xml, NULL, "attrX", NULL)); + /* No nodeX node */ + assert_null(pcmk__xe_first_child(xml, "nodeX", NULL, NULL)); + /* No nodeA node with attrX */ + assert_null(pcmk__xe_first_child(xml, "nodeA", "attrX", NULL)); + /* No nodeA node with attrA=XYZ */ + assert_null(pcmk__xe_first_child(xml, "nodeA", "attrA", "XYZ")); + + free_xml(xml); +} + +static void +find_attrB(void **state) { + xmlNode *xml = pcmk__xml_parse(str1); + xmlNode *result = NULL; + + /* Find the first node with attrB */ + result = pcmk__xe_first_child(xml, NULL, "attrB", NULL); + assert_non_null(result); + assert_string_equal(crm_element_value(result, PCMK_XA_ID), "3"); + + /* Find the first nodeB with attrB */ + result = pcmk__xe_first_child(xml, "nodeB", "attrB", NULL); + assert_non_null(result); + assert_string_equal(crm_element_value(result, PCMK_XA_ID), "5"); + + free_xml(xml); +} + +static void +find_attrA_matching(void **state) { + xmlNode *xml = pcmk__xml_parse(str1); + xmlNode *result = NULL; + + /* Find attrA=456 */ + result = pcmk__xe_first_child(xml, NULL, "attrA", "456"); + assert_non_null(result); + assert_string_equal(crm_element_value(result, PCMK_XA_ID), "2"); + + /* Find a nodeB with attrA=123 */ + result = pcmk__xe_first_child(xml, "nodeB", "attrA", "123"); + assert_non_null(result); + assert_string_equal(crm_element_value(result, PCMK_XA_ID), "4"); + + free_xml(xml); +} + +PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(not_found), + cmocka_unit_test(find_attrB), + cmocka_unit_test(find_attrA_matching)); diff --git a/lib/common/tests/xml/pcmk__xe_foreach_child_test.c b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c index ffb9171..a833dde 100644 --- a/lib/common/tests/xml/pcmk__xe_foreach_child_test.c +++ b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the Pacemaker project contributors + * Copyright 2022-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -36,7 +36,7 @@ const char *str1 = static void bad_input(void **state) { - xmlNode *xml = string2xml(str1); + xmlNode *xml = pcmk__xml_parse(str1); pcmk__assert_asserts(pcmk__xe_foreach_child(xml, NULL, NULL, NULL)); @@ -45,7 +45,7 @@ bad_input(void **state) { static void name_given_test(void **state) { - xmlNode *xml = string2xml(str1); + xmlNode *xml = pcmk__xml_parse(str1); /* The handler should be called once for every node. */ expect_function_call(compare_name_handler); @@ -58,7 +58,7 @@ name_given_test(void **state) { static void no_name_given_test(void **state) { - xmlNode *xml = string2xml(str1); + xmlNode *xml = pcmk__xml_parse(str1); /* The handler should be called once for every node. */ expect_function_call(compare_name_handler); @@ -71,7 +71,7 @@ no_name_given_test(void **state) { static void name_doesnt_exist_test(void **state) { - xmlNode *xml = string2xml(str1); + xmlNode *xml = pcmk__xml_parse(str1); pcmk__xe_foreach_child(xml, "xxx", compare_name_handler, NULL); free_xml(xml); } @@ -100,7 +100,7 @@ const char *str2 = static void multiple_levels_test(void **state) { - xmlNode *xml = string2xml(str2); + xmlNode *xml = pcmk__xml_parse(str2); /* The handler should be called once for every node. */ expect_function_call(compare_name_handler); @@ -112,7 +112,7 @@ multiple_levels_test(void **state) { static void multiple_levels_no_name_test(void **state) { - xmlNode *xml = string2xml(str2); + xmlNode *xml = pcmk__xml_parse(str2); /* The handler should be called once for every node. */ expect_function_call(compare_name_handler); @@ -147,7 +147,7 @@ static int any_of_handler(xmlNode *xml, void *userdata) { static void any_of_test(void **state) { - xmlNode *xml = string2xml(str3); + xmlNode *xml = pcmk__xml_parse(str3); /* The handler should be called once for every node. */ expect_function_call(any_of_handler); @@ -190,7 +190,7 @@ static int stops_on_third_handler(xmlNode *xml, void *userdata) { static void one_of_test(void **state) { - xmlNode *xml = string2xml(str3); + xmlNode *xml = pcmk__xml_parse(str3); /* The handler should be called once. */ expect_function_call(stops_on_first_handler); @@ -205,7 +205,7 @@ one_of_test(void **state) { free_xml(xml); } -PCMK__UNIT_TEST(NULL, NULL, +PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL, cmocka_unit_test(bad_input), cmocka_unit_test(name_given_test), cmocka_unit_test(no_name_given_test), diff --git a/lib/common/tests/xml/pcmk__xe_match_test.c b/lib/common/tests/xml/pcmk__xe_match_test.c deleted file mode 100644 index be2c949..0000000 --- a/lib/common/tests/xml/pcmk__xe_match_test.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2022 the Pacemaker project contributors - * - * The version control history for this file may have further details. - * - * This source code is licensed under the GNU General Public License version 2 - * or later (GPLv2+) WITHOUT ANY WARRANTY. - */ - -#include - -#include -#include -#include - -const char *str1 = - "\n" - " \n" - " \n" - " content\n" - " \n" - " \n" - " \n" - " content\n" - " \n" - " \n" - " \n" - " content\n" - " \n" - " \n" - " \n" - " content\n" - " \n" - " \n" - " \n" - " content\n" - " \n" - ""; - -static void -bad_input(void **state) { - xmlNode *xml = string2xml(str1); - - assert_null(pcmk__xe_match(NULL, NULL, NULL, NULL)); - assert_null(pcmk__xe_match(NULL, NULL, NULL, "attrX")); - - free_xml(xml); -} - -static void -not_found(void **state) { - xmlNode *xml = string2xml(str1); - - /* No node with an attrX attribute */ - assert_null(pcmk__xe_match(xml, NULL, "attrX", NULL)); - /* No nodeX node */ - assert_null(pcmk__xe_match(xml, "nodeX", NULL, NULL)); - /* No nodeA node with attrX */ - assert_null(pcmk__xe_match(xml, "nodeA", "attrX", NULL)); - /* No nodeA node with attrA=XYZ */ - assert_null(pcmk__xe_match(xml, "nodeA", "attrA", "XYZ")); - - free_xml(xml); -} - -static void -find_attrB(void **state) { - xmlNode *xml = string2xml(str1); - xmlNode *result = NULL; - - /* Find the first node with attrB */ - result = pcmk__xe_match(xml, NULL, "attrB", NULL); - assert_non_null(result); - assert_string_equal(crm_element_value(result, "id"), "3"); - - /* Find the first nodeB with attrB */ - result = pcmk__xe_match(xml, "nodeB", "attrB", NULL); - assert_non_null(result); - assert_string_equal(crm_element_value(result, "id"), "5"); - - free_xml(xml); -} - -static void -find_attrA_matching(void **state) { - xmlNode *xml = string2xml(str1); - xmlNode *result = NULL; - - /* Find attrA=456 */ - result = pcmk__xe_match(xml, NULL, "attrA", "456"); - assert_non_null(result); - assert_string_equal(crm_element_value(result, "id"), "2"); - - /* Find a nodeB with attrA=123 */ - result = pcmk__xe_match(xml, "nodeB", "attrA", "123"); - assert_non_null(result); - assert_string_equal(crm_element_value(result, "id"), "4"); - - free_xml(xml); -} - -PCMK__UNIT_TEST(NULL, NULL, - cmocka_unit_test(bad_input), - cmocka_unit_test(not_found), - cmocka_unit_test(find_attrB), - cmocka_unit_test(find_attrA_matching)); diff --git a/lib/common/tests/xml/pcmk__xe_set_score_test.c b/lib/common/tests/xml/pcmk__xe_set_score_test.c new file mode 100644 index 0000000..deb85b0 --- /dev/null +++ b/lib/common/tests/xml/pcmk__xe_set_score_test.c @@ -0,0 +1,188 @@ +/* + * Copyright 2022-2024 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include + +#include + +#include "crmcommon_private.h" // pcmk__xe_set_score() + +/*! + * \internal + * \brief Update an XML attribute value and check it against a reference value + * + * The attribute name is hard-coded as \c "X". + * + * \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() + */ +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"); + + crm_xml_add(test_xml, name, initial); + assert_int_equal(pcmk__xe_set_score(test_xml, name, new), reference_rc); + assert_string_equal(crm_element_value(test_xml, name), reference_val); + + free_xml(test_xml); +} + +static void +value_is_name_plus_plus(void **state) +{ + assert_set_score("5", "X++", "6", pcmk_rc_ok); +} + +static void +value_is_name_plus_equals_integer(void **state) +{ + assert_set_score("5", "X+=2", "7", pcmk_rc_ok); +} + +// NULL input + +static void +target_is_NULL(void **state) +{ + // Dumps core via CRM_CHECK() + assert_int_equal(pcmk__xe_set_score(NULL, "X", "X++"), EINVAL); +} + +static void +name_is_NULL(void **state) +{ + xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml"); + + crm_xml_add(test_xml, "X", "5"); + + // Dumps core via CRM_CHECK() + assert_int_equal(pcmk__xe_set_score(test_xml, NULL, "X++"), EINVAL); + assert_string_equal(crm_element_value(test_xml, "X"), "5"); + + free_xml(test_xml); +} + +static void +value_is_NULL(void **state) +{ + assert_set_score("5", NULL, "5", pcmk_rc_ok); +} + +// the value input doesn't start with the name input + +static void +value_is_wrong_name(void **state) +{ + assert_set_score("5", "Y++", "Y++", pcmk_rc_ok); +} + +static void +value_is_only_an_integer(void **state) +{ + assert_set_score("5", "2", "2", pcmk_rc_ok); +} + +// non-integers + +static void +variable_is_initialized_to_be_non_numeric(void **state) +{ + assert_set_score("hello", "X++", "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); +} + +static void +variable_is_initialized_to_be_numeric_and_decimal_point_containing(void **state) +{ + assert_set_score("5.01", "X++", "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); +} + +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); +} + +static void +value_is_non_numeric(void **state) +{ + assert_set_score("5", "X+=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); +} + +static void +value_is_numeric_and_decimal_point_containing_2(void **state) +{ + assert_set_score("5", "X+=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); +} + +// undefined input + +static void +name_is_undefined(void **state) +{ + assert_set_score(NULL, "X++", "X++", pcmk_rc_ok); +} + +// large input + +static void +assignment_result_is_too_large(void **state) +{ + assert_set_score("5", "X+=100000000000", "1000000", pcmk_rc_ok); +} + +PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL, + 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)) diff --git a/lib/common/tests/xml/pcmk__xml_escape_test.c b/lib/common/tests/xml/pcmk__xml_escape_test.c new file mode 100644 index 0000000..8c6fd21 --- /dev/null +++ b/lib/common/tests/xml/pcmk__xml_escape_test.c @@ -0,0 +1,213 @@ +/* + * Copyright 2024 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include +#include + +#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); +} + +static void +null_empty(void **state) +{ + assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_text)); + assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_attr)); + assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_attr_pretty)); + + assert_escape("", "", pcmk__xml_escape_text); + assert_escape("", "", pcmk__xml_escape_attr); + assert_escape("", "", pcmk__xml_escape_attr_pretty); +} + +static void +invalid_type(void **state) +{ + const enum pcmk__xml_escape_type type = (enum pcmk__xml_escape_type) -1; + + // Easier to ignore invalid type for NULL or empty string + assert_null(pcmk__xml_escape(NULL, type)); + assert_escape("", "", type); + + // Otherwise, assert if we somehow passed an invalid type + pcmk__assert_asserts(pcmk__xml_escape("he<>llo", type)); +} + +static void +escape_unchanged(void **state) +{ + // No escaped characters (note: this string includes single quote at end) + const char *unchanged = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "`~!@#$%^*()-_=+/|\\[]{}?.,'"; + + assert_escape(unchanged, unchanged, pcmk__xml_escape_text); + assert_escape(unchanged, unchanged, pcmk__xml_escape_attr); + assert_escape(unchanged, unchanged, pcmk__xml_escape_attr_pretty); +} + +// Ensure special characters get escaped at start, middle, and end + +static void +escape_left_angle(void **state) +{ + const char *l_angle = " + +#include +#include + +#include "crmcommon_private.h" + +static void +null_empty(void **state) +{ + assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_text)); + assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_attr)); + assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_attr_pretty)); + + assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_text)); + assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_attr)); + assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_attr_pretty)); +} + +static void +invalid_type(void **state) +{ + const enum pcmk__xml_escape_type type = (enum pcmk__xml_escape_type) -1; + + // Easier to ignore invalid type for NULL or empty string + assert_false(pcmk__xml_needs_escape(NULL, type)); + assert_false(pcmk__xml_needs_escape("", type)); + + // Otherwise, assert if we somehow passed an invalid type + pcmk__assert_asserts(pcmk__xml_needs_escape("he<>llo", type)); +} + +static void +escape_unchanged(void **state) +{ + // No escaped characters (note: this string includes single quote at end) + const char *unchanged = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "`~!@#$%^*()-_=+/|\\[]{}?.,'"; + + assert_false(pcmk__xml_needs_escape(unchanged, pcmk__xml_escape_text)); + assert_false(pcmk__xml_needs_escape(unchanged, pcmk__xml_escape_attr)); + assert_false(pcmk__xml_needs_escape(unchanged, + pcmk__xml_escape_attr_pretty)); +} + +// Ensure special characters get escaped at start, middle, and end + +static void +escape_left_angle(void **state) +{ + const char *l_angle_left = "