pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
pcmk__scan_double_test.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 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 
32 static void
33 empty_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);
39  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
40 
41  assert_int_equal(pcmk__scan_double("", &result, NULL, NULL), EINVAL);
42  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
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);
49  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
50 }
51 
52 static void
53 bad_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);
59  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
60 
61  assert_int_equal(pcmk__scan_double("as2.0", &result, NULL, NULL), EINVAL);
62  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
63 
64  // With default text (not used)
65  assert_int_equal(pcmk__scan_double("asdf", &result, "2.0", NULL), EINVAL);
66  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
67 
68  assert_int_equal(pcmk__scan_double("as2.0", &result, "2.0", NULL), EINVAL);
69  assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON);
70 }
71 
72 static void
73 trailing_chars(void **state)
74 {
75  double result;
76 
77  assert_int_equal(pcmk__scan_double("2.0asdf", &result, NULL, NULL), pcmk_rc_ok);
78  assert_float_equal(result, 2.0, DBL_EPSILON);
79 }
80 
81 static void
82 typical_case(void **state)
83 {
84  char str[LOCAL_BUF_SIZE];
85  double result;
86 
87  assert_int_equal(pcmk__scan_double("0.0", &result, NULL, NULL), pcmk_rc_ok);
88  assert_float_equal(result, 0.0, DBL_EPSILON);
89 
90  assert_int_equal(pcmk__scan_double("1.0", &result, NULL, NULL), pcmk_rc_ok);
91  assert_float_equal(result, 1.0, DBL_EPSILON);
92 
93  assert_int_equal(pcmk__scan_double("-1.0", &result, NULL, NULL), pcmk_rc_ok);
94  assert_float_equal(result, -1.0, DBL_EPSILON);
95 
96  snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
97  assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
98  assert_float_equal(result, DBL_MAX, 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 
105 static void
106 double_overflow(void **state)
107 {
108  char str[LOCAL_BUF_SIZE];
109  double result;
110 
111  /*
112  * 1e(DBL_MAX_10_EXP + 1) produces an inf value
113  * Can't use assert_float_equal() because (inf - inf) == NaN
114  */
115  snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
116  assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
117  assert_true(result > DBL_MAX);
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 
124 static void
125 double_underflow(void **state)
126 {
127  char str[LOCAL_BUF_SIZE];
128  double result;
129 
130  /*
131  * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0
132  * and DBL_MIN)
133  *
134  * C99/C11: result will be **no greater than** DBL_MIN
135  */
136  snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1);
137  assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
138  assert_true(result >= 0.0);
139  assert_true(result <= DBL_MIN);
140 
141  snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
142  assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
143  assert_true(result <= 0.0);
144  assert_true(result >= -DBL_MIN);
145 }
146 
147 int main(int argc, char **argv)
148 {
149  const struct CMUnitTest tests[] = {
150  // Test for input string issues
151  cmocka_unit_test(empty_input_string),
152  cmocka_unit_test(bad_input_string),
153  cmocka_unit_test(trailing_chars),
154 
155  // Test for numeric issues
156  cmocka_unit_test(typical_case),
157  cmocka_unit_test(double_overflow),
158  cmocka_unit_test(double_underflow),
159  };
160 
161  cmocka_set_message_output(CM_OUTPUT_TAP);
162  return cmocka_run_group_tests(tests, NULL, NULL);
163 }
164 
#define assert_float_equal(a, b, epsilon)
#define PCMK__PARSE_DBL_DEFAULT
int main(int argc, char **argv)
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
#define LOCAL_BUF_SIZE