pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdarg.h>
13#include <stddef.h>
14#include <stdint.h>
15#include <setjmp.h>
16#include <cmocka.h>
17
18#include <float.h> // DBL_MAX, etc.
19#include <math.h> // fabs()
20
21// Ensure plenty of characters for %f display
22#define LOCAL_BUF_SIZE 2 * DBL_MAX_10_EXP
23
24/*
25 * assert_float_equal doesn't exist for older versions of cmocka installed on some
26 * of our builders, so define it in terms of regular assert() here in that case.
27 */
28#if HAVE_DECL_ASSERT_FLOAT_EQUAL == 0
29#define assert_float_equal(a, b, epsilon) assert_true(fabs((a) - (b)) < (epsilon))
30#endif
31
32static void
33empty_input_string(void **state)
34{
35 double result;
36
37 // Without default_text
38 assert_int_equal(pcmk__scan_double(NULL, &result, NULL, NULL), EINVAL);
40
41 assert_int_equal(pcmk__scan_double("", &result, NULL, NULL), EINVAL);
43
44 // With default_text
45 assert_int_equal(pcmk__scan_double(NULL, &result, "2.0", NULL), pcmk_rc_ok);
46 assert_float_equal(result, 2.0, DBL_EPSILON);
47
48 assert_int_equal(pcmk__scan_double("", &result, "2.0", NULL), EINVAL);
50}
51
52static void
53bad_input_string(void **state)
54{
55 double result;
56
57 // Without default text
58 assert_int_equal(pcmk__scan_double("asdf", &result, NULL, NULL), EINVAL);
60
61 assert_int_equal(pcmk__scan_double("as2.0", &result, NULL, NULL), EINVAL);
63
64 // With default text (not used)
65 assert_int_equal(pcmk__scan_double("asdf", &result, "2.0", NULL), EINVAL);
67
68 assert_int_equal(pcmk__scan_double("as2.0", &result, "2.0", NULL), EINVAL);
70}
71
72static void
73trailing_chars(void **state)
74{
75 double result;
76 char *end_text;
77
78 assert_int_equal(pcmk__scan_double("2.0asdf", &result, NULL, &end_text), pcmk_rc_ok);
79 assert_float_equal(result, 2.0, DBL_EPSILON);
80 assert_string_equal(end_text, "asdf");
81}
82
83static void
84typical_case(void **state)
85{
86 char str[LOCAL_BUF_SIZE];
87 double result;
88
89 assert_int_equal(pcmk__scan_double("0.0", &result, NULL, NULL), pcmk_rc_ok);
90 assert_float_equal(result, 0.0, DBL_EPSILON);
91
92 assert_int_equal(pcmk__scan_double("1.0", &result, NULL, NULL), pcmk_rc_ok);
93 assert_float_equal(result, 1.0, DBL_EPSILON);
94
95 assert_int_equal(pcmk__scan_double("-1.0", &result, NULL, NULL), pcmk_rc_ok);
96 assert_float_equal(result, -1.0, DBL_EPSILON);
97
98 snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
99 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
100 assert_float_equal(result, DBL_MAX, DBL_EPSILON);
101
102 snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX);
103 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
104 assert_float_equal(result, -DBL_MAX, DBL_EPSILON);
105}
106
107static void
108double_overflow(void **state)
109{
110 char str[LOCAL_BUF_SIZE];
111 double result;
112
113 /*
114 * 1e(DBL_MAX_10_EXP + 1) produces an inf value
115 * Can't use assert_float_equal() because (inf - inf) == NaN
116 */
117 snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
118 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
119 assert_true(result > DBL_MAX);
120
121 snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1);
122 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
123 assert_true(result < -DBL_MAX);
124}
125
126static void
127double_underflow(void **state)
128{
129 char str[LOCAL_BUF_SIZE];
130 double result;
131
132 /*
133 * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0
134 * and DBL_MIN)
135 *
136 * C99/C11: result will be **no greater than** DBL_MIN
137 */
138 snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1);
139 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
140 assert_true(result >= 0.0);
141 assert_true(result <= DBL_MIN);
142
143 snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
144 assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
145 assert_true(result <= 0.0);
146 assert_true(result >= -DBL_MIN);
147}
148
149int main(int argc, char **argv)
150{
151 const struct CMUnitTest tests[] = {
152 // Test for input string issues
153 cmocka_unit_test(empty_input_string),
154 cmocka_unit_test(bad_input_string),
155 cmocka_unit_test(trailing_chars),
156
157 // Test for numeric issues
158 cmocka_unit_test(typical_case),
159 cmocka_unit_test(double_overflow),
160 cmocka_unit_test(double_underflow),
161 };
162
163 cmocka_set_message_output(CM_OUTPUT_TAP);
164 return cmocka_run_group_tests(tests, NULL, NULL);
165}
166
#define LOCAL_BUF_SIZE
int main(int argc, char **argv)
#define assert_float_equal(a, b, epsilon)
pcmk__action_result_t result
Definition: pcmk_fence.c:34
@ pcmk_rc_ok
Definition: results.h:146
@ pcmk_rc_underflow
Definition: results.h:114
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
#define PCMK__PARSE_DBL_DEFAULT