root/lib/common/tests/xml_element/pcmk__xe_sort_attrs_test.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. assert_order
  2. null_arg
  3. nothing_to_sort
  4. already_sorted
  5. need_sort

   1 /*
   2  * Copyright 2024-2025 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <crm/common/unittest_internal.h>
  13 
  14 #include <glib.h>                           // GHashTable, etc.
  15 #include <libxml/tree.h>                    // xmlNode
  16 #include <libxml/xmlstring.h>               // xmlChar
  17 
  18 #include "crmcommon_private.h"              // xml_node_private_t
  19 
  20 /*!
  21  * \internal
  22  * \brief Sort an XML element's attributes and compare against a reference
  23  *
  24  * This also verifies that any flags set on the original attributes are
  25  * preserved.
  26  *
  27  * \param[in,out] test_xml       XML whose attributes to sort
  28  * \param[in]     reference_xml  XML whose attribute order to compare against
  29  *                               (attributes must have the same values as in
  30  *                               \p test_xml)
  31  */
  32 static void
  33 assert_order(xmlNode *test_xml, const xmlNode *reference_xml)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35     GHashTable *attr_flags = pcmk__strkey_table(free, NULL);
  36     xmlAttr *test_attr = NULL;
  37     xmlAttr *ref_attr = NULL;
  38 
  39     // Save original flags
  40     for (xmlAttr *attr = pcmk__xe_first_attr(test_xml); attr != NULL;
  41          attr = attr->next) {
  42 
  43         xml_node_private_t *nodepriv = attr->_private;
  44         uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
  45 
  46         g_hash_table_insert(attr_flags,
  47                             pcmk__str_copy((const char *) attr->name),
  48                             GUINT_TO_POINTER((guint) flags));
  49     }
  50 
  51     pcmk__xe_sort_attrs(test_xml);
  52 
  53     test_attr = pcmk__xe_first_attr(test_xml);
  54     ref_attr = pcmk__xe_first_attr(reference_xml);
  55 
  56     for (; (test_attr != NULL) && (ref_attr != NULL);
  57          test_attr = test_attr->next, ref_attr = ref_attr->next) {
  58 
  59         const char *test_name = (const char *) test_attr->name;
  60         xml_node_private_t *nodepriv = test_attr->_private;
  61         uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
  62 
  63         gpointer old_flags_ptr = g_hash_table_lookup(attr_flags, test_name);
  64         uint32_t old_flags = pcmk__xf_none;
  65 
  66         if (old_flags_ptr != NULL) {
  67             old_flags = GPOINTER_TO_UINT(old_flags_ptr);
  68         }
  69 
  70         // Flags must not change
  71         assert_true(flags == old_flags);
  72 
  73         // Attributes must be in expected order with expected values
  74         assert_string_equal(test_name, (const char *) ref_attr->name);
  75         assert_string_equal(pcmk__xml_attr_value(test_attr),
  76                             pcmk__xml_attr_value(ref_attr));
  77     }
  78 
  79     // Attribute lists must be the same length
  80     assert_null(test_attr);
  81     assert_null(ref_attr);
  82 
  83     g_hash_table_destroy(attr_flags);
  84 }
  85 
  86 static void
  87 null_arg(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89     // Ensure it doesn't crash
  90     pcmk__xe_sort_attrs(NULL);
  91 }
  92 
  93 static void
  94 nothing_to_sort(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96     xmlNode *test_xml = pcmk__xe_create(NULL, "test");
  97     xmlNode *reference_xml = NULL;
  98 
  99     // No attributes
 100     reference_xml = pcmk__xml_copy(NULL, test_xml);
 101     assert_order(test_xml, reference_xml);
 102     pcmk__xml_free(reference_xml);
 103 
 104     // Only one attribute
 105     crm_xml_add(test_xml, "name", "value");
 106     reference_xml = pcmk__xml_copy(NULL, test_xml);
 107     assert_order(test_xml, reference_xml);
 108     pcmk__xml_free(reference_xml);
 109 
 110     pcmk__xml_free(test_xml);
 111 }
 112 
 113 static void
 114 already_sorted(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116     xmlNode *test_xml = pcmk__xe_create(NULL, "test");
 117     xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
 118 
 119     xmlAttr *attr = NULL;
 120 
 121     crm_xml_add(test_xml, "admin", "john");
 122     crm_xml_add(test_xml, "dummy", "value");
 123     crm_xml_add(test_xml, "location", "usa");
 124 
 125     // Set flags in test_xml's attributes for testing flag preservation
 126     attr = xmlHasProp(test_xml, (const xmlChar *) "admin");
 127     if (attr != NULL) {
 128         xml_node_private_t *nodepriv = attr->_private;
 129 
 130         if (nodepriv != NULL) {
 131             pcmk__clear_xml_flags(nodepriv, pcmk__xf_created|pcmk__xf_dirty);
 132         }
 133     }
 134 
 135     attr = xmlHasProp(test_xml, (const xmlChar *) "location");
 136     if (attr != NULL) {
 137         xml_node_private_t *nodepriv = attr->_private;
 138 
 139         if (nodepriv != NULL) {
 140             pcmk__set_xml_flags(nodepriv, pcmk__xf_ignore_attr_pos);
 141         }
 142     }
 143 
 144     pcmk__xe_set_props(reference_xml,
 145                        "admin", "john",
 146                        "dummy", "value",
 147                        "location", "usa",
 148                        NULL);
 149 
 150     assert_order(test_xml, reference_xml);
 151 
 152     pcmk__xml_free(test_xml);
 153     pcmk__xml_free(reference_xml);
 154 }
 155 
 156 static void
 157 need_sort(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159     xmlNode *test_xml = pcmk__xe_create(NULL, "test");
 160     xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
 161 
 162     xmlAttr *attr = NULL;
 163 
 164     crm_xml_add(test_xml, "location", "usa");
 165     crm_xml_add(test_xml, "admin", "john");
 166     crm_xml_add(test_xml, "dummy", "value");
 167 
 168     // Set flags in test_xml's attributes for testing flag preservation
 169     attr = xmlHasProp(test_xml, (const xmlChar *) "location");
 170     if (attr != NULL) {
 171         xml_node_private_t *nodepriv = attr->_private;
 172 
 173         if (nodepriv != NULL) {
 174             pcmk__set_xml_flags(nodepriv, pcmk__xf_ignore_attr_pos);
 175         }
 176     }
 177 
 178     attr = xmlHasProp(test_xml, (const xmlChar *) "admin");
 179     if (attr != NULL) {
 180         xml_node_private_t *nodepriv = attr->_private;
 181 
 182         if (nodepriv != NULL) {
 183             pcmk__clear_xml_flags(nodepriv, pcmk__xf_created|pcmk__xf_dirty);
 184         }
 185     }
 186 
 187     pcmk__xe_set_props(reference_xml,
 188                        "admin", "john",
 189                        "dummy", "value",
 190                        "location", "usa",
 191                        NULL);
 192 
 193     assert_order(test_xml, reference_xml);
 194 
 195     pcmk__xml_free(test_xml);
 196     pcmk__xml_free(reference_xml);
 197 }
 198 
 199 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 200                 cmocka_unit_test(null_arg),
 201                 cmocka_unit_test(nothing_to_sort),
 202                 cmocka_unit_test(already_sorted),
 203                 cmocka_unit_test(need_sort))

/* [previous][next][first][last][top][bottom][index][help] */