File size: 5,453 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 |
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <libxml/parser.h>
#include <stdlib.h>
#include <string.h>
/* Wrapper for the static function under test (provided in the module). */
extern void test_htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate);
/* Helpers */
static htmlParserCtxtPtr make_ctx_from_mem(const char *buf, int len) {
htmlParserCtxtPtr ctxt = htmlCreateMemoryParserCtxt(buf, len);
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML parser context");
/* Be permissive to avoid errors affecting the test */
(void)htmlCtxtUseOptions(ctxt, HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
return ctxt;
}
static size_t cur_offset(htmlParserCtxtPtr ctxt) {
return (size_t)(ctxt->input->cur - ctxt->input->base);
}
static size_t end_offset(htmlParserCtxtPtr ctxt) {
return (size_t)(ctxt->input->end - ctxt->input->base);
}
/* Unity hooks */
void setUp(void) {
/* Initialize library per test to be safe */
xmlInitParser();
}
void tearDown(void) {
/* No global cleanup here; contexts are freed in tests */
}
/* Tests */
void test_htmlParseTryOrFinish_start_nonterminate_small_avail_returns_early(void) {
const char *data = "abc"; /* less than 4 bytes */
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
TEST_ASSERT_EQUAL_INT(XML_PARSER_START, ctxt->instate);
size_t before_cur = cur_offset(ctxt);
test_htmlParseTryOrFinish(ctxt, 0);
/* Should not have progressed from START due to insufficient bytes and non-terminate */
TEST_ASSERT_EQUAL_INT(XML_PARSER_START, ctxt->instate);
TEST_ASSERT_EQUAL_size_t(before_cur, cur_offset(ctxt));
htmlFreeParserCtxt(ctxt);
}
void test_htmlParseTryOrFinish_start_terminate_progresses_and_consumes_text(void) {
const char *data = "abc";
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
size_t end = end_offset(ctxt);
test_htmlParseTryOrFinish(ctxt, 1);
/* Should have progressed into CONTENT and consumed the text */
TEST_ASSERT_EQUAL_INT(XML_PARSER_CONTENT, ctxt->instate);
TEST_ASSERT_EQUAL_size_t(end, cur_offset(ctxt));
/* endCheckState should be 0 after plain text consumption */
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
void test_htmlParseTryOrFinish_misc_to_start_tag_partial_nonterminate(void) {
/* 4 spaces ensure we pass START; "<p" triggers START_TAG with missing '>' */
const char *data = " <p";
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
test_htmlParseTryOrFinish(ctxt, 0);
/* With terminate == 0 and no '>', the function should return in START_TAG state */
TEST_ASSERT_EQUAL_INT(XML_PARSER_START_TAG, ctxt->instate);
/* htmlParseLookupGt should have set a non-zero checkIndex for rescanning */
TEST_ASSERT_TRUE(ctxt->checkIndex != 0);
/* Input cursor should not have consumed the '<p' (still at or before '<') */
/* We expect no advance past the '<' since we bailed out before parsing tag */
/* It's acceptable if whitespace was skipped while moving into MISC. Ensure not at end. */
TEST_ASSERT_TRUE(cur_offset(ctxt) < end_offset(ctxt));
htmlFreeParserCtxt(ctxt);
}
void test_htmlParseTryOrFinish_parses_comment_and_advances(void) {
const char *data = "<!--x-->";
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
size_t end = end_offset(ctxt);
test_htmlParseTryOrFinish(ctxt, 1);
/* Cursor should be at end after consuming the comment */
TEST_ASSERT_EQUAL_size_t(end, cur_offset(ctxt));
/* State likely remains in MISC or CONTENT; just ensure not EOF */
TEST_ASSERT_NOT_EQUAL_INT(XML_PARSER_EOF, ctxt->instate);
htmlFreeParserCtxt(ctxt);
}
void test_htmlParseTryOrFinish_parses_simple_element_and_end_tag_full_terminate(void) {
const char *data = "<p>Hi</p>";
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
size_t end = end_offset(ctxt);
test_htmlParseTryOrFinish(ctxt, 1);
/* Should have consumed the entire input */
TEST_ASSERT_EQUAL_size_t(end, cur_offset(ctxt));
/* Should be in CONTENT after handling tags and text */
TEST_ASSERT_EQUAL_INT(XML_PARSER_CONTENT, ctxt->instate);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
void test_htmlParseTryOrFinish_end_tag_only_transitions_and_consumes(void) {
const char *data = "</p>";
htmlParserCtxtPtr ctxt = make_ctx_from_mem(data, (int)strlen(data));
size_t end = end_offset(ctxt);
test_htmlParseTryOrFinish(ctxt, 1);
/* End tag should be consumed fully */
TEST_ASSERT_EQUAL_size_t(end, cur_offset(ctxt));
/* After processing end tag, parser returns to CONTENT */
TEST_ASSERT_EQUAL_INT(XML_PARSER_CONTENT, ctxt->instate);
htmlFreeParserCtxt(ctxt);
}
/* Main */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_htmlParseTryOrFinish_start_nonterminate_small_avail_returns_early);
RUN_TEST(test_htmlParseTryOrFinish_start_terminate_progresses_and_consumes_text);
RUN_TEST(test_htmlParseTryOrFinish_misc_to_start_tag_partial_nonterminate);
RUN_TEST(test_htmlParseTryOrFinish_parses_comment_and_advances);
RUN_TEST(test_htmlParseTryOrFinish_parses_simple_element_and_end_tag_full_terminate);
RUN_TEST(test_htmlParseTryOrFinish_end_tag_only_transitions_and_consumes);
return UNITY_END();
} |