diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index 75147ec2c9..c2d01abcf3 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -1,65 +1,29 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PCMK__CRM_COMMON_RULES_INTERNAL__H #define PCMK__CRM_COMMON_RULES_INTERNAL__H #include // regmatch_t #include // xmlNode #include // enum expression_type, etc. #include // crm_time_t -// How node attribute values may be compared in rules -enum pcmk__comparison { - pcmk__comparison_unknown, - pcmk__comparison_defined, - pcmk__comparison_undefined, - pcmk__comparison_eq, - pcmk__comparison_ne, - pcmk__comparison_lt, - pcmk__comparison_lte, - pcmk__comparison_gt, - pcmk__comparison_gte, -}; - -// How node attribute values may be parsed in rules -enum pcmk__type { - pcmk__type_unknown, - pcmk__type_string, - pcmk__type_integer, - pcmk__type_number, - pcmk__type_version, -}; - -// Where to obtain reference value for a node attribute comparison -enum pcmk__reference_source { - pcmk__source_unknown, - pcmk__source_literal, - pcmk__source_instance_attrs, - pcmk__source_meta_attrs, -}; - enum expression_type pcmk__expression_type(const xmlNode *expr); -enum pcmk__comparison pcmk__parse_comparison(const char *op); -enum pcmk__type pcmk__parse_type(const char *type, enum pcmk__comparison op, - const char *value1, const char *value2); -enum pcmk__reference_source pcmk__parse_source(const char *source); -int pcmk__cmp_by_type(const char *value1, const char *value2, - enum pcmk__type type); char *pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches); int pcmk__evaluate_date_expression(const xmlNode *date_expression, const crm_time_t *now, crm_time_t *next_change); int pcmk__evaluate_attr_expression(const xmlNode *expression, const pcmk_rule_input_t *rule_input); #endif // PCMK__CRM_COMMON_RULES_INTERNAL__H diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index db52662496..4849f2f06c 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -1,354 +1,398 @@ /* * Copyright 2018-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef CRMCOMMON_PRIVATE__H # define CRMCOMMON_PRIVATE__H /* This header is for the sole use of libcrmcommon, so that functions can be * declared with G_GNUC_INTERNAL for efficiency. */ #include // uint8_t, uint32_t #include // bool #include // size_t #include // GList #include // xmlNode, xmlAttr #include // struct qb_ipc_response_header // Decent chunk size for processing large amounts of data #define PCMK__BUFFER_SIZE 4096 #if defined(PCMK__UNIT_TESTING) #undef G_GNUC_INTERNAL #define G_GNUC_INTERNAL #endif /* When deleting portions of an XML tree, we keep a record so we can know later * (e.g. when checking differences) that something was deleted. */ typedef struct pcmk__deleted_xml_s { char *path; int position; } pcmk__deleted_xml_t; typedef struct xml_node_private_s { uint32_t check; uint32_t flags; } xml_node_private_t; typedef struct xml_doc_private_s { uint32_t check; uint32_t flags; char *user; GList *acls; GList *deleted_objs; // List of pcmk__deleted_xml_t } xml_doc_private_t; //! libxml2 supports only XML version 1.0, at least as of libxml2-2.12.5 #define PCMK__XML_VERSION ((pcmkXmlStr) "1.0") #define pcmk__set_xml_flags(xml_priv, flags_to_set) do { \ (xml_priv)->flags = pcmk__set_flags_as(__func__, __LINE__, \ LOG_NEVER, "XML", "XML node", (xml_priv)->flags, \ (flags_to_set), #flags_to_set); \ } while (0) #define pcmk__clear_xml_flags(xml_priv, flags_to_clear) do { \ (xml_priv)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_NEVER, "XML", "XML node", (xml_priv)->flags, \ (flags_to_clear), #flags_to_clear); \ } while (0) G_GNUC_INTERNAL bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy); G_GNUC_INTERNAL void pcmk__mark_xml_created(xmlNode *xml); G_GNUC_INTERNAL int pcmk__xml_position(const xmlNode *xml, enum xml_private_flags ignore_if_set); G_GNUC_INTERNAL xmlNode *pcmk__xml_match(const xmlNode *haystack, const xmlNode *needle, bool exact); G_GNUC_INTERNAL void pcmk__xml_update(xmlNode *parent, xmlNode *target, xmlNode *update, bool as_diff); G_GNUC_INTERNAL xmlNode *pcmk__xc_match(const xmlNode *root, const xmlNode *search_comment, bool exact); G_GNUC_INTERNAL void pcmk__xc_update(xmlNode *parent, xmlNode *target, xmlNode *update); G_GNUC_INTERNAL void pcmk__free_acls(GList *acls); G_GNUC_INTERNAL void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user); G_GNUC_INTERNAL bool pcmk__is_user_in_group(const char *user, const char *group); G_GNUC_INTERNAL void pcmk__apply_acl(xmlNode *xml); G_GNUC_INTERNAL void pcmk__apply_creation_acl(xmlNode *xml, bool check_top); G_GNUC_INTERNAL void pcmk__mark_xml_attr_dirty(xmlAttr *a); G_GNUC_INTERNAL bool pcmk__xa_filterable(const char *name); G_GNUC_INTERNAL void pcmk__log_xmllib_err(void *ctx, const char *fmt, ...) G_GNUC_PRINTF(2, 3); G_GNUC_INTERNAL void pcmk__mark_xml_node_dirty(xmlNode *xml); G_GNUC_INTERNAL bool pcmk__marked_as_deleted(xmlAttrPtr a, void *user_data); G_GNUC_INTERNAL void pcmk__dump_xml_attr(const xmlAttr *attr, GString *buffer); /* * Date/times */ // For use with pcmk__add_time_from_xml() enum pcmk__time_component { pcmk__time_unknown, pcmk__time_years, pcmk__time_months, pcmk__time_weeks, pcmk__time_days, pcmk__time_hours, pcmk__time_minutes, pcmk__time_seconds, }; G_GNUC_INTERNAL const char *pcmk__time_component_attr(enum pcmk__time_component component); G_GNUC_INTERNAL int pcmk__add_time_from_xml(crm_time_t *t, enum pcmk__time_component component, const xmlNode *xml); G_GNUC_INTERNAL void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source); /* * IPC */ #define PCMK__IPC_VERSION 1 #define PCMK__CONTROLD_API_MAJOR "1" #define PCMK__CONTROLD_API_MINOR "0" // IPC behavior that varies by daemon typedef struct pcmk__ipc_methods_s { /*! * \internal * \brief Allocate any private data needed by daemon IPC * * \param[in,out] api IPC API connection * * \return Standard Pacemaker return code */ int (*new_data)(pcmk_ipc_api_t *api); /*! * \internal * \brief Free any private data used by daemon IPC * * \param[in,out] api_data Data allocated by new_data() method */ void (*free_data)(void *api_data); /*! * \internal * \brief Perform daemon-specific handling after successful connection * * Some daemons require clients to register before sending any other * commands. The controller requires a CRM_OP_HELLO (with no reply), and * the CIB manager, executor, and fencer require a CRM_OP_REGISTER (with a * reply). Ideally this would be consistent across all daemons, but for now * this allows each to do its own authorization. * * \param[in,out] api IPC API connection * * \return Standard Pacemaker return code */ int (*post_connect)(pcmk_ipc_api_t *api); /*! * \internal * \brief Check whether an IPC request results in a reply * * \param[in,out] api IPC API connection * \param[in] request IPC request XML * * \return true if request would result in an IPC reply, false otherwise */ bool (*reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request); /*! * \internal * \brief Perform daemon-specific handling of an IPC message * * \param[in,out] api IPC API connection * \param[in,out] msg Message read from IPC connection * * \return true if more IPC reply messages should be expected */ bool (*dispatch)(pcmk_ipc_api_t *api, xmlNode *msg); /*! * \internal * \brief Perform daemon-specific handling of an IPC disconnect * * \param[in,out] api IPC API connection */ void (*post_disconnect)(pcmk_ipc_api_t *api); } pcmk__ipc_methods_t; // Implementation of pcmk_ipc_api_t struct pcmk_ipc_api_s { enum pcmk_ipc_server server; // Daemon this IPC API instance is for enum pcmk_ipc_dispatch dispatch_type; // How replies should be dispatched size_t ipc_size_max; // maximum IPC buffer size crm_ipc_t *ipc; // IPC connection mainloop_io_t *mainloop_io; // If using mainloop, I/O source for IPC bool free_on_disconnect; // Whether disconnect should free object pcmk_ipc_callback_t cb; // Caller-registered callback (if any) void *user_data; // Caller-registered data (if any) void *api_data; // For daemon-specific use pcmk__ipc_methods_t *cmds; // Behavior that varies by daemon }; typedef struct pcmk__ipc_header_s { struct qb_ipc_response_header qb; uint32_t size_uncompressed; uint32_t size_compressed; uint32_t flags; uint8_t version; } pcmk__ipc_header_t; G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request); G_GNUC_INTERNAL void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data); G_GNUC_INTERNAL unsigned int pcmk__ipc_buffer_size(unsigned int max); G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header); G_GNUC_INTERNAL pcmk__ipc_methods_t *pcmk__attrd_api_methods(void); G_GNUC_INTERNAL pcmk__ipc_methods_t *pcmk__controld_api_methods(void); G_GNUC_INTERNAL pcmk__ipc_methods_t *pcmk__pacemakerd_api_methods(void); G_GNUC_INTERNAL pcmk__ipc_methods_t *pcmk__schedulerd_api_methods(void); /* * Logging */ //! XML is newly created #define PCMK__XML_PREFIX_CREATED "++" //! XML has been deleted #define PCMK__XML_PREFIX_DELETED "--" //! XML has been modified #define PCMK__XML_PREFIX_MODIFIED "+ " //! XML has been moved #define PCMK__XML_PREFIX_MOVED "+~" /* * Output */ 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_option_messages(pcmk__output_t *out); G_GNUC_INTERNAL void pcmk__register_patchset_messages(pcmk__output_t *out); G_GNUC_INTERNAL bool pcmk__output_text_get_fancy(pcmk__output_t *out); /* * Rules */ +// How node attribute values may be compared in rules +enum pcmk__comparison { + pcmk__comparison_unknown, + pcmk__comparison_defined, + pcmk__comparison_undefined, + pcmk__comparison_eq, + pcmk__comparison_ne, + pcmk__comparison_lt, + pcmk__comparison_lte, + pcmk__comparison_gt, + pcmk__comparison_gte, +}; + +// How node attribute values may be parsed in rules +enum pcmk__type { + pcmk__type_unknown, + pcmk__type_string, + pcmk__type_integer, + pcmk__type_number, + pcmk__type_version, +}; + +// Where to obtain reference value for a node attribute comparison +enum pcmk__reference_source { + pcmk__source_unknown, + pcmk__source_literal, + pcmk__source_instance_attrs, + pcmk__source_meta_attrs, +}; + +G_GNUC_INTERNAL +enum pcmk__comparison pcmk__parse_comparison(const char *op); + +G_GNUC_INTERNAL +enum pcmk__type pcmk__parse_type(const char *type, enum pcmk__comparison op, + const char *value1, const char *value2); + +G_GNUC_INTERNAL +enum pcmk__reference_source pcmk__parse_source(const char *source); + +G_GNUC_INTERNAL +int pcmk__cmp_by_type(const char *value1, const char *value2, + enum pcmk__type type); + G_GNUC_INTERNAL int pcmk__unpack_duration(const xmlNode *duration, const crm_time_t *start, crm_time_t **end); G_GNUC_INTERNAL int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now); /* * Utils */ #define PCMK__PW_BUFFER_LEN 500 /* * Schemas */ typedef struct { unsigned char v[2]; } pcmk__schema_version_t; enum pcmk__schema_validator { pcmk__schema_validator_none, pcmk__schema_validator_rng }; typedef struct { char *name; char *transform; void *cache; enum pcmk__schema_validator validator; pcmk__schema_version_t version; char *transform_enter; bool transform_onleave; } pcmk__schema_t; G_GNUC_INTERNAL int pcmk__find_x_0_schema_index(GList *schemas); #endif // CRMCOMMON_PRIVATE__H diff --git a/lib/common/tests/rules/pcmk__cmp_by_type_test.c b/lib/common/tests/rules/pcmk__cmp_by_type_test.c index d4bd98454f..cf468f1fa5 100644 --- a/lib/common/tests/rules/pcmk__cmp_by_type_test.c +++ b/lib/common/tests/rules/pcmk__cmp_by_type_test.c @@ -1,101 +1,102 @@ /* * 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 // INT_MIN, INT_MAX #include // crm_strdup_printf() #include #include +#include "crmcommon_private.h" static void null_compares_lesser(void **state) { assert_int_equal(pcmk__cmp_by_type(NULL, NULL, pcmk__type_string), 0); assert_true(pcmk__cmp_by_type("0", NULL, pcmk__type_integer) > 0); assert_true(pcmk__cmp_by_type(NULL, "0", pcmk__type_number) < 0); } static void invalid_compares_equal(void **state) { assert_int_equal(pcmk__cmp_by_type("0", "1", pcmk__type_unknown), 0); assert_int_equal(pcmk__cmp_by_type("hi", "bye", pcmk__type_unknown), 0); assert_int_equal(pcmk__cmp_by_type("-1.0", "2.0", pcmk__type_unknown), 0); } static void compare_string_type(void **state) { assert_int_equal(pcmk__cmp_by_type("bye", "bye", pcmk__type_string), 0); assert_int_equal(pcmk__cmp_by_type("bye", "BYE", pcmk__type_string), 0); assert_true(pcmk__cmp_by_type("bye", "hello", pcmk__type_string) < 0); assert_true(pcmk__cmp_by_type("bye", "HELLO", pcmk__type_string) < 0); assert_true(pcmk__cmp_by_type("bye", "boo", pcmk__type_string) > 0); assert_true(pcmk__cmp_by_type("bye", "Boo", pcmk__type_string) > 0); } static void compare_integer_type(void **state) { char *int_min = crm_strdup_printf("%d", INT_MIN); char *int_max = crm_strdup_printf("%d", INT_MAX); assert_int_equal(pcmk__cmp_by_type("0", "0", pcmk__type_integer), 0); assert_true(pcmk__cmp_by_type("0", "1", pcmk__type_integer) < 0); assert_true(pcmk__cmp_by_type("1", "0", pcmk__type_integer) > 0); assert_true(pcmk__cmp_by_type("3999", "399", pcmk__type_integer) > 0); assert_true(pcmk__cmp_by_type(int_min, int_max, pcmk__type_integer) < 0); assert_true(pcmk__cmp_by_type(int_max, int_min, pcmk__type_integer) > 0); free(int_min); free(int_max); // Non-integers compare as strings assert_int_equal(pcmk__cmp_by_type("0", "x", pcmk__type_integer), pcmk__cmp_by_type("0", "x", pcmk__type_string)); assert_int_equal(pcmk__cmp_by_type("x", "0", pcmk__type_integer), pcmk__cmp_by_type("x", "0", pcmk__type_string)); assert_int_equal(pcmk__cmp_by_type("x", "X", pcmk__type_integer), pcmk__cmp_by_type("x", "X", pcmk__type_string)); } static void compare_number_type(void **state) { assert_int_equal(pcmk__cmp_by_type("0", "0.0", pcmk__type_number), 0); assert_true(pcmk__cmp_by_type("0.345", "0.5", pcmk__type_number) < 0); assert_true(pcmk__cmp_by_type("5", "3.1", pcmk__type_number) > 0); assert_true(pcmk__cmp_by_type("3999", "399", pcmk__type_number) > 0); // Non-numbers compare as strings assert_int_equal(pcmk__cmp_by_type("0.0", "x", pcmk__type_number), pcmk__cmp_by_type("0.0", "x", pcmk__type_string)); assert_int_equal(pcmk__cmp_by_type("x", "0.0", pcmk__type_number), pcmk__cmp_by_type("x", "0.0", pcmk__type_string)); assert_int_equal(pcmk__cmp_by_type("x", "X", pcmk__type_number), pcmk__cmp_by_type("x", "X", pcmk__type_string)); } static void compare_version_type(void **state) { assert_int_equal(pcmk__cmp_by_type("1.0", "1.0", pcmk__type_version), 0); assert_true(pcmk__cmp_by_type("1.0.0", "1.0.1", pcmk__type_version) < 0); assert_true(pcmk__cmp_by_type("5.0", "3.1.15", pcmk__type_version) > 0); assert_true(pcmk__cmp_by_type("3999", "399", pcmk__type_version) > 0); } PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(null_compares_lesser), cmocka_unit_test(invalid_compares_equal), cmocka_unit_test(compare_string_type), cmocka_unit_test(compare_integer_type), cmocka_unit_test(compare_number_type), cmocka_unit_test(compare_version_type)) diff --git a/lib/common/tests/rules/pcmk__parse_comparison_test.c b/lib/common/tests/rules/pcmk__parse_comparison_test.c index 2a9426657b..a99559620a 100644 --- a/lib/common/tests/rules/pcmk__parse_comparison_test.c +++ b/lib/common/tests/rules/pcmk__parse_comparison_test.c @@ -1,71 +1,72 @@ /* * 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 +#include "crmcommon_private.h" static void null_unknown(void **state) { assert_int_equal(pcmk__parse_comparison(NULL), pcmk__comparison_unknown); } static void invalid(void **state) { assert_int_equal(pcmk__parse_comparison("nope"), pcmk__comparison_unknown); } static void valid(void **state) { assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_DEFINED), pcmk__comparison_defined); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_NOT_DEFINED), pcmk__comparison_undefined); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_EQ), pcmk__comparison_eq); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_NE), pcmk__comparison_ne); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_LT), pcmk__comparison_lt); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_LTE), pcmk__comparison_lte); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_GT), pcmk__comparison_gt); assert_int_equal(pcmk__parse_comparison(PCMK_VALUE_GTE), pcmk__comparison_gte); } static void case_insensitive(void **state) { assert_int_equal(pcmk__parse_comparison("DEFINED"), pcmk__comparison_defined); assert_int_equal(pcmk__parse_comparison("Not_Defined"), pcmk__comparison_undefined); } PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(null_unknown), cmocka_unit_test(invalid), cmocka_unit_test(valid), cmocka_unit_test(case_insensitive)) diff --git a/lib/common/tests/rules/pcmk__parse_source_test.c b/lib/common/tests/rules/pcmk__parse_source_test.c index 72c65bf8f5..9cf9b3253b 100644 --- a/lib/common/tests/rules/pcmk__parse_source_test.c +++ b/lib/common/tests/rules/pcmk__parse_source_test.c @@ -1,61 +1,62 @@ /* * 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 +#include "crmcommon_private.h" static void default_literal(void **state) { assert_int_equal(pcmk__parse_source(NULL), pcmk__source_literal); } static void invalid(void **state) { assert_int_equal(pcmk__parse_source(""), pcmk__source_unknown); assert_int_equal(pcmk__parse_source(" "), pcmk__source_unknown); assert_int_equal(pcmk__parse_source("params"), pcmk__source_unknown); } static void valid(void **state) { assert_int_equal(pcmk__parse_source(PCMK_VALUE_LITERAL), pcmk__source_literal); assert_int_equal(pcmk__parse_source(PCMK_VALUE_PARAM), pcmk__source_instance_attrs); assert_int_equal(pcmk__parse_source(PCMK_VALUE_META), pcmk__source_meta_attrs); } static void case_insensitive(void **state) { assert_int_equal(pcmk__parse_source("LITERAL"), pcmk__source_literal); assert_int_equal(pcmk__parse_source("Param"), pcmk__source_instance_attrs); assert_int_equal(pcmk__parse_source("MeTa"), pcmk__source_meta_attrs); } PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(default_literal), cmocka_unit_test(invalid), cmocka_unit_test(valid), cmocka_unit_test(case_insensitive)) diff --git a/lib/common/tests/rules/pcmk__parse_type_test.c b/lib/common/tests/rules/pcmk__parse_type_test.c index f33ab214fa..96f02c87e4 100644 --- a/lib/common/tests/rules/pcmk__parse_type_test.c +++ b/lib/common/tests/rules/pcmk__parse_type_test.c @@ -1,126 +1,127 @@ /* * 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 +#include "crmcommon_private.h" static void invalid(void **state) { assert_int_equal(pcmk__parse_type("nope", pcmk__comparison_unknown, NULL, NULL), pcmk__type_unknown); } static void valid(void **state) { assert_int_equal(pcmk__parse_type(PCMK_VALUE_STRING, pcmk__comparison_unknown, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type(PCMK_VALUE_INTEGER, pcmk__comparison_unknown, NULL, NULL), pcmk__type_integer); assert_int_equal(pcmk__parse_type(PCMK_VALUE_NUMBER, pcmk__comparison_unknown, NULL, NULL), pcmk__type_number); assert_int_equal(pcmk__parse_type(PCMK_VALUE_VERSION, pcmk__comparison_unknown, NULL, NULL), pcmk__type_version); } static void case_insensitive(void **state) { assert_int_equal(pcmk__parse_type("STRING", pcmk__comparison_unknown, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type("Integer", pcmk__comparison_unknown, NULL, NULL), pcmk__type_integer); } static void default_number(void **state) { assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_lt, "1.0", "2.5"), pcmk__type_number); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_lte, "1.", "2"), pcmk__type_number); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gt, "1", ".5"), pcmk__type_number); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gte, "1.0", "2"), pcmk__type_number); } static void default_integer(void **state) { assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_lt, "1", "2"), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_lte, "1", "2"), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gt, "1", "2"), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gte, "1", "2"), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gte, NULL, NULL), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gte, "1", NULL), pcmk__type_integer); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_gte, NULL, "2.5"), pcmk__type_number); } static void default_string(void **state) { assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_unknown, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_defined, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_undefined, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_eq, NULL, NULL), pcmk__type_string); assert_int_equal(pcmk__parse_type(NULL, pcmk__comparison_ne, NULL, NULL), pcmk__type_string); } PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(invalid), cmocka_unit_test(valid), cmocka_unit_test(case_insensitive), cmocka_unit_test(default_number), cmocka_unit_test(default_integer), cmocka_unit_test(default_string))