root/lib/common/tests/strings/pcmk__scan_double_test.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. empty_input_string
  2. bad_input_string
  3. trailing_chars
  4. typical_case
  5. double_overflow
  6. double_underflow
  7. main

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  28 {
  29     double result;
  30 
  31     // Without default_text
  32     g_assert_cmpint(pcmk__scan_double(NULL, &result, NULL, NULL), ==, EINVAL);
  33     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  34 
  35     g_assert_cmpint(pcmk__scan_double("", &result, NULL, NULL), ==, EINVAL);
  36     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  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);
  44     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  45 }
  46 
  47 static void
  48 bad_input_string(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50     double result;
  51 
  52     // Without default text
  53     g_assert_cmpint(pcmk__scan_double("asdf", &result, NULL, NULL), ==, EINVAL);
  54     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  55 
  56     g_assert_cmpint(pcmk__scan_double("as2.0", &result, NULL, NULL), ==,
  57                     EINVAL);
  58     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  59 
  60     // With default text (not used)
  61     g_assert_cmpint(pcmk__scan_double("asdf", &result, "2.0", NULL), ==,
  62                     EINVAL);
  63     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  64 
  65     g_assert_cmpint(pcmk__scan_double("as2.0", &result, "2.0", NULL), ==,
  66                     EINVAL);
  67     ASSERT_DBL_EQ(result, PCMK__PARSE_DBL_DEFAULT);
  68 }
  69 
  70 static void
  71 trailing_chars(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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), ==,
 142                     pcmk_rc_underflow);
 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), ==,
 148                     pcmk_rc_underflow);
 149     g_assert_cmpfloat(result, <=, 0.0);
 150     g_assert_cmpfloat(result, >=, -DBL_MIN);
 151 }
 152 
 153 int main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 

/* [previous][next][first][last][top][bottom][index][help] */