pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
pcmk__scan_double_test.c
Go to the documentation of this file.
1 #include <float.h> // DBL_MAX, etc.
2 #include <math.h> // fabs()
3 
4 #include <glib.h>
5 
6 #include <crm_internal.h>
7 
8 // Ensure plenty of characters for %f display
9 #define LOCAL_BUF_SIZE 2 * DBL_MAX_10_EXP
10 
11 /*
12  * Avoids compiler warnings for floating-point equality checks.
13  * Use for comparing numbers (e.g., 1.0 == 1.0), not expression values.
14  */
15 #define ASSERT_DBL_EQ(d1, d2) g_assert_cmpfloat(fabs(d1 - d2), \
16  <, DBL_EPSILON);
17 
18 static void
19 empty_input_string(void)
20 {
21  double result;
22 
23  // Without default_text
24  g_assert_cmpint(pcmk__scan_double(NULL, &result, NULL, NULL), ==, EINVAL);
26 
27  g_assert_cmpint(pcmk__scan_double("", &result, NULL, NULL), ==, EINVAL);
29 
30  // With default_text
31  g_assert_cmpint(pcmk__scan_double(NULL, &result, "2.0", NULL), ==,
32  pcmk_rc_ok);
33  ASSERT_DBL_EQ(result, 2.0);
34 
35  g_assert_cmpint(pcmk__scan_double("", &result, "2.0", NULL), ==, EINVAL);
37 }
38 
39 static void
40 bad_input_string(void)
41 {
42  double result;
43 
44  // Without default text
45  g_assert_cmpint(pcmk__scan_double("asdf", &result, NULL, NULL), ==, EINVAL);
47 
48  g_assert_cmpint(pcmk__scan_double("as2.0", &result, NULL, NULL), ==,
49  EINVAL);
51 
52  // With default text (not used)
53  g_assert_cmpint(pcmk__scan_double("asdf", &result, "2.0", NULL), ==,
54  EINVAL);
56 
57  g_assert_cmpint(pcmk__scan_double("as2.0", &result, "2.0", NULL), ==,
58  EINVAL);
60 }
61 
62 static void
63 trailing_chars(void)
64 {
65  double result;
66 
67  g_assert_cmpint(pcmk__scan_double("2.0asdf", &result, NULL, NULL), ==,
68  pcmk_rc_ok);
69  ASSERT_DBL_EQ(result, 2.0);
70 }
71 
72 static void
73 typical_case(void)
74 {
75  char str[LOCAL_BUF_SIZE];
76  double result;
77 
78  g_assert_cmpint(pcmk__scan_double("0.0", &result, NULL, NULL), ==,
79  pcmk_rc_ok);
80  ASSERT_DBL_EQ(result, 0.0);
81 
82  g_assert_cmpint(pcmk__scan_double("1.0", &result, NULL, NULL), ==,
83  pcmk_rc_ok);
84  ASSERT_DBL_EQ(result, 1.0);
85 
86  g_assert_cmpint(pcmk__scan_double("-1.0", &result, NULL, NULL), ==,
87  pcmk_rc_ok);
88  ASSERT_DBL_EQ(result, -1.0);
89 
90  snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
91  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
92  pcmk_rc_ok);
93  ASSERT_DBL_EQ(result, DBL_MAX);
94 
95  snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX);
96  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
97  pcmk_rc_ok);
98  ASSERT_DBL_EQ(result, -DBL_MAX);
99 }
100 
101 static void
102 double_overflow(void)
103 {
104  char str[LOCAL_BUF_SIZE];
105  double result;
106 
107  /*
108  * 1e(DBL_MAX_10_EXP + 1) produces an inf value
109  * Can't use ASSERT_DBL_EQ() because (inf - inf) == NaN
110  */
111  snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
112  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==, EOVERFLOW);
113  g_assert_cmpfloat(result, >, DBL_MAX);
114 
115  snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1);
116  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==, EOVERFLOW);
117  g_assert_cmpfloat(result, <, -DBL_MAX);
118 }
119 
120 static void
121 double_underflow(void)
122 {
123  char str[LOCAL_BUF_SIZE];
124  double result;
125 
126  /*
127  * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0
128  * and DBL_MIN)
129  *
130  * C99/C11: result will be **no greater than** DBL_MIN
131  */
132  snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1);
133  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
135  g_assert_cmpfloat(result, >=, 0.0);
136  g_assert_cmpfloat(result, <=, DBL_MIN);
137 
138  snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
139  g_assert_cmpint(pcmk__scan_double(str, &result, NULL, NULL), ==,
141  g_assert_cmpfloat(result, <=, 0.0);
142  g_assert_cmpfloat(result, >=, -DBL_MIN);
143 }
144 
145 int main(int argc, char **argv)
146 {
147  g_test_init(&argc, &argv, NULL);
148 
149  // Test for input string issues
150  g_test_add_func("/common/strings/double/empty_input", empty_input_string);
151  g_test_add_func("/common/strings/double/bad_input", bad_input_string);
152  g_test_add_func("/common/strings/double/trailing_chars", trailing_chars);
153 
154  // Test for numeric issues
155  g_test_add_func("/common/strings/double/typical", typical_case);
156  g_test_add_func("/common/strings/double/overflow", double_overflow);
157  g_test_add_func("/common/strings/double/underflow", double_underflow);
158 
159  return g_test_run();
160 }
161 
#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:178
#define LOCAL_BUF_SIZE