libxml / tests /tests_HTMLparser_htmlCheckImplied.c
AryaWu's picture
Upload folder using huggingface_hub
6baed57 verified
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <stdlib.h>
#include <string.h>
/* Wrapper for the static function provided in the module */
extern void test_htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag);
typedef struct {
char **names;
int count;
int capacity;
} Capture;
static char *xstrdup(const char *s) {
if (s == NULL) return NULL;
size_t len = strlen(s) + 1;
char *d = (char *)malloc(len);
if (d) memcpy(d, s, len);
return d;
}
static void cap_init(Capture *cap) {
cap->names = NULL;
cap->count = 0;
cap->capacity = 0;
}
static void cap_add(Capture *cap, const char *name) {
if (cap->count == cap->capacity) {
int newcap = (cap->capacity == 0) ? 4 : cap->capacity * 2;
char **nn = (char **)realloc(cap->names, (size_t)newcap * sizeof(char *));
if (!nn) return; /* keep silent; tests will fail if memory is out */
cap->names = nn;
cap->capacity = newcap;
}
cap->names[cap->count++] = xstrdup(name);
}
static void cap_free(Capture *cap) {
if (cap->names) {
for (int i = 0; i < cap->count; i++) {
free(cap->names[i]);
}
free(cap->names);
}
cap->names = NULL;
cap->count = 0;
cap->capacity = 0;
}
static void testStartElement(void *userData, const xmlChar *name, const xmlChar **atts) {
(void)atts;
Capture *cap = (Capture *)userData;
cap_add(cap, (const char *)name);
}
static htmlParserCtxtPtr new_ctxt(Capture *cap, xmlSAXHandlerPtr *out_sax) {
xmlSAXHandler *sax = (xmlSAXHandler *)calloc(1, sizeof(xmlSAXHandler));
if (sax == NULL) return NULL;
memset(sax, 0, sizeof(xmlSAXHandler));
sax->startElement = testStartElement;
htmlParserCtxtPtr ctxt = htmlCreatePushParserCtxt(sax, cap, "", 0, NULL, XML_CHAR_ENCODING_NONE);
if (out_sax) *out_sax = sax;
return ctxt;
}
static void free_ctxt(htmlParserCtxtPtr ctxt, xmlSAXHandlerPtr sax, Capture *cap) {
if (ctxt) htmlFreeParserCtxt(ctxt);
if (sax) free(sax);
if (cap) cap_free(cap);
}
/* Unity hooks */
void setUp(void) {
/* No global setup needed */
}
void tearDown(void) {
/* No global teardown needed */
}
/* Tests */
void test_htmlCheckImplied_with_p_generates_html_and_body(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"p");
TEST_ASSERT_EQUAL_INT(2, cap.count);
TEST_ASSERT_NOT_NULL(cap.names[0]);
TEST_ASSERT_NOT_NULL(cap.names[1]);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
TEST_ASSERT_EQUAL_STRING("body", cap.names[1]);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_with_head_generates_only_html(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"head");
TEST_ASSERT_EQUAL_INT(1, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_with_html_generates_nothing(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"html");
TEST_ASSERT_EQUAL_INT(0, cap.count);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_with_script_generates_html_and_head(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"script");
TEST_ASSERT_TRUE(cap.count >= 1);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
/* Expect head generation in initial state */
TEST_ASSERT_EQUAL_INT(2, cap.count);
TEST_ASSERT_EQUAL_STRING("head", cap.names[1]);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_subsequent_p_does_not_generate_body_if_head_present(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
/* First call with script: should push html + head */
test_htmlCheckImplied(ctxt, (const xmlChar *)"script");
TEST_ASSERT_EQUAL_INT(2, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
TEST_ASSERT_EQUAL_STRING("head", cap.names[1]);
/* Second call with p: should not generate body since head is on the stack */
test_htmlCheckImplied(ctxt, (const xmlChar *)"p");
TEST_ASSERT_EQUAL_INT(2, cap.count); /* no new events */
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_no_duplicate_body_on_subsequent_calls(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
/* First call with p: expect html + body */
test_htmlCheckImplied(ctxt, (const xmlChar *)"p");
TEST_ASSERT_EQUAL_INT(2, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
TEST_ASSERT_EQUAL_STRING("body", cap.names[1]);
/* Second call with span: body already on stack, so nothing new */
test_htmlCheckImplied(ctxt, (const xmlChar *)"span");
TEST_ASSERT_EQUAL_INT(2, cap.count);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_frame_like_tags_do_not_generate_body(void) {
/* frame */
{
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"frame");
TEST_ASSERT_EQUAL_INT(1, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
free_ctxt(ctxt, sax, &cap);
}
/* frameset */
{
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"frameset");
TEST_ASSERT_EQUAL_INT(1, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
free_ctxt(ctxt, sax, &cap);
}
/* noframes */
{
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
test_htmlCheckImplied(ctxt, (const xmlChar *)"noframes");
TEST_ASSERT_EQUAL_INT(1, cap.count);
TEST_ASSERT_EQUAL_STRING("html", cap.names[0]);
free_ctxt(ctxt, sax, &cap);
}
}
void test_htmlCheckImplied_noimplied_option_suppresses_generation(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
/* Set NOIMPLIED option */
int rc = htmlCtxtUseOptions(ctxt, HTML_PARSE_NOIMPLIED);
(void)rc;
test_htmlCheckImplied(ctxt, (const xmlChar *)"p");
/* No implied insertions should occur */
TEST_ASSERT_EQUAL_INT(0, cap.count);
free_ctxt(ctxt, sax, &cap);
}
void test_htmlCheckImplied_html5_option_suppresses_generation(void) {
Capture cap; cap_init(&cap);
xmlSAXHandlerPtr sax = NULL;
htmlParserCtxtPtr ctxt = new_ctxt(&cap, &sax);
TEST_ASSERT_NOT_NULL(ctxt);
/* Set HTML5 option */
int rc = htmlCtxtUseOptions(ctxt, HTML_PARSE_HTML5);
(void)rc;
test_htmlCheckImplied(ctxt, (const xmlChar *)"p");
/* No implied insertions should occur */
TEST_ASSERT_EQUAL_INT(0, cap.count);
free_ctxt(ctxt, sax, &cap);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_htmlCheckImplied_with_p_generates_html_and_body);
RUN_TEST(test_htmlCheckImplied_with_head_generates_only_html);
RUN_TEST(test_htmlCheckImplied_with_html_generates_nothing);
RUN_TEST(test_htmlCheckImplied_with_script_generates_html_and_head);
RUN_TEST(test_htmlCheckImplied_subsequent_p_does_not_generate_body_if_head_present);
RUN_TEST(test_htmlCheckImplied_no_duplicate_body_on_subsequent_calls);
RUN_TEST(test_htmlCheckImplied_frame_like_tags_do_not_generate_body);
RUN_TEST(test_htmlCheckImplied_noimplied_option_suppresses_generation);
RUN_TEST(test_htmlCheckImplied_html5_option_suppresses_generation);
return UNITY_END();
}