pcre2 / tests /tests_pcre2_compile_pcre2_code_free.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 <stdlib.h>
#include <string.h>
/* Helper: compile a pattern, fail the test on error */
static pcre2_code* compile_pat(const char* pat)
{
int errorcode = 0;
PCRE2_SIZE erroroffset = 0;
pcre2_code* code = pcre2_compile(
(PCRE2_SPTR)pat,
PCRE2_ZERO_TERMINATED,
0,
&errorcode,
&erroroffset,
NULL);
if (code == NULL) {
char msg[256];
snprintf(msg, sizeof(msg), "pcre2_compile failed: error %d at offset %zu for pattern '%s'",
errorcode, (size_t)erroroffset, pat);
TEST_FAIL_MESSAGE(msg);
}
return code;
}
/* Helper: run a simple match, returning rc (>=0 success, <0 failure) */
static int match_rc(pcre2_code* code, const char* subject)
{
pcre2_match_data* mdata = pcre2_match_data_create_from_pattern(code, NULL);
TEST_ASSERT_NOT_NULL_MESSAGE(mdata, "pcre2_match_data_create_from_pattern returned NULL");
int rc = pcre2_match(
code,
(PCRE2_SPTR)subject,
(PCRE2_SIZE)strlen(subject),
0, /* startoffset */
0, /* options */
mdata,
NULL);
pcre2_match_data_free(mdata);
return rc;
}
void setUp(void) {
/* no-op */
}
void tearDown(void) {
/* no-op */
}
/* 1) pcre2_code_free must safely handle NULL */
void test_pcre2_code_free_null_ok(void)
{
pcre2_code_free(NULL);
TEST_PASS(); /* If we got here, no crash */
}
/* 2) Freeing a basic compiled code (no deref tables) should succeed */
void test_pcre2_code_free_basic_code(void)
{
pcre2_code* code = compile_pat("a+");
int rc = match_rc(code, "aaa");
TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(0, rc, "Expected a successful match before free");
pcre2_code_free(code);
/* Can't and shouldn't use the code after free; test ends here */
}
/* 3) Shared tables via copy_with_tables() + copy(): freeing one sharer must keep others valid */
void test_pcre2_code_free_shared_tables_refcount_two(void)
{
/* Compile a simple pattern */
pcre2_code* base = compile_pat("abc");
/* Create a copy with its own tables (refcount initialized to 1) */
pcre2_code* codeA = pcre2_code_copy_with_tables(base);
TEST_ASSERT_NOT_NULL_MESSAGE(codeA, "pcre2_code_copy_with_tables returned NULL");
/* Create a second copy sharing tables; copy() increments tables refcount */
pcre2_code* codeB = pcre2_code_copy(codeA);
TEST_ASSERT_NOT_NULL_MESSAGE(codeB, "pcre2_code_copy returned NULL");
/* Free first sharer; tables should not be freed yet (refcount > 1) */
pcre2_code_free(codeA);
/* Remaining sharer must still work */
int rc = match_rc(codeB, "xyzabcxyz");
TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(0, rc, "Expected successful match with remaining sharer after freeing another");
/* Clean up remaining codes */
pcre2_code_free(codeB);
pcre2_code_free(base);
}
/* 4) Shared tables with three sharers; free two, last must remain usable */
void test_pcre2_code_free_shared_tables_refcount_chain(void)
{
pcre2_code* base = compile_pat("h.*o"); /* simple pattern */
pcre2_code* codeA = pcre2_code_copy_with_tables(base);
TEST_ASSERT_NOT_NULL_MESSAGE(codeA, "pcre2_code_copy_with_tables returned NULL");
pcre2_code* codeB = pcre2_code_copy(codeA);
TEST_ASSERT_NOT_NULL_MESSAGE(codeB, "pcre2_code_copy returned NULL (B)");
pcre2_code* codeC = pcre2_code_copy(codeA);
TEST_ASSERT_NOT_NULL_MESSAGE(codeC, "pcre2_code_copy returned NULL (C)");
/* Free A and B; tables refcount should still be > 0 because C remains */
pcre2_code_free(codeA);
pcre2_code_free(codeB);
/* C must still be able to match */
int rc = match_rc(codeC, "hello");
TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(0, rc, "Expected successful match with last remaining sharer");
/* Clean up */
pcre2_code_free(codeC);
pcre2_code_free(base);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_pcre2_code_free_null_ok);
RUN_TEST(test_pcre2_code_free_basic_code);
RUN_TEST(test_pcre2_code_free_shared_tables_refcount_two);
RUN_TEST(test_pcre2_code_free_shared_tables_refcount_chain);
return UNITY_END();
}