pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <float.h> // DBL_MAX, etc.
13 #include <math.h> // fabs()
14 #include <glib.h>
15 
16 // Ensure plenty of characters for %f display
17 #define LOCAL_BUF_SIZE 2 * DBL_MAX_10_EXP
18 
19 /*
20  * Avoids compiler warnings for floating-point equality checks.
21  * Use for comparing numbers (e.g., 1.0 == 1.0), not expression values.
22  */
23 #define ASSERT_DBL_EQ(d1, d2) g_assert_cmpfloat(fabs(d1 - d2), \
24  <, DBL_EPSILON);
25 
26 static void
27 empty_input_string(void)
28 {
29  double result;
30 
31  // Without default_text
32  g_assert_cmpint(pcmk__scan_double(NULL, &result, NULL, NULL), ==, EINVAL);
34 
35  g_assert_cmpint(pcmk__scan_double("", &result, NULL, NULL), ==, EINVAL);
37 
38  // With default_text
39  g_assert_cmpint(pcmk__scan_double(NULL, &result, "2.0", NULL), ==,
40  pcmk_rc_ok);
41  ASSERT_DBL_EQ(result, 2.0);
42 
43  g_assert_cmpint(pcmk__scan_double("", &result, "2.0", NULL), ==, EINVAL);
45 }
46 
47 static void
48 bad_input_string(void)
49 {
50  double result;
51 
52  // Without default text
53  g_assert_cmpint(pcmk__scan_double("asdf", &result, NULL, NULL), ==, EINVAL);
55 
56  g_assert_cmpint(pcmk__scan_double("as2.0", &result, NULL, NULL), ==,
57  EINVAL);
59 
60  // With default text (not used)
61  g_assert_cmpint(pcmk__scan_double("asdf", &result, "2.0", NULL), ==,
62  EINVAL);
64 
65  g_assert_cmpint(pcmk__scan_double("as2.0", &result, "2.0", NULL), ==,
66  EINVAL);
68 }
69 
70 static void
71 trailing_chars(void)
72 {
73  double result;
74 
75  g_assert_cmpint(pcmk__scan_double("2.0asdf", &result, NULL, NULL), ==,
76  pcmk_rc_ok);
77  ASSERT_DBL_EQ(result, 2.0);
78 }
79 
80 static void
81 typical_case(void)
82 {
83  char str[LOCAL_BUF_SIZE];
84  double result;
85 
86  g_assert_cmpint(pcmk__scan_double("0.0", &result, NULL, NULL), ==,
87  pcmk_rc_ok);
88  ASSERT_DBL_EQ(result, 0.0);
89 
90  g_assert_cmpint(pcmk__scan_double("1.0", &result, NULL, NULL), ==,
91  pcmk_rc_ok);
92  ASSERT_DBL_EQ(result, 1.0);
93 
94  g_assert_cmpint(pcmk__scan_double("-1.0", &result, NULL, NULL), ==,
95  pcmk_rc_ok);
96  ASSERT_DBL_EQ(result, -1.0);
97 
98  snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
99  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
100  pcmk_rc_ok);
101  ASSERT_DBL_EQ(result, DBL_MAX);
102 
103  snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX);
104  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
105  pcmk_rc_ok);
106  ASSERT_DBL_EQ(result, -DBL_MAX);
107 }
108 
109 static void
110 double_overflow(void)
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_DBL_EQ() because (inf - inf) == NaN
118  */
119  snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
120  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==, EOVERFLOW);
121  g_assert_cmpfloat(result, >, DBL_MAX);
122 
123  snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1);
124  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==, EOVERFLOW);
125  g_assert_cmpfloat(result, <, -DBL_MAX);
126 }
127 
128 static void
129 double_underflow(void)
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  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
143  g_assert_cmpfloat(result, >=, 0.0);
144  g_assert_cmpfloat(result, <=, DBL_MIN);
145 
146  snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
147  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
149  g_assert_cmpfloat(result, <=, 0.0);
150  g_assert_cmpfloat(result, >=, -DBL_MIN);
151 }
152 
153 int main(int argc, char **argv)
154 {
155  g_test_init(&argc, &argv, NULL);
156 
157  // Test for input string issues
158  g_test_add_func("/common/strings/double/empty_input", empty_input_string);
159  g_test_add_func("/common/strings/double/bad_input", bad_input_string);
160  g_test_add_func("/common/strings/double/trailing_chars", trailing_chars);
161 
162  // Test for numeric issues
163  g_test_add_func("/common/strings/double/typical", typical_case);
164  g_test_add_func("/common/strings/double/overflow", double_overflow);
165  g_test_add_func("/common/strings/double/underflow", double_underflow);
166 
167  return g_test_run();
168 }
169 
#define ASSERT_DBL_EQ(d1, d2)
#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