pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk__scan_double_test.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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
13
14#include <float.h> // DBL_MAX, etc.
15#include <math.h> // fabs()
16
17// Ensure plenty of characters for %f display
18#define LOCAL_BUF_SIZE 2 * DBL_MAX_10_EXP
19
20/*
21 * assert_float_equal doesn't exist for older versions of cmocka installed on some
22 * of our builders, so define it in terms of regular assert() here in that case.
23 */
24#if HAVE_DECL_ASSERT_FLOAT_EQUAL == 0
25#define assert_float_equal(a, b, epsilon) assert_true(fabs((a) - (b)) < (epsilon))
26#endif
27
28static void
29empty_input_string(void **state)
30{
31 double result;
32
33 // Without default_text
34 assert_int_equal(pcmk__scan_double(NULL, &result, NULL, NULL), EINVAL);
36
37 assert_int_equal(pcmk__scan_double("", &result, NULL, NULL), EINVAL);
39
40 // With default_text
41 assert_int_equal(pcmk__scan_double(NULL, &result, "2.0", NULL), pcmk_rc_ok);
42 assert_float_equal(result, 2.0, DBL_EPSILON);
43
44 assert_int_equal(pcmk__scan_double("", &result, "2.0", NULL), EINVAL);
46}
47
48static void
49bad_input_string(void **state)
50{
51 double result;
52
53 // Without default text
54 assert_int_equal(pcmk__scan_double("asdf", &result, NULL, NULL), EINVAL);
56
57 assert_int_equal(pcmk__scan_double("as2.0", &result, NULL, NULL), EINVAL);
59
60 // With default text (not used)
61 assert_int_equal(pcmk__scan_double("asdf", &result, "2.0", NULL), EINVAL);
63
64 assert_int_equal(pcmk__scan_double("as2.0", &result, "2.0", NULL), EINVAL);
66}
67
68static void
69trailing_chars(void **state)
70{
71 double result;
72 char *end_text;
73
74 assert_int_equal(pcmk__scan_double("2.0asdf", &result, NULL, &end_text), pcmk_rc_ok);
75 assert_float_equal(result, 2.0, DBL_EPSILON);
76 assert_string_equal(end_text, "asdf");
77}
78
79static void
80no_result_variable(void **state)
81{
82 pcmk__assert_asserts(pcmk__scan_double("asdf", NULL, NULL, NULL));
83}
84
85static void
86typical_case(void **state)
87{
88 char str[LOCAL_BUF_SIZE];
89 double result;
90
91 assert_int_equal(pcmk__scan_double("0.0", &result, NULL, NULL), pcmk_rc_ok);
92 assert_float_equal(result, 0.0, DBL_EPSILON);
93
94 assert_int_equal(pcmk__scan_double("1.0", &result, NULL, NULL), pcmk_rc_ok);
95 assert_float_equal(result, 1.0, DBL_EPSILON);
96
97 assert_int_equal(pcmk__scan_double("-1.0", &result, NULL, NULL), pcmk_rc_ok);
98 assert_float_equal(result, -1.0, DBL_EPSILON);
99
100 snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
101 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
102 assert_float_equal(result, DBL_MAX, DBL_EPSILON);
103
104 snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX);
105 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
106 assert_float_equal(result, -DBL_MAX, DBL_EPSILON);
107}
108
109static void
110double_overflow(void **state)
111{
112 char str[LOCAL_BUF_SIZE];
113 double result;
114
115 /*
116 * 1e(DBL_MAX_10_EXP + 1) produces an inf value
117 * Can't use assert_float_equal() because (inf - inf) == NaN
118 */
119 snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
120 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
121 assert_true(result > DBL_MAX);
122
123 snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1);
124 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
125 assert_true(result < -DBL_MAX);
126}
127
128static void
129double_underflow(void **state)
130{
131 char str[LOCAL_BUF_SIZE];
132 double result;
133
134 /*
135 * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0
136 * and DBL_MIN)
137 *
138 * C99/C11: result will be **no greater than** DBL_MIN
139 */
140 snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1);
141 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
142 assert_true(result >= 0.0);
143 assert_true(result <= DBL_MIN);
144
145 snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
146 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
147 assert_true(result <= 0.0);
148 assert_true(result >= -DBL_MIN);
149}
150
151PCMK__UNIT_TEST(NULL, NULL,
152 cmocka_unit_test(empty_input_string),
153 cmocka_unit_test(bad_input_string),
154 cmocka_unit_test(trailing_chars),
155 cmocka_unit_test(no_result_variable),
156 cmocka_unit_test(typical_case),
157 cmocka_unit_test(double_overflow),
158 cmocka_unit_test(double_underflow))
#define LOCAL_BUF_SIZE
#define assert_float_equal(a, b, epsilon)
pcmk__action_result_t result
Definition pcmk_fence.c:37
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_underflow
Definition results.h:126
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition strings.c:191
#define PCMK__PARSE_DBL_DEFAULT
#define pcmk__assert_asserts(stmt)
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)