Files
open62541/tests/check_parse_num.c

283 lines
8.6 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <check.h>
#include "parse_num.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <float.h>
/* parseUInt64 tests */
START_TEST(parseUint64Zero) {
uint64_t result = 42;
size_t len = parseUInt64("0", 1, &result);
ck_assert_uint_eq(len, 1);
ck_assert_uint_eq(result, 0);
} END_TEST
START_TEST(parseUint64Simple) {
uint64_t result = 0;
size_t len = parseUInt64("12345", 5, &result);
ck_assert_uint_eq(len, 5);
ck_assert_uint_eq(result, 12345);
} END_TEST
START_TEST(parseUint64Max) {
uint64_t result = 0;
const char *str = "18446744073709551615";
size_t len = parseUInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 20);
ck_assert_uint_eq(result, UINT64_MAX);
} END_TEST
START_TEST(parseUint64Overflow) {
uint64_t result = 0;
/* One more than UINT64_MAX: 18446744073709551616 */
const char *str = "18446744073709551616";
size_t len = parseUInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 0); /* overflow → return 0 */
} END_TEST
START_TEST(parseUint64Hex) {
uint64_t result = 0;
size_t len = parseUInt64("0xFF", 4, &result);
ck_assert_uint_eq(len, 4);
ck_assert_uint_eq(result, 255);
} END_TEST
START_TEST(parseUint64HexLower) {
uint64_t result = 0;
size_t len = parseUInt64("0xff", 4, &result);
ck_assert_uint_eq(len, 4);
ck_assert_uint_eq(result, 255);
} END_TEST
START_TEST(parseUint64HexZero) {
uint64_t result = 0;
size_t len = parseUInt64("0x0", 3, &result);
ck_assert_uint_eq(len, 3);
ck_assert_uint_eq(result, 0);
} END_TEST
START_TEST(parseUint64HexNoDigit) {
/* "0x" with no hex digit after prefix: parser may consume '0' as decimal */
uint64_t result = 42;
size_t len = parseUInt64("0x", 2, &result);
/* Implementation parses '0' as a decimal zero, returns len=1 */
ck_assert_uint_le(len, 2);
} END_TEST
START_TEST(parseUint64HexLarge) {
uint64_t result = 0;
const char *str = "0xFFFFFFFFFFFFFFFF";
size_t len = parseUInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 18);
ck_assert_uint_eq(result, UINT64_MAX);
} END_TEST
START_TEST(parseUint64PartialConsumption) {
uint64_t result = 0;
size_t len = parseUInt64("123abc", 6, &result);
ck_assert_uint_eq(len, 3);
ck_assert_uint_eq(result, 123);
} END_TEST
START_TEST(parseUint64EmptyString) {
uint64_t result = 42;
size_t len = parseUInt64("", 0, &result);
ck_assert_uint_eq(len, 0);
ck_assert_uint_eq(result, 0);
} END_TEST
START_TEST(parseUint64NonNumeric) {
uint64_t result = 42;
size_t len = parseUInt64("abc", 3, &result);
ck_assert_uint_eq(len, 0);
ck_assert_uint_eq(result, 0);
} END_TEST
START_TEST(parseUint64HexMixed) {
uint64_t result = 0;
size_t len = parseUInt64("0xAbCd", 6, &result);
ck_assert_uint_eq(len, 6);
ck_assert_uint_eq(result, 0xABCD);
} END_TEST
/* parseInt64 tests */
START_TEST(parseInt64Zero) {
int64_t result = 42;
size_t len = parseInt64("0", 1, &result);
ck_assert_uint_eq(len, 1);
ck_assert_int_eq(result, 0);
} END_TEST
START_TEST(parseInt64Positive) {
int64_t result = 0;
size_t len = parseInt64("12345", 5, &result);
ck_assert_uint_eq(len, 5);
ck_assert_int_eq(result, 12345);
} END_TEST
START_TEST(parseInt64Negative) {
int64_t result = 0;
size_t len = parseInt64("-12345", 6, &result);
ck_assert_uint_eq(len, 6);
ck_assert_int_eq(result, -12345);
} END_TEST
START_TEST(parseInt64PlusSign) {
int64_t result = 0;
size_t len = parseInt64("+42", 3, &result);
ck_assert_uint_eq(len, 3);
ck_assert_int_eq(result, 42);
} END_TEST
START_TEST(parseInt64Max) {
int64_t result = 0;
const char *str = "9223372036854775807";
size_t len = parseInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 19);
ck_assert_int_eq(result, INT64_MAX);
} END_TEST
START_TEST(parseInt64Min) {
int64_t result = 0;
const char *str = "-9223372036854775808";
size_t len = parseInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 20);
ck_assert_int_eq(result, INT64_MIN);
} END_TEST
START_TEST(parseInt64OverflowPositive) {
int64_t result = 0;
/* One more than INT64_MAX */
const char *str = "9223372036854775808";
size_t len = parseInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 0); /* overflow → return 0 */
} END_TEST
START_TEST(parseInt64OverflowNegative) {
int64_t result = 0;
/* One less than INT64_MIN (abs value one more than 9223372036854775808) */
const char *str = "-9223372036854775809";
size_t len = parseInt64(str, strlen(str), &result);
ck_assert_uint_eq(len, 0); /* overflow → return 0 */
} END_TEST
/* parseDouble tests */
START_TEST(parseDoubleSimple) {
double result = 0.0;
size_t len = parseDouble("3.14", 4, &result);
ck_assert_uint_gt(len, 0);
ck_assert((fabs(result - 3.14)) <= (1e-10));
} END_TEST
START_TEST(parseDoubleZero) {
double result = 42.0;
size_t len = parseDouble("0.0", 3, &result);
ck_assert_uint_gt(len, 0);
ck_assert((result) == (0.0));
} END_TEST
START_TEST(parseDoubleNegative) {
double result = 0.0;
size_t len = parseDouble("-1.5", 4, &result);
ck_assert_uint_gt(len, 0);
ck_assert((result) == (-1.5));
} END_TEST
START_TEST(parseDoubleScientific) {
double result = 0.0;
size_t len = parseDouble("1.5e10", 6, &result);
ck_assert_uint_gt(len, 0);
ck_assert((fabs(result - 1.5e10)) <= (1.0));
} END_TEST
START_TEST(parseDoubleTooLong) {
/* Size >= 2000 → return 0 */
double result = 42.0;
char buf[2001];
memset(buf, '1', 2000);
buf[2000] = '\0';
size_t len = parseDouble(buf, 2000, &result);
ck_assert_uint_eq(len, 0);
} END_TEST
START_TEST(parseDoubleInteger) {
double result = 0.0;
size_t len = parseDouble("42", 2, &result);
ck_assert_uint_gt(len, 0);
ck_assert((result) == (42.0));
} END_TEST
START_TEST(parseDoubleSubstring) {
/* Parse "3.14" from a buffer that is NOT null-terminated at position 4.
* Before the fix, strtod was called on the original (non-terminated)
* pointer instead of the null-terminated local copy. */
char buf[8] = {'3', '.', '1', '4', 'X', 'Y', 'Z', '!'};
double result = 0.0;
size_t len = parseDouble(buf, 4, &result);
ck_assert_uint_eq(len, 4);
ck_assert(fabs(result - 3.14) <= 1e-9);
} END_TEST
static Suite *testSuite_parse_num(void) {
TCase *tc_uint = tcase_create("parseUInt64");
tcase_add_test(tc_uint, parseUint64Zero);
tcase_add_test(tc_uint, parseUint64Simple);
tcase_add_test(tc_uint, parseUint64Max);
tcase_add_test(tc_uint, parseUint64Overflow);
tcase_add_test(tc_uint, parseUint64Hex);
tcase_add_test(tc_uint, parseUint64HexLower);
tcase_add_test(tc_uint, parseUint64HexZero);
tcase_add_test(tc_uint, parseUint64HexNoDigit);
tcase_add_test(tc_uint, parseUint64HexLarge);
tcase_add_test(tc_uint, parseUint64PartialConsumption);
tcase_add_test(tc_uint, parseUint64EmptyString);
tcase_add_test(tc_uint, parseUint64NonNumeric);
tcase_add_test(tc_uint, parseUint64HexMixed);
TCase *tc_int = tcase_create("parseInt64");
tcase_add_test(tc_int, parseInt64Zero);
tcase_add_test(tc_int, parseInt64Positive);
tcase_add_test(tc_int, parseInt64Negative);
tcase_add_test(tc_int, parseInt64PlusSign);
tcase_add_test(tc_int, parseInt64Max);
tcase_add_test(tc_int, parseInt64Min);
tcase_add_test(tc_int, parseInt64OverflowPositive);
tcase_add_test(tc_int, parseInt64OverflowNegative);
TCase *tc_double = tcase_create("parseDouble");
tcase_add_test(tc_double, parseDoubleSimple);
tcase_add_test(tc_double, parseDoubleZero);
tcase_add_test(tc_double, parseDoubleNegative);
tcase_add_test(tc_double, parseDoubleScientific);
tcase_add_test(tc_double, parseDoubleTooLong);
tcase_add_test(tc_double, parseDoubleInteger);
tcase_add_test(tc_double, parseDoubleSubstring);
Suite *s = suite_create("Test number parsing functions");
suite_add_tcase(s, tc_uint);
suite_add_tcase(s, tc_int);
suite_add_tcase(s, tc_double);
return s;
}
int main(void) {
int number_failed = 0;
Suite *s = testSuite_parse_num();
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr, CK_NORMAL);
number_failed += srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}