File size: 6,928 Bytes
6baed57 |
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 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <string.h>
#include <stdlib.h>
/* Wrapper for the static function provided in the source module */
extern int test_htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value);
static xmlNodePtr make_dummy_node(const char *name) {
return xmlNewNode(NULL, (const xmlChar *)name);
}
void setUp(void) {
xmlInitParser();
}
void tearDown(void) {
xmlCleanupParser();
}
/* Helper to compare two htmlParserNodeInfo records */
static void assert_nodeinfo_equal(const htmlParserNodeInfo *a, const htmlParserNodeInfo *b) {
TEST_ASSERT_NOT_NULL(a);
TEST_ASSERT_NOT_NULL(b);
TEST_ASSERT_EQUAL_PTR(a->node, b->node);
TEST_ASSERT_EQUAL_UINT64(a->begin_pos, b->begin_pos);
TEST_ASSERT_EQUAL_UINT64(a->begin_line, b->begin_line);
TEST_ASSERT_EQUAL_UINT64(a->end_pos, b->end_pos);
TEST_ASSERT_EQUAL_UINT64(a->end_line, b->end_line);
}
/* Test: initial allocation when table is NULL and max=0 */
void test_htmlNodeInfoPush_initial_alloc_and_store(void) {
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL(ctxt);
/* Force an empty stack state */
ctxt->nodeInfoTab = NULL;
ctxt->nodeInfoMax = 0;
ctxt->nodeInfoNr = 0;
ctxt->nodeInfo = NULL;
xmlNodePtr n1 = make_dummy_node("n1");
TEST_ASSERT_NOT_NULL(n1);
htmlParserNodeInfo info1;
memset(&info1, 0, sizeof(info1));
info1.node = n1;
info1.begin_pos = 10;
info1.begin_line = 2;
info1.end_pos = 20;
info1.end_line = 3;
int ret = test_htmlNodeInfoPush(ctxt, &info1);
/* ret can be 0 for first element; ensure push succeeded */
TEST_ASSERT_NOT_NULL(ctxt->nodeInfoTab);
TEST_ASSERT_TRUE(ctxt->nodeInfoMax > 0);
TEST_ASSERT_EQUAL_INT(1, ctxt->nodeInfoNr);
TEST_ASSERT_EQUAL_PTR(&ctxt->nodeInfoTab[0], ctxt->nodeInfo);
assert_nodeinfo_equal(&info1, &ctxt->nodeInfoTab[0]);
xmlFreeNode(n1);
htmlFreeParserCtxt(ctxt);
}
/* Test: push when there is already capacity (no growth path) */
void test_htmlNodeInfoPush_no_growth_needed(void) {
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL(ctxt);
/* Pre-allocate capacity for 4 entries */
int cap = 4;
ctxt->nodeInfoTab = (xmlParserNodeInfo *)xmlMalloc(sizeof(ctxt->nodeInfoTab[0]) * cap);
TEST_ASSERT_NOT_NULL(ctxt->nodeInfoTab);
ctxt->nodeInfoMax = cap;
ctxt->nodeInfoNr = 0;
ctxt->nodeInfo = NULL;
xmlNodePtr n1 = make_dummy_node("a");
xmlNodePtr n2 = make_dummy_node("b");
TEST_ASSERT_NOT_NULL(n1);
TEST_ASSERT_NOT_NULL(n2);
htmlParserNodeInfo info1, info2;
memset(&info1, 0, sizeof(info1));
memset(&info2, 0, sizeof(info2));
info1.node = n1; info1.begin_pos = 1; info1.begin_line = 1; info1.end_pos = 2; info1.end_line = 2;
info2.node = n2; info2.begin_pos = 3; info2.begin_line = 3; info2.end_pos = 4; info2.end_line = 4;
int ret0 = test_htmlNodeInfoPush(ctxt, &info1);
TEST_ASSERT_EQUAL_INT(0, ret0);
TEST_ASSERT_EQUAL_INT(1, ctxt->nodeInfoNr);
TEST_ASSERT_EQUAL_PTR(&ctxt->nodeInfoTab[0], ctxt->nodeInfo);
assert_nodeinfo_equal(&info1, &ctxt->nodeInfoTab[0]);
int ret1 = test_htmlNodeInfoPush(ctxt, &info2);
TEST_ASSERT_EQUAL_INT(1, ret1);
TEST_ASSERT_EQUAL_INT(2, ctxt->nodeInfoNr);
TEST_ASSERT_EQUAL_PTR(&ctxt->nodeInfoTab[1], ctxt->nodeInfo);
assert_nodeinfo_equal(&info2, &ctxt->nodeInfoTab[1]);
xmlFreeNode(n1);
xmlFreeNode(n2);
htmlFreeParserCtxt(ctxt);
}
/* Test: growth when full and preservation of existing entries */
void test_htmlNodeInfoPush_growth_and_preserve_existing(void) {
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL(ctxt);
/* Capacity 1, already filled with one element */
ctxt->nodeInfoTab = (xmlParserNodeInfo *)xmlMalloc(sizeof(ctxt->nodeInfoTab[0]) * 1);
TEST_ASSERT_NOT_NULL(ctxt->nodeInfoTab);
ctxt->nodeInfoMax = 1;
ctxt->nodeInfoNr = 1;
ctxt->nodeInfo = &ctxt->nodeInfoTab[0];
xmlNodePtr n0 = make_dummy_node("first");
xmlNodePtr n1 = make_dummy_node("second");
TEST_ASSERT_NOT_NULL(n0);
TEST_ASSERT_NOT_NULL(n1);
htmlParserNodeInfo first, second;
memset(&first, 0, sizeof(first));
memset(&second, 0, sizeof(second));
first.node = n0; first.begin_pos = 10; first.begin_line = 1; first.end_pos = 11; first.end_line = 2;
second.node = n1; second.begin_pos = 20; second.begin_line = 3; second.end_pos = 21; second.end_line = 4;
/* Initialize first entry */
ctxt->nodeInfoTab[0] = first;
/* Push second; should trigger growth and append at index 1 */
int ret = test_htmlNodeInfoPush(ctxt, &second);
TEST_ASSERT_EQUAL_INT(1, ret);
TEST_ASSERT_TRUE(ctxt->nodeInfoMax > 1);
TEST_ASSERT_EQUAL_INT(2, ctxt->nodeInfoNr);
TEST_ASSERT_NOT_NULL(ctxt->nodeInfoTab);
TEST_ASSERT_EQUAL_PTR(&ctxt->nodeInfoTab[1], ctxt->nodeInfo);
assert_nodeinfo_equal(&first, &ctxt->nodeInfoTab[0]);
assert_nodeinfo_equal(&second, &ctxt->nodeInfoTab[1]);
xmlFreeNode(n0);
xmlFreeNode(n1);
htmlFreeParserCtxt(ctxt);
}
/* Test: multiple pushes to ensure repeated growth and correct indexing */
void test_htmlNodeInfoPush_multiple_pushes(void) {
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL(ctxt);
/* Start with an empty stack */
ctxt->nodeInfoTab = NULL;
ctxt->nodeInfoMax = 0;
ctxt->nodeInfoNr = 0;
ctxt->nodeInfo = NULL;
const int count = 100;
xmlNodePtr nodes[count];
for (int i = 0; i < count; i++) {
nodes[i] = make_dummy_node("x");
TEST_ASSERT_NOT_NULL(nodes[i]);
htmlParserNodeInfo info;
memset(&info, 0, sizeof(info));
info.node = nodes[i];
info.begin_pos = (unsigned long)i;
info.begin_line = (unsigned long)(i + 1);
info.end_pos = (unsigned long)(2 * i);
info.end_line = (unsigned long)(2 * i + 1);
int ret = test_htmlNodeInfoPush(ctxt, &info);
TEST_ASSERT_EQUAL_INT(i, ret);
TEST_ASSERT_EQUAL_INT(i + 1, ctxt->nodeInfoNr);
/* Verify the just-pushed element */
assert_nodeinfo_equal(&info, &ctxt->nodeInfoTab[i]);
TEST_ASSERT_EQUAL_PTR(&ctxt->nodeInfoTab[i], ctxt->nodeInfo);
}
TEST_ASSERT_TRUE(ctxt->nodeInfoMax >= ctxt->nodeInfoNr);
TEST_ASSERT_EQUAL_INT(count, ctxt->nodeInfoNr);
/* Cleanup created nodes */
for (int i = 0; i < count; i++) {
xmlFreeNode(nodes[i]);
}
htmlFreeParserCtxt(ctxt);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_htmlNodeInfoPush_initial_alloc_and_store);
RUN_TEST(test_htmlNodeInfoPush_no_growth_needed);
RUN_TEST(test_htmlNodeInfoPush_growth_and_preserve_existing);
RUN_TEST(test_htmlNodeInfoPush_multiple_pushes);
return UNITY_END();
} |