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-2022 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     char *end_text;
  77 
  78     assert_int_equal(pcmk__scan_double("2.0asdf", &result, NULL, &end_text), pcmk_rc_ok);
  79     assert_float_equal(result, 2.0, DBL_EPSILON);
  80     assert_string_equal(end_text, "asdf");
  81 }
  82 
  83 static void
  84 typical_case(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86     char str[LOCAL_BUF_SIZE];
  87     double result;
  88 
  89     assert_int_equal(pcmk__scan_double("0.0", &result, NULL, NULL), pcmk_rc_ok);
  90     assert_float_equal(result, 0.0, DBL_EPSILON);
  91 
  92     assert_int_equal(pcmk__scan_double("1.0", &result, NULL, NULL), pcmk_rc_ok);
  93     assert_float_equal(result, 1.0, DBL_EPSILON);
  94 
  95     assert_int_equal(pcmk__scan_double("-1.0", &result, NULL, NULL), pcmk_rc_ok);
  96     assert_float_equal(result, -1.0, DBL_EPSILON);
  97 
  98     snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX);
  99     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
 100     assert_float_equal(result, DBL_MAX, DBL_EPSILON);
 101 
 102     snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX);
 103     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok);
 104     assert_float_equal(result, -DBL_MAX, DBL_EPSILON);
 105 }
 106 
 107 static void
 108 double_overflow(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     char str[LOCAL_BUF_SIZE];
 111     double result;
 112 
 113     /*
 114      * 1e(DBL_MAX_10_EXP + 1) produces an inf value
 115      * Can't use assert_float_equal() because (inf - inf) == NaN
 116      */
 117     snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1);
 118     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
 119     assert_true(result > DBL_MAX);
 120 
 121     snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1);
 122     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW);
 123     assert_true(result < -DBL_MAX);
 124 }
 125 
 126 static void
 127 double_underflow(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129     char str[LOCAL_BUF_SIZE];
 130     double result;
 131 
 132     /*
 133      * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0
 134      * and DBL_MIN)
 135      *
 136      * C99/C11: result will be **no greater than** DBL_MIN
 137      */
 138     snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1);
 139     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
 140     assert_true(result >= 0.0);
 141     assert_true(result <= DBL_MIN);
 142 
 143     snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1);
 144     assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow);
 145     assert_true(result <= 0.0);
 146     assert_true(result >= -DBL_MIN);
 147 }
 148 
 149 int main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151     const struct CMUnitTest tests[] = {
 152         // Test for input string issues
 153         cmocka_unit_test(empty_input_string),
 154         cmocka_unit_test(bad_input_string),
 155         cmocka_unit_test(trailing_chars),
 156 
 157         // Test for numeric issues
 158         cmocka_unit_test(typical_case),
 159         cmocka_unit_test(double_overflow),
 160         cmocka_unit_test(double_underflow),
 161     };
 162 
 163     cmocka_set_message_output(CM_OUTPUT_TAP);
 164     return cmocka_run_group_tests(tests, NULL, NULL);
 165 }
 166 

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