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 <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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 

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