File size: 7,090 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 |
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <stdlib.h>
#include <string.h>
/* Wrapper for the static function under test provided in the module */
extern void test_htmlParserFinishElementParsing(htmlParserCtxtPtr ctxt);
static htmlParserCtxtPtr
create_ctxt_with_input(size_t base_len, size_t cur_offset, unsigned long consumed, unsigned long line,
xmlParserInputPtr *outInput, xmlChar **outBase) {
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML parser context");
xmlParserInputPtr in = xmlNewInputStream(ctxt);
TEST_ASSERT_NOT_NULL_MESSAGE(in, "Failed to create new input stream");
xmlChar *base = (xmlChar *)xmlMalloc(base_len);
TEST_ASSERT_NOT_NULL_MESSAGE(base, "Failed to allocate base buffer");
memset(base, 'A', base_len);
/* Ensure cur_offset within base_len */
TEST_ASSERT_MESSAGE(cur_offset <= base_len, "cur_offset exceeds base buffer length");
in->base = base;
in->cur = base + cur_offset;
in->end = base + base_len;
in->consumed = consumed;
in->line = line;
ctxt->input = in;
if (outInput) *outInput = in;
if (outBase) *outBase = base;
return ctxt;
}
static void
destroy_ctxt_and_input(htmlParserCtxtPtr ctxt, xmlParserInputPtr in, xmlChar *base) {
if (ctxt != NULL) {
/* Detach input from context so we can free it explicitly to avoid double-free */
ctxt->input = NULL;
}
if (in != NULL) {
/* Avoid freeing base twice if libxml would attempt it; we own base */
in->base = NULL;
in->cur = NULL;
in->end = NULL;
xmlFreeInputStream(in);
}
if (base != NULL) {
xmlFree(base);
}
if (ctxt != NULL) {
htmlFreeParserCtxt(ctxt);
}
}
void setUp(void) {
xmlInitParser();
}
void tearDown(void) {
xmlCleanupParser();
}
void test_htmlParserFinishElementParsing_records_end_info_basic(void) {
xmlParserInputPtr in = NULL;
xmlChar *base = NULL;
/* base length 32, cur_offset 5, consumed 2, line 7 */
htmlParserCtxtPtr ctxt = create_ctxt_with_input(32, 5, 2, 7, &in, &base);
/* Prepare node and nodeInfo */
xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *)"test");
TEST_ASSERT_NOT_NULL(node);
ctxt->node = node;
ctxt->record_info = 1;
xmlParserNodeInfo *info = (xmlParserNodeInfo *)xmlMalloc(sizeof(xmlParserNodeInfo));
TEST_ASSERT_NOT_NULL(info);
memset(info, 0, sizeof(*info));
ctxt->nodeInfo = info;
/* Call the wrapper */
test_htmlParserFinishElementParsing(ctxt);
/* Verify info was added to the context's node info sequence */
const xmlParserNodeInfo *found = xmlParserFindNodeInfo(ctxt, node);
TEST_ASSERT_NOT_NULL_MESSAGE(found, "xmlParserNodeInfo not found for node");
TEST_ASSERT_EQUAL_PTR(node, found->node);
/* end_pos = consumed + (cur - base) = 2 + (5) = 7 */
TEST_ASSERT_EQUAL_UINT(7u, (unsigned int)found->end_pos);
TEST_ASSERT_EQUAL_UINT(7u, (unsigned int)found->end_line);
/* Cleanup */
xmlFreeNode(node);
/* info was likely freed by htmlNodeInfoPop; freeing only if still referenced would be unsafe.
We won't free 'info' here. */
destroy_ctxt_and_input(ctxt, in, base);
}
void test_htmlParserFinishElementParsing_calculates_end_pos_with_consumed_offset(void) {
xmlParserInputPtr in = NULL;
xmlChar *base = NULL;
/* base length 64, cur_offset 13, consumed 21, line 3 */
htmlParserCtxtPtr ctxt = create_ctxt_with_input(64, 13, 21, 3, &in, &base);
xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *)"elem");
TEST_ASSERT_NOT_NULL(node);
ctxt->node = node;
ctxt->record_info = 1;
xmlParserNodeInfo *info = (xmlParserNodeInfo *)xmlMalloc(sizeof(xmlParserNodeInfo));
TEST_ASSERT_NOT_NULL(info);
memset(info, 0, sizeof(*info));
ctxt->nodeInfo = info;
test_htmlParserFinishElementParsing(ctxt);
const xmlParserNodeInfo *found = xmlParserFindNodeInfo(ctxt, node);
TEST_ASSERT_NOT_NULL_MESSAGE(found, "xmlParserNodeInfo not found for node");
TEST_ASSERT_EQUAL_PTR(node, found->node);
/* end_pos = 21 + 13 = 34; end_line = 3 */
TEST_ASSERT_EQUAL_UINT(34u, (unsigned int)found->end_pos);
TEST_ASSERT_EQUAL_UINT(3u, (unsigned int)found->end_line);
xmlFreeNode(node);
destroy_ctxt_and_input(ctxt, in, base);
}
void test_htmlParserFinishElementParsing_noop_when_node_null(void) {
xmlParserInputPtr in = NULL;
xmlChar *base = NULL;
htmlParserCtxtPtr ctxt = create_ctxt_with_input(16, 4, 9, 11, &in, &base);
/* node is NULL; enable record_info to test the node NULL guard */
ctxt->node = NULL;
ctxt->record_info = 1;
/* Provide a nodeInfo struct; function must not use it since node is NULL */
xmlParserNodeInfo *info = (xmlParserNodeInfo *)xmlMalloc(sizeof(xmlParserNodeInfo));
TEST_ASSERT_NOT_NULL(info);
memset(info, 0, sizeof(*info));
ctxt->nodeInfo = info;
test_htmlParserFinishElementParsing(ctxt);
/* Create a node to search for; should not find any info since node was NULL */
xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *)"unused");
TEST_ASSERT_NOT_NULL(node);
const xmlParserNodeInfo *found = xmlParserFindNodeInfo(ctxt, node);
TEST_ASSERT_NULL(found);
xmlFreeNode(node);
/* As above, assume htmlNodeInfoPop may have freed info; do not free directly. */
destroy_ctxt_and_input(ctxt, in, base);
}
void test_htmlParserFinishElementParsing_noop_when_record_info_false_even_with_node(void) {
/* Intentionally no input to ensure function doesn't touch input when record_info == 0 */
htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
TEST_ASSERT_NOT_NULL(ctxt);
xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *)"n");
TEST_ASSERT_NOT_NULL(node);
ctxt->node = node;
ctxt->record_info = 0; /* disabled */
ctxt->input = NULL; /* would crash if accessed */
/* Provide a nodeInfo pointer; must not be used since record_info == 0 */
xmlParserNodeInfo *info = (xmlParserNodeInfo *)xmlMalloc(sizeof(xmlParserNodeInfo));
TEST_ASSERT_NOT_NULL(info);
memset(info, 0, sizeof(*info));
ctxt->nodeInfo = info;
test_htmlParserFinishElementParsing(ctxt);
/* Since recording is disabled, no node info should be present */
const xmlParserNodeInfo *found = xmlParserFindNodeInfo(ctxt, node);
TEST_ASSERT_NULL(found);
xmlFreeNode(node);
/* Do not free 'info' as it may be managed by internal pop logic in other cases. */
htmlFreeParserCtxt(ctxt);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_htmlParserFinishElementParsing_records_end_info_basic);
RUN_TEST(test_htmlParserFinishElementParsing_calculates_end_pos_with_consumed_offset);
RUN_TEST(test_htmlParserFinishElementParsing_noop_when_node_null);
RUN_TEST(test_htmlParserFinishElementParsing_noop_when_record_info_false_even_with_node);
return UNITY_END();
} |