mirror of
https://github.com/open62541/open62541.git
synced 2026-10-18 13:42:32 +08:00
283 lines
8.6 KiB
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;
|
|
}
|