| | #include "unity/unity.h" |
| | #include <libxml/HTMLparser.h> |
| |
|
| | #include <string.h> |
| | #include <stdlib.h> |
| |
|
| | |
| | extern int test_htmlParseElementInternal(htmlParserCtxtPtr ctxt); |
| |
|
| | typedef struct { |
| | int startCount; |
| | int endCount; |
| | char lastStart[64]; |
| | char lastEnd[64]; |
| | } TestSaxCounters; |
| |
|
| | static void sax_start(void *ctx, const xmlChar *name, const xmlChar **atts) { |
| | (void)atts; |
| | TestSaxCounters *c = (TestSaxCounters *)ctx; |
| | c->startCount++; |
| | if (name != NULL) { |
| | strncpy(c->lastStart, (const char *)name, sizeof(c->lastStart) - 1); |
| | c->lastStart[sizeof(c->lastStart) - 1] = '\0'; |
| | } |
| | } |
| |
|
| | static void sax_end(void *ctx, const xmlChar *name) { |
| | TestSaxCounters *c = (TestSaxCounters *)ctx; |
| | c->endCount++; |
| | if (name != NULL) { |
| | strncpy(c->lastEnd, (const char *)name, sizeof(c->lastEnd) - 1); |
| | c->lastEnd[sizeof(c->lastEnd) - 1] = '\0'; |
| | } |
| | } |
| |
|
| | static htmlParserCtxtPtr make_ctxt_with_input(const char *input, |
| | int use_html5, |
| | xmlSAXHandler *sax, |
| | void *user) { |
| | htmlParserCtxtPtr ctxt = htmlCreatePushParserCtxt(sax, user, |
| | input, |
| | (int)strlen(input), |
| | NULL, |
| | XML_CHAR_ENCODING_NONE); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML push parser context"); |
| | if (use_html5) { |
| | ctxt->options |= HTML_PARSE_HTML5; |
| | } |
| | return ctxt; |
| | } |
| |
|
| | void setUp(void) { |
| | xmlInitParser(); |
| | } |
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| |
|
| | void test_htmlParseElementInternal_null_context_returns_0(void) { |
| | int ret = test_htmlParseElementInternal(NULL); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| | } |
| |
|
| | void test_htmlParseElementInternal_null_input_returns_0(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| | |
| | TEST_ASSERT_NULL(ctxt->input); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_nonempty_tag_returns_1_and_callbacks(void) { |
| | const char *src = "<div>"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 0, &sax, &counters); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(1, ret); |
| | TEST_ASSERT_EQUAL_INT(1, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(0, counters.endCount); |
| | TEST_ASSERT_EQUAL_STRING("div", counters.lastStart); |
| |
|
| | |
| | TEST_ASSERT_NOT_NULL(ctxt->name); |
| | TEST_ASSERT_TRUE(xmlStrEqual(ctxt->name, BAD_CAST "div")); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_self_closing_non_html5_calls_endElement_and_returns_0(void) { |
| | const char *src = "<input/>"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 0, &sax, &counters); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| | TEST_ASSERT_EQUAL_INT(1, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(1, counters.endCount); |
| | TEST_ASSERT_EQUAL_STRING("input", counters.lastStart); |
| | TEST_ASSERT_EQUAL_STRING("input", counters.lastEnd); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_self_closing_html5_does_not_call_endElement_returns_0(void) { |
| | const char *src = "<input/>"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 1, &sax, &counters); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| | TEST_ASSERT_EQUAL_INT(1, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(0, counters.endCount); |
| | TEST_ASSERT_EQUAL_STRING("input", counters.lastStart); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_dtd_empty_without_solidus_returns_0_and_calls_end(void) { |
| | const char *src = "<br>"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 0, &sax, &counters); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| | TEST_ASSERT_EQUAL_INT(1, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(1, counters.endCount); |
| | TEST_ASSERT_EQUAL_STRING("br", counters.lastStart); |
| | TEST_ASSERT_EQUAL_STRING("br", counters.lastEnd); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_missing_gt_returns_0_and_no_callbacks(void) { |
| | const char *src = "<div"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 0, &sax, &counters); |
| |
|
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(0, ret); |
| | TEST_ASSERT_EQUAL_INT(0, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(0, counters.endCount); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | void test_htmlParseElementInternal_unknown_tag_keeps_endCheckState_zero_returns_1(void) { |
| | const char *src = "<custom>"; |
| | xmlSAXHandler sax; |
| | memset(&sax, 0, sizeof(sax)); |
| | sax.startElement = sax_start; |
| | sax.endElement = sax_end; |
| |
|
| | TestSaxCounters counters = {0}; |
| | htmlParserCtxtPtr ctxt = make_ctxt_with_input(src, 0, &sax, &counters); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); |
| | int ret = test_htmlParseElementInternal(ctxt); |
| | TEST_ASSERT_EQUAL_INT(1, ret); |
| | TEST_ASSERT_EQUAL_INT(1, counters.startCount); |
| | TEST_ASSERT_EQUAL_INT(0, counters.endCount); |
| | TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_htmlParseElementInternal_null_context_returns_0); |
| | RUN_TEST(test_htmlParseElementInternal_null_input_returns_0); |
| | RUN_TEST(test_htmlParseElementInternal_nonempty_tag_returns_1_and_callbacks); |
| | RUN_TEST(test_htmlParseElementInternal_self_closing_non_html5_calls_endElement_and_returns_0); |
| | RUN_TEST(test_htmlParseElementInternal_self_closing_html5_does_not_call_endElement_returns_0); |
| | RUN_TEST(test_htmlParseElementInternal_dtd_empty_without_solidus_returns_0_and_calls_end); |
| | RUN_TEST(test_htmlParseElementInternal_missing_gt_returns_0_and_no_callbacks); |
| | RUN_TEST(test_htmlParseElementInternal_unknown_tag_keeps_endCheckState_zero_returns_1); |
| | return UNITY_END(); |
| | } |