pacemaker 2.1.1-77db578727
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-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
26static void
27empty_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), ==,
41 ASSERT_DBL_EQ(result, 2.0);
42
43 g_assert_cmpint(pcmk__scan_double("", &result, "2.0", NULL), ==, EINVAL);
45}
46
47static void
48bad_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
70static void
71trailing_chars(void)
72{
73 double result;
74
75 g_assert_cmpint(pcmk__scan_double("2.0asdf", &result, NULL, NULL), ==,
77 ASSERT_DBL_EQ(result, 2.0);
78}
79
80static void
81typical_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), ==,
88 ASSERT_DBL_EQ(result, 0.0);
89
90 g_assert_cmpint(pcmk__scan_double("1.0", &result, NULL, NULL), ==,
92 ASSERT_DBL_EQ(result, 1.0);
93
94 g_assert_cmpint(pcmk__scan_double("-1.0", &result, NULL, NULL), ==,
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
109static void
110double_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
128static void
129double_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
153int 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 LOCAL_BUF_SIZE
int main(int argc, char **argv)
#define ASSERT_DBL_EQ(d1, d2)
@ pcmk_rc_ok
Definition results.h:142
@ pcmk_rc_underflow
Definition results.h:110
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