pcre2 / tests /tests_pcre2_compile_class_compile_class_operand.c
AryaWu's picture
Upload folder using huggingface_hub
864071c verified
#include "unity/unity.h"
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"
/* Internal compile-time interfaces and constants */
#include "pcre2_compile.h"
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
/* The wrapper is defined in the source module under test. We only need a prototype.
Use void* for the context parameter to avoid requiring its typedef here. */
extern BOOL test_compile_class_operand(void *context, BOOL negated,
uint32_t **pptr, PCRE2_UCHAR **pcode,
eclass_op_info *pop_info,
PCRE2_SIZE *lengthptr);
static void assert_bits_all_ones(const eclass_op_info *info) {
for (int i = 0; i < 8; i++) {
TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFFu, info->bits.classwords[i]);
}
}
static void assert_bits_all_zeros(const eclass_op_info *info) {
for (int i = 0; i < 8; i++) {
TEST_ASSERT_EQUAL_HEX32(0x00000000u, info->bits.classwords[i]);
}
}
void setUp(void) {
/* Nothing needed */
}
void tearDown(void) {
/* Nothing needed */
}
/* Helper to run the simple EMPTY/EMPTY_NOT case with/without negation and verify results. */
static void run_empty_case(uint32_t token, BOOL negated,
uint8_t expected_opcode, BOOL expect_all_ones_bits,
BOOL use_length_only_mode)
{
uint32_t tokens[3];
tokens[0] = token;
tokens[1] = META_CLASS_END; /* sentinel following token */
tokens[2] = META_END; /* extra sentinel */
uint32_t *ptr = tokens;
PCRE2_UCHAR codebuf[16];
memset(codebuf, 0, sizeof(codebuf));
PCRE2_UCHAR *codep = codebuf;
eclass_op_info opinfo;
memset(&opinfo, 0xCC, sizeof(opinfo)); /* poison to ensure function fills it */
PCRE2_SIZE len = 0;
PCRE2_SIZE *lengthptr = use_length_only_mode ? &len : NULL;
BOOL ok = test_compile_class_operand(NULL /* context unused in this path */,
negated, &ptr, &codep, &opinfo, lengthptr);
TEST_ASSERT_TRUE_MESSAGE(ok, "compile_class_operand returned FALSE");
/* Pointer advancement: should consume exactly one token from input */
TEST_ASSERT_EQUAL_PTR(tokens + 1, ptr);
if (use_length_only_mode) {
/* codep should be rewound to the start; len should reflect 1 unit written. */
TEST_ASSERT_EQUAL_PTR(codebuf, codep);
TEST_ASSERT_EQUAL_size_t(1, len);
/* The opcode byte is still written even in length-only mode. */
TEST_ASSERT_EQUAL_HEX8(expected_opcode, codebuf[0]);
TEST_ASSERT_NULL(opinfo.code_start);
} else {
TEST_ASSERT_EQUAL_HEX8(expected_opcode, codebuf[0]);
TEST_ASSERT_EQUAL_PTR(codebuf + 1, codep);
TEST_ASSERT_EQUAL_PTR(codebuf, opinfo.code_start);
}
TEST_ASSERT_EQUAL_UINT(1, opinfo.length);
TEST_ASSERT_EQUAL_HEX8(expected_opcode, opinfo.op_single_type);
if (expect_all_ones_bits) {
assert_bits_all_ones(&opinfo);
} else {
assert_bits_all_zeros(&opinfo);
}
}
void test_compile_class_operand_EMPTY_negated_false(void) {
/* META_CLASS_EMPTY, negated == FALSE => ECL_NONE, all bits zero */
run_empty_case(META_CLASS_EMPTY, /*negated*/FALSE, ECL_NONE, /*all ones*/FALSE, /*len only*/FALSE);
}
void test_compile_class_operand_EMPTY_negated_true(void) {
/* META_CLASS_EMPTY, negated == TRUE => ECL_ANY, all bits ones */
run_empty_case(META_CLASS_EMPTY, /*negated*/TRUE, ECL_ANY, /*all ones*/TRUE, /*len only*/FALSE);
}
void test_compile_class_operand_EMPTY_NOT_negated_false(void) {
/* META_CLASS_EMPTY_NOT, negated == FALSE => ECL_ANY, all bits ones */
run_empty_case(META_CLASS_EMPTY_NOT, /*negated*/FALSE, ECL_ANY, /*all ones*/TRUE, /*len only*/FALSE);
}
void test_compile_class_operand_EMPTY_NOT_negated_true(void) {
/* META_CLASS_EMPTY_NOT, negated == TRUE => ECL_NONE, all bits zero */
run_empty_case(META_CLASS_EMPTY_NOT, /*negated*/TRUE, ECL_NONE, /*all ones*/FALSE, /*len only*/FALSE);
}
void test_compile_class_operand_length_only_mode(void) {
/* Verify lengthptr-mode behavior for META_CLASS_EMPTY_NOT with no negation */
run_empty_case(META_CLASS_EMPTY_NOT, /*negated*/FALSE, ECL_ANY, /*all ones*/TRUE, /*len only*/TRUE);
}
/* Nested ECLASS containing an empty element: exercises the CLASS_IS_ECLASS path */
static void run_nested_empty_case(uint32_t inner_token, BOOL outer_negated,
uint8_t expected_opcode, BOOL expect_all_ones_bits,
BOOL use_length_only_mode)
{
uint32_t tokens[4];
tokens[0] = META_CLASS | CLASS_IS_ECLASS; /* nested class start */
tokens[1] = inner_token; /* inner content: EMPTY or EMPTY_NOT */
tokens[2] = META_CLASS_END; /* end nested class */
tokens[3] = META_END; /* sentinel */
uint32_t *ptr = tokens;
PCRE2_UCHAR codebuf[16];
memset(codebuf, 0, sizeof(codebuf));
PCRE2_UCHAR *codep = codebuf;
eclass_op_info opinfo;
memset(&opinfo, 0xCC, sizeof(opinfo));
PCRE2_SIZE len = 0;
PCRE2_SIZE *lengthptr = use_length_only_mode ? &len : NULL;
BOOL ok = test_compile_class_operand(NULL /* context unused via empty path */,
outer_negated, &ptr, &codep, &opinfo, lengthptr);
TEST_ASSERT_TRUE(ok);
/* Should consume the entire nested class block: 3 tokens */
TEST_ASSERT_EQUAL_PTR(tokens + 3, ptr);
if (use_length_only_mode) {
TEST_ASSERT_EQUAL_PTR(codebuf, codep);
TEST_ASSERT_EQUAL_size_t(1, len);
TEST_ASSERT_EQUAL_HEX8(expected_opcode, codebuf[0]);
TEST_ASSERT_NULL(opinfo.code_start);
} else {
TEST_ASSERT_EQUAL_HEX8(expected_opcode, codebuf[0]);
TEST_ASSERT_EQUAL_PTR(codebuf + 1, codep);
TEST_ASSERT_EQUAL_PTR(codebuf, opinfo.code_start);
}
TEST_ASSERT_EQUAL_UINT(1, opinfo.length);
TEST_ASSERT_EQUAL_HEX8(expected_opcode, opinfo.op_single_type);
if (expect_all_ones_bits) {
assert_bits_all_ones(&opinfo);
} else {
assert_bits_all_zeros(&opinfo);
}
}
void test_compile_class_operand_nested_EMPTY_not_negated(void) {
/* Nested: [ <EMPTY> ], negated == FALSE => ECL_NONE, bits zero */
run_nested_empty_case(META_CLASS_EMPTY, /*negated*/FALSE, ECL_NONE, /*all ones*/FALSE, /*len only*/FALSE);
}
void test_compile_class_operand_nested_EMPTY_negated(void) {
/* Nested: ![ <EMPTY> ], negated == TRUE => ECL_ANY, bits ones */
run_nested_empty_case(META_CLASS_EMPTY, /*negated*/TRUE, ECL_ANY, /*all ones*/TRUE, /*len only*/FALSE);
}
void test_compile_class_operand_nested_EMPTY_length_only_mode(void) {
/* Nested with length-only mode */
run_nested_empty_case(META_CLASS_EMPTY_NOT, /*negated*/FALSE, ECL_ANY, /*all ones*/TRUE, /*len only*/TRUE);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_compile_class_operand_EMPTY_negated_false);
RUN_TEST(test_compile_class_operand_EMPTY_negated_true);
RUN_TEST(test_compile_class_operand_EMPTY_NOT_negated_false);
RUN_TEST(test_compile_class_operand_EMPTY_NOT_negated_true);
RUN_TEST(test_compile_class_operand_length_only_mode);
RUN_TEST(test_compile_class_operand_nested_EMPTY_not_negated);
RUN_TEST(test_compile_class_operand_nested_EMPTY_negated);
RUN_TEST(test_compile_class_operand_nested_EMPTY_length_only_mode);
return UNITY_END();
}