pcre2 / tests /tests_pcre2_compile_read_number.c
AryaWu's picture
Upload folder using huggingface_hub
864071c verified
#include "unity/unity.h"
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"
#include <stdint.h>
#include <string.h>
/* The module provides a test wrapper to invoke the static read_number(). */
extern int test_read_number(PCRE2_SPTR *ptrptr,
PCRE2_SPTR ptrend,
int32_t allow_sign,
uint32_t max_value,
uint32_t max_error,
int *intptr,
int *errorcodeptr);
void setUp(void) {
/* Nothing to set up */
}
void tearDown(void) {
/* Nothing to tear down */
}
/* Helper to make PCRE2_SPTR from C string and limit */
static void make_span(const char *s, PCRE2_SPTR *start, PCRE2_SPTR *end) {
*start = (const PCRE2_UCHAR *)s;
*end = (const PCRE2_UCHAR *)(s + strlen(s));
}
/* Basic number parsing without sign; should succeed and stop at first non-digit */
void test_read_number_basic(void) {
const char *s = "123abc";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = -1, err = -1;
PCRE2_SPTR p0 = p;
int rc = test_read_number(&p, e, -1, 100000, 9999, &out, &err);
TEST_ASSERT_TRUE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_INT(123, out);
/* Pointer advanced past digits (3 chars) */
TEST_ASSERT_EQUAL_PTR((const void*)(p0 + 3), (const void*)p);
}
/* No number found (first char non-digit and sign not allowed); returns FALSE, errorcode==0, pointer unchanged */
void test_read_number_no_number_no_error(void) {
const char *s = "xyz";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
PCRE2_SPTR p0 = p;
int out = 0, err = 12345;
int rc = test_read_number(&p, e, -1, 100, 777, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_PTR((const void*)p0, (const void*)p);
}
/* Sign not allowed (allow_sign < 0); "+3" should be treated as 'no number found', pointer unchanged */
void test_read_number_sign_not_allowed(void) {
const char *s = "+3";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
PCRE2_SPTR p0 = p;
int out = 0, err = 0;
int rc = test_read_number(&p, e, -1, 100, 123, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_PTR((const void*)p0, (const void*)p);
}
/* Positive relative reference with allow_sign >= 0: "+2" when allow_sign=3 => 3 + 2 = 5 */
void test_read_number_positive_relative_valid(void) {
const char *s = "+2end";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 3, 1000, 999, &out, &err);
TEST_ASSERT_TRUE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_INT(5, out);
/* pointer advanced to after '2' */
TEST_ASSERT_EQUAL_CHAR('e', *p);
}
/* Negative relative reference valid: "-2" when allow_sign=3 => 3 + 1 - 2 = 2 */
void test_read_number_negative_relative_valid(void) {
const char *s = "-2";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 3, 1000, 999, &out, &err);
TEST_ASSERT_TRUE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_INT(2, out);
TEST_ASSERT_EQUAL_PTR((const void*)e, (const void*)p);
}
/* Negative relative reference invalid: "-4" when allow_sign=3 => error (non-zero), return FALSE */
void test_read_number_negative_relative_invalid(void) {
const char *s = "-4X";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 3, 1000, 321, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_NOT_EQUAL(0, err);
/* pointer advanced past the digits '4' */
TEST_ASSERT_EQUAL_CHAR('X', *p);
}
/* -0 and +0 are invalid when sign mode enabled; should set non-zero error, return FALSE */
void test_read_number_signed_zero_is_invalid(void) {
/* -0 */
{
const char *s = "-0end";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 5, 1000, 321, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_NOT_EQUAL(0, err);
/* pointer advanced past '0' */
TEST_ASSERT_EQUAL_CHAR('e', *p);
}
/* +0 */
{
const char *s = "+0!";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 7, 1000, 654, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_NOT_EQUAL(0, err);
TEST_ASSERT_EQUAL_CHAR('!', *p);
}
}
/* Overflow with max_value: once n exceeds max_value, error set to max_error, all digits skipped, returns FALSE */
void test_read_number_overflow_sets_error_and_skips_digits(void) {
const char *s = "123456a";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
uint32_t max_error = 777;
int rc = test_read_number(&p, e, -1, 100, max_error, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_EQUAL_INT((int)max_error, err);
/* Pointer advanced to first non-digit 'a' */
TEST_ASSERT_EQUAL_CHAR('a', *p);
}
/* When sign is allowed but no digit follows (e.g., "+x"), it's "no number found": FALSE, err=0, pointer advanced past sign */
void test_read_number_plus_without_digits_advances_pointer(void) {
const char *s = "+x";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
PCRE2_SPTR p0 = p;
int out = 0, err = 123;
int rc = test_read_number(&p, e, 0, 1000, 99, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
/* Advanced over '+' even though no digits */
TEST_ASSERT_EQUAL_PTR((const void*)(p0 + 1), (const void*)p);
TEST_ASSERT_EQUAL_CHAR('x', *p);
}
/* Check that adjusted max_value with positive sign prevents overflow after adding allow_sign:
For allow_sign=10, max_value=100, "+90" should pass with result 100; "+91" should overflow. */
void test_read_number_plus_with_adjusted_maxvalue_guard(void) {
/* Allowed case: +90 => 90 <= (100 - 10) then +10 => 100 */
{
const char *s = "+90.";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, 10, 100, 4242, &out, &err);
TEST_ASSERT_TRUE(rc);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_INT(100, out);
TEST_ASSERT_EQUAL_CHAR('.', *p);
}
/* Disallowed case: +91 would exceed overall max after adding allow_sign => overflow error */
{
const char *s = "+91!";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
uint32_t max_error = 5050;
int rc = test_read_number(&p, e, 10, 100, max_error, &out, &err);
TEST_ASSERT_FALSE(rc);
TEST_ASSERT_EQUAL_INT((int)max_error, err);
TEST_ASSERT_EQUAL_CHAR('!', *p);
}
}
/* Verify pointer advances to end when reading digits up to ptrend */
void test_read_number_consumes_to_ptrend(void) {
const char *s = "42";
PCRE2_SPTR p, e;
make_span(s, &p, &e);
int out = 0, err = 0;
int rc = test_read_number(&p, e, -1, 1000, 123, &out, &err);
TEST_ASSERT_TRUE(rc);
TEST_ASSERT_EQUAL_INT(42, out);
TEST_ASSERT_EQUAL_INT(0, err);
TEST_ASSERT_EQUAL_PTR((const void*)e, (const void*)p);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_read_number_basic);
RUN_TEST(test_read_number_no_number_no_error);
RUN_TEST(test_read_number_sign_not_allowed);
RUN_TEST(test_read_number_positive_relative_valid);
RUN_TEST(test_read_number_negative_relative_valid);
RUN_TEST(test_read_number_negative_relative_invalid);
RUN_TEST(test_read_number_signed_zero_is_invalid);
RUN_TEST(test_read_number_overflow_sets_error_and_skips_digits);
RUN_TEST(test_read_number_plus_without_digits_advances_pointer);
RUN_TEST(test_read_number_plus_with_adjusted_maxvalue_guard);
RUN_TEST(test_read_number_consumes_to_ptrend);
return UNITY_END();
}