#include "unity/unity.h" #include #include #include /* Wrapper provided in the module for calling the static function */ int test_htmlParseLookupGt(xmlParserCtxtPtr ctxt); /* Unity hooks */ void setUp(void) { /* No per-test setup needed */ } void tearDown(void) { /* No per-test teardown needed */ } /* Helper to create an HTML parser context from a C string */ static htmlParserCtxtPtr make_ctx(const char *s) { int len = (int)strlen(s); htmlParserCtxtPtr ctxt = htmlCreateMemoryParserCtxt(s, len); TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML parser context"); TEST_ASSERT_NOT_NULL_MESSAGE(ctxt->input, "Parser input is NULL"); /* Ensure cur starts at the beginning of the buffer for our tests */ if (ctxt->input->base != NULL) ctxt->input->cur = ctxt->input->base; return ctxt; } /* Basic tag: should find '>' immediately */ void test_htmlParseLookupGt_basic_tag(void) { htmlParserCtxtPtr ctxt = make_ctx(""); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* Tag with attributes and spaces before closing '>' */ void test_htmlParseLookupGt_attrs_and_spaces(void) { htmlParserCtxtPtr ctxt = make_ctx(""); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* '>' inside single-quoted attribute value must not terminate the tag */ void test_htmlParseLookupGt_gt_inside_single_quotes(void) { htmlParserCtxtPtr ctxt = make_ctx(""); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* '>' inside double-quoted attribute value must not terminate the tag */ void test_htmlParseLookupGt_gt_inside_double_quotes(void) { htmlParserCtxtPtr ctxt = make_ctx(" not end\" data=\"x\">"); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* Incomplete tag: no closing '>' in buffer */ void test_htmlParseLookupGt_incomplete_no_gt(void) { const char *buf = "checkIndex = 0; ctxt->endCheckState = 0; size_t expectedIndex = (size_t)(ctxt->input->end - ctxt->input->cur); int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(-1, ret); TEST_ASSERT_EQUAL_size_t(expectedIndex, ctxt->checkIndex); /* endCheckState is implementation-defined but should be preserved and non-negative */ TEST_ASSERT_TRUE(ctxt->endCheckState >= 0); htmlFreeParserCtxt(ctxt); } /* Repeated call on the same incomplete buffer should be idempotent */ void test_htmlParseLookupGt_incomplete_repeat_call_stable(void) { const char *buf = "checkIndex = 0; ctxt->endCheckState = 0; size_t expectedIndex = (size_t)(ctxt->input->end - ctxt->input->cur); int ret1 = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(-1, ret1); int savedState = ctxt->endCheckState; size_t savedIndex = ctxt->checkIndex; int ret2 = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(-1, ret2); TEST_ASSERT_EQUAL_size_t(expectedIndex, ctxt->checkIndex); TEST_ASSERT_EQUAL_size_t(savedIndex, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(savedState, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* Resume scanning across buffers: first incomplete, then complete */ void test_htmlParseLookupGt_resume_scanning_across_buffers(void) { const char *part1 = "checkIndex = 0; ctxt1->endCheckState = 0; int ret1 = test_htmlParseLookupGt(ctxt1); TEST_ASSERT_EQUAL_INT(-1, ret1); size_t savedIndex = ctxt1->checkIndex; int savedState = ctxt1->endCheckState; htmlFreeParserCtxt(ctxt1); /* Now, new buffer that continues and closes the tag */ htmlParserCtxtPtr ctxt2 = make_ctx(part2); ctxt2->checkIndex = savedIndex; /* resume offset */ ctxt2->endCheckState = savedState; /* resume state */ int ret2 = test_htmlParseLookupGt(ctxt2); TEST_ASSERT_EQUAL_INT(0, ret2); TEST_ASSERT_EQUAL_UINT(0, ctxt2->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt2->endCheckState); htmlFreeParserCtxt(ctxt2); } /* Closing tag should be handled correctly */ void test_htmlParseLookupGt_closing_tag(void) { htmlParserCtxtPtr ctxt = make_ctx(""); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } /* Self-closing tag with '/' before '>' */ void test_htmlParseLookupGt_self_closing(void) { htmlParserCtxtPtr ctxt = make_ctx("x"); ctxt->checkIndex = 0; ctxt->endCheckState = 0; int ret = test_htmlParseLookupGt(ctxt); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex); TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); htmlFreeParserCtxt(ctxt); } int main(void) { UNITY_BEGIN(); xmlInitParser(); RUN_TEST(test_htmlParseLookupGt_basic_tag); RUN_TEST(test_htmlParseLookupGt_attrs_and_spaces); RUN_TEST(test_htmlParseLookupGt_gt_inside_single_quotes); RUN_TEST(test_htmlParseLookupGt_gt_inside_double_quotes); RUN_TEST(test_htmlParseLookupGt_incomplete_no_gt); RUN_TEST(test_htmlParseLookupGt_incomplete_repeat_call_stable); RUN_TEST(test_htmlParseLookupGt_resume_scanning_across_buffers); RUN_TEST(test_htmlParseLookupGt_closing_tag); RUN_TEST(test_htmlParseLookupGt_self_closing); xmlCleanupParser(); return UNITY_END(); }