#include "unity/unity.h" #define PCRE2_CODE_UNIT_WIDTH 8 #include "pcre2.h" #include "pcre2_compile.h" #include #include #include #include /* The wrapper is defined in the module under test. We declare it with a void* for the first parameter to avoid needing eclass_context's definition. */ extern BOOL test_compile_eclass_nested(void *context, BOOL negated, uint32_t **pptr, PCRE2_UCHAR **pcode, eclass_op_info *pop_info, PCRE2_SIZE *lengthptr); static void assert_bits_all(uint8_t *bits, uint8_t value) { for (int i = 0; i < 32; i++) { TEST_ASSERT_EQUAL_HEX8_MESSAGE(value, bits[i], "Bitset value mismatch"); } } static void assert_single_op(const eclass_op_info *info, int expected_op) { TEST_ASSERT_EQUAL_UINT_MESSAGE(1, info->length, "Expected single opcode length"); TEST_ASSERT_EQUAL_INT_MESSAGE(expected_op, info->op_single_type, "op_single_type mismatch"); TEST_ASSERT_NOT_NULL(info->code_start); TEST_ASSERT_EQUAL_INT8_MESSAGE((int8_t)expected_op, (int8_t)info->code_start[0], "Emitted opcode mismatch"); } void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* [] => NONE */ void test_compile_eclass_nested_empty_returns_none(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[16] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_NONE); assert_bits_all(info.bits.classbits, 0x00); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* [^] (via META_CLASS_NOT around a nested class with empty) => ANY */ void test_compile_eclass_nested_empty_with_outer_not_returns_any(void) { uint32_t tokens[] = { (META_CLASS_NOT | CLASS_IS_ECLASS), META_CLASS_EMPTY, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[16] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_ANY); assert_bits_all(info.bits.classbits, 0xFF); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* ![] (META_ECLASS_NOT unary) => ANY */ void test_compile_eclass_nested_unary_not_operator(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_ECLASS_NOT, META_CLASS_EMPTY, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[16] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_ANY); assert_bits_all(info.bits.classbits, 0xFF); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* [] && [^] => NONE */ void test_compile_eclass_nested_binary_and_folding(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY, META_ECLASS_AND, META_CLASS_EMPTY_NOT, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[32] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_NONE); assert_bits_all(info.bits.classbits, 0x00); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* [] || [^] => ANY */ void test_compile_eclass_nested_binary_or_folding(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY, META_ECLASS_OR, META_CLASS_EMPTY_NOT, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[32] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_ANY); assert_bits_all(info.bits.classbits, 0xFF); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* [^] -- [^] => ANY && !ANY => NONE */ void test_compile_eclass_nested_binary_sub_folding(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY_NOT, META_ECLASS_SUB, META_CLASS_EMPTY_NOT, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[32] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_NONE); assert_bits_all(info.bits.classbits, 0x00); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* [^] XOR [^] => NONE */ void test_compile_eclass_nested_binary_xor_folding(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY_NOT, META_ECLASS_XOR, META_CLASS_EMPTY_NOT, META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[32] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_NONE); assert_bits_all(info.bits.classbits, 0x00); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* Nested class inside: ([^]) && ([]) => NONE */ void test_compile_eclass_nested_with_nested_operand(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), /* Nested start */ (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY_NOT, /* inner => ANY */ META_CLASS_END, /* end inner */ META_ECLASS_AND, META_CLASS_EMPTY, /* outer RHS => NONE */ META_CLASS_END /* end outer */ }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[32] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, NULL); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); assert_single_op(&info, ECL_NONE); assert_bits_all(info.bits.classbits, 0x00); TEST_ASSERT_EQUAL_PTR(info.code_start + info.length, code); } /* lengthptr counting for a single operand: should be 1 */ void test_compile_eclass_nested_lengthptr_single_operand_counts_one(void) { uint32_t tokens[] = { (META_CLASS | CLASS_IS_ECLASS), META_CLASS_EMPTY_NOT, /* ANY */ META_CLASS_END }; uint32_t *ptr = tokens; PCRE2_UCHAR codebuf[16] = {0}; PCRE2_UCHAR *code = codebuf; eclass_op_info info; PCRE2_SIZE length = 0; BOOL ok = test_compile_eclass_nested(NULL, FALSE, &ptr, &code, &info, &length); TEST_ASSERT_TRUE(ok); TEST_ASSERT_EQUAL_UINT32(META_CLASS_END, *ptr); TEST_ASSERT_EQUAL_UINT(1, length); /* In lengthptr mode, code pointer should not advance. */ TEST_ASSERT_EQUAL_PTR(codebuf, code); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_compile_eclass_nested_empty_returns_none); RUN_TEST(test_compile_eclass_nested_empty_with_outer_not_returns_any); RUN_TEST(test_compile_eclass_nested_unary_not_operator); RUN_TEST(test_compile_eclass_nested_binary_and_folding); RUN_TEST(test_compile_eclass_nested_binary_or_folding); RUN_TEST(test_compile_eclass_nested_binary_sub_folding); RUN_TEST(test_compile_eclass_nested_binary_xor_folding); RUN_TEST(test_compile_eclass_nested_with_nested_operand); RUN_TEST(test_compile_eclass_nested_lengthptr_single_operand_counts_one); return UNITY_END(); }