#include "unity/unity.h" #include #include #include /* Wrapper for the static function under test (provided in the module) */ void test_htmlParseComment(htmlParserCtxtPtr ctxt, int bogus); /* Capture structure for SAX comment callback */ typedef struct { int count; char *last; } CommentCapture; static void free_capture(CommentCapture *cap) { if (cap->last) { free(cap->last); cap->last = NULL; } cap->count = 0; } static void comment_cb(void *ctx, const xmlChar *value) { CommentCapture *cap = (CommentCapture *)ctx; cap->count++; /* Copy the comment text into an owned buffer (ASCII-safe) */ const char *val = (const char *)value; size_t n = strlen(val); free_capture(cap); cap->last = (char *)malloc(n + 1); if (cap->last) { memcpy(cap->last, val, n + 1); } } /* Helper to create a parser context with given input buffer */ static htmlParserCtxtPtr make_ctxt(const char *data) { if (data == NULL) data = ""; int len = (int)strlen(data); htmlParserCtxtPtr ctxt = htmlCreateMemoryParserCtxt(data, len); return ctxt; } void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* Bogus comment: content is read until '>', which is then skipped */ void test_htmlParseComment_bogus_basic(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("hello>"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 1); TEST_ASSERT_EQUAL_INT(1, cap.count); TEST_ASSERT_NOT_NULL(cap.last); TEST_ASSERT_EQUAL_STRING("hello", cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Bogus comment without closing '>' should still emit collected content */ void test_htmlParseComment_bogus_no_terminator(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("noend"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 1); TEST_ASSERT_EQUAL_INT(1, cap.count); TEST_ASSERT_NOT_NULL(cap.last); TEST_ASSERT_EQUAL_STRING("noend", cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Non-bogus: immediate '>' produces an empty comment */ void test_htmlParseComment_nonbogus_immediate_gt(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt(">"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 0); TEST_ASSERT_EQUAL_INT(1, cap.count); TEST_ASSERT_NOT_NULL(cap.last); TEST_ASSERT_EQUAL_STRING("", cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Non-bogus: immediate "->" also produces an empty comment */ void test_htmlParseComment_nonbogus_immediate_arrow(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("->"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 0); TEST_ASSERT_EQUAL_INT(1, cap.count); TEST_ASSERT_NOT_NULL(cap.last); TEST_ASSERT_EQUAL_STRING("", cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Non-bogus: parse data until '-' is encountered; expect content before '-' */ void test_htmlParseComment_nonbogus_until_dash(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("abc-def->"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 0); TEST_ASSERT_EQUAL_INT(1, cap.count); TEST_ASSERT_NOT_NULL(cap.last); TEST_ASSERT_EQUAL_STRING("abc", cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Ensure no callback is emitted when SAX is disabled */ void test_htmlParseComment_SAX_disabled(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("ignored>"); TEST_ASSERT_NOT_NULL(ctxt); xmlSAXHandler sax; memset(&sax, 0, sizeof(sax)); sax.comment = comment_cb; ctxt->sax = &sax; ctxt->userData = ∩ ctxt->disableSAX = 1; /* Disable SAX */ test_htmlParseComment(ctxt, 1); TEST_ASSERT_EQUAL_INT(0, cap.count); TEST_ASSERT_NULL(cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } /* Ensure safe behavior when ctxt->sax is NULL */ void test_htmlParseComment_null_sax(void) { CommentCapture cap = {0, NULL}; htmlParserCtxtPtr ctxt = make_ctxt("hello>"); TEST_ASSERT_NOT_NULL(ctxt); ctxt->sax = NULL; /* No SAX handler */ ctxt->userData = ∩ ctxt->disableSAX = 0; test_htmlParseComment(ctxt, 1); TEST_ASSERT_EQUAL_INT(0, cap.count); TEST_ASSERT_NULL(cap.last); free_capture(&cap); htmlFreeParserCtxt(ctxt); } int main(void) { /* Initialize libxml2 parser library */ xmlInitParser(); UNITY_BEGIN(); RUN_TEST(test_htmlParseComment_bogus_basic); RUN_TEST(test_htmlParseComment_bogus_no_terminator); RUN_TEST(test_htmlParseComment_nonbogus_immediate_gt); RUN_TEST(test_htmlParseComment_nonbogus_immediate_arrow); RUN_TEST(test_htmlParseComment_nonbogus_until_dash); RUN_TEST(test_htmlParseComment_SAX_disabled); RUN_TEST(test_htmlParseComment_null_sax); int rc = UNITY_END(); /* Cleanup libxml2 global state */ xmlCleanupParser(); return rc; }