File size: 5,525 Bytes
864071c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | #include "unity/unity.h"
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"
#include "pcre2_compile.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* External wrapper provided by the module under test */
extern size_t test_parse_class(uint32_t *ptr, uint32_t options, uint32_t *buffer);
static void assert_ranges_equal(const uint32_t *actual, size_t actual_size_u32, const uint32_t (*expected)[2], size_t expected_pairs)
{
/* actual_size_u32 is the number of uint32_t entries filled in actual.
It should be exactly expected_pairs * 2. */
TEST_ASSERT_EQUAL_UINT32((uint32_t)(expected_pairs * 2), (uint32_t)actual_size_u32);
for (size_t i = 0; i < expected_pairs; i++) {
TEST_ASSERT_EQUAL_UINT32(expected[i][0], actual[2*i + 0]);
TEST_ASSERT_EQUAL_UINT32(expected[i][1], actual[2*i + 1]);
}
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Helper to run parse_class twice (query size then fill) */
static size_t run_parse_and_fill(uint32_t *tokens, uint32_t options, uint32_t **out_buf)
{
size_t sz = test_parse_class(tokens, options, NULL);
if (sz == 0) {
*out_buf = NULL;
return 0;
}
uint32_t *buf = (uint32_t *)malloc(sz * sizeof(uint32_t));
TEST_ASSERT_NOT_NULL(buf);
memset(buf, 0xCC, sz * sizeof(uint32_t));
size_t sz2 = test_parse_class(tokens, options, buf);
TEST_ASSERT_EQUAL_UINT32((uint32_t)sz, (uint32_t)sz2);
*out_buf = buf;
return sz;
}
void test_parse_class_empty_returns_zero(void)
{
uint32_t tokens[] = {
META_CLASS_END
};
size_t sz = test_parse_class(tokens, 0 /* options */, NULL);
TEST_ASSERT_EQUAL_UINT32(0, (uint32_t)sz);
uint32_t *buf = NULL;
size_t sz2 = run_parse_and_fill(tokens, 0, &buf);
TEST_ASSERT_EQUAL_UINT32(0, (uint32_t)sz2);
TEST_ASSERT_NULL(buf);
}
void test_parse_class_single_literal_A(void)
{
uint32_t tokens[] = {
(uint32_t)'A',
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
const uint32_t expected[][2] = { { (uint32_t)'A', (uint32_t)'A' } };
assert_ranges_equal(buf, sz, expected, 1);
free(buf);
}
void test_parse_class_range_literal_a_to_d(void)
{
uint32_t tokens[] = {
(uint32_t)'a',
META_RANGE_LITERAL,
(uint32_t)'d',
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
const uint32_t expected[][2] = { { (uint32_t)'a', (uint32_t)'d' } };
assert_ranges_equal(buf, sz, expected, 1);
free(buf);
}
void test_parse_class_multiple_mixed_literals_and_ranges(void)
{
uint32_t tokens[] = {
(uint32_t)'b',
(uint32_t)'c',
(uint32_t)'x', META_RANGE_LITERAL, (uint32_t)'z',
(uint32_t)'Q',
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
const uint32_t expected[][2] = {
{ (uint32_t)'b', (uint32_t)'b' },
{ (uint32_t)'c', (uint32_t)'c' },
{ (uint32_t)'x', (uint32_t)'z' },
{ (uint32_t)'Q', (uint32_t)'Q' },
};
assert_ranges_equal(buf, sz, expected, 4);
free(buf);
}
void test_parse_class_bigvalue_single_literal(void)
{
/* U+20AC EURO SIGN as a big value literal */
uint32_t tokens[] = {
META_BIGVALUE, 0x20AC,
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
const uint32_t expected[][2] = { { 0x20ACu, 0x20ACu } };
assert_ranges_equal(buf, sz, expected, 1);
free(buf);
}
void test_parse_class_range_with_bigvalue_end_a_to_0100(void)
{
/* 'a' - 0x0100 range, where the end uses META_BIGVALUE encoding */
uint32_t tokens[] = {
(uint32_t)'a', META_RANGE_LITERAL, META_BIGVALUE, 0x0100u,
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
const uint32_t expected[][2] = { { (uint32_t)'a', 0x0100u } };
assert_ranges_equal(buf, sz, expected, 1);
free(buf);
}
void test_parse_class_posix_neg_adds_non_ascii_range(void)
{
/* POSIX negated class (the specific class value is ignored by parse_class for this path) */
uint32_t tokens[] = {
META_POSIX_NEG, 0, /* second word is class identifier (ignored here) */
META_CLASS_END
};
uint32_t *buf = NULL;
size_t sz = run_parse_and_fill(tokens, 0, &buf);
/* In 8-bit builds, highest char is MAX_UTF_CODE_POINT */
TEST_ASSERT_EQUAL_UINT32(2, (uint32_t)sz);
TEST_ASSERT_NOT_NULL(buf);
TEST_ASSERT_EQUAL_UINT32(0x100u, buf[0]);
/* Expect upper bound to be the max char point for 8-bit builds */
#ifdef MAX_UTF_CODE_POINT
TEST_ASSERT_EQUAL_UINT32((uint32_t)MAX_UTF_CODE_POINT, buf[1]);
#else
/* Fallback: at least ensure it's a large value and >= start */
TEST_ASSERT_MESSAGE(buf[1] >= 0x100u, "Upper bound for non-ASCII range must be >= 0x100");
#endif
free(buf);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_parse_class_empty_returns_zero);
RUN_TEST(test_parse_class_single_literal_A);
RUN_TEST(test_parse_class_range_literal_a_to_d);
RUN_TEST(test_parse_class_multiple_mixed_literals_and_ranges);
RUN_TEST(test_parse_class_bigvalue_single_literal);
RUN_TEST(test_parse_class_range_with_bigvalue_end_a_to_0100);
RUN_TEST(test_parse_class_posix_neg_adds_non_ascii_range);
return UNITY_END();
} |