pacemaker  2.1.8-3980678f03
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 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 
28 static void
29 empty_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 
48 static void
49 bad_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 
68 static void
69 trailing_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 
79 static void
80 no_result_variable(void **state)
81 {
82  pcmk__assert_asserts(pcmk__scan_double("asdf", NULL, NULL, NULL));
83 }
84 
85 static void
86 typical_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 
109 static void
110 double_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 
128 static void
129 double_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 
151 PCMK__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 assert_float_equal(a, b, epsilon)
#define PCMK__PARSE_DBL_DEFAULT
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
#define pcmk__assert_asserts(stmt)
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define LOCAL_BUF_SIZE