| | #include "unity/unity.h" |
| | #include <libxml/HTMLparser.h> |
| |
|
| | #include <string.h> |
| | #include <stdlib.h> |
| | #include <stdio.h> |
| |
|
| | |
| | typedef struct { |
| | char buf[2048]; |
| | } EventLog; |
| |
|
| | static void log_append(EventLog *log, const char *s) { |
| | size_t cur = strlen(log->buf); |
| | size_t add = strlen(s); |
| | if (cur + add >= sizeof(log->buf)) { |
| | add = sizeof(log->buf) - cur - 1; |
| | } |
| | if (add > 0) { |
| | memcpy(log->buf + cur, s, add); |
| | log->buf[cur + add] = '\0'; |
| | } |
| | } |
| |
|
| | |
| | static void onStartElement(void *ctx, const xmlChar *name, const xmlChar **atts) { |
| | (void)atts; |
| | EventLog *log = (EventLog *)ctx; |
| | char tmp[256]; |
| | snprintf(tmp, sizeof(tmp), "[S:%s]", (const char *)name); |
| | log_append(log, tmp); |
| | } |
| |
|
| | static void onEndElement(void *ctx, const xmlChar *name) { |
| | EventLog *log = (EventLog *)ctx; |
| | char tmp[256]; |
| | snprintf(tmp, sizeof(tmp), "[E:%s]", (const char *)name); |
| | log_append(log, tmp); |
| | } |
| |
|
| | static void onCharacters(void *ctx, const xmlChar *ch, int len) { |
| | EventLog *log = (EventLog *)ctx; |
| | if (len <= 0) |
| | return; |
| | char tmp[512]; |
| | int copy = len; |
| | if (copy > (int)sizeof(tmp) - 1) |
| | copy = (int)sizeof(tmp) - 1; |
| | memcpy(tmp, ch, (size_t)copy); |
| | tmp[copy] = '\0'; |
| |
|
| | char out[600]; |
| | snprintf(out, sizeof(out), "[T:%s]", tmp); |
| | log_append(log, out); |
| | } |
| |
|
| | |
| | static xmlSAXHandler gSAX; |
| |
|
| | void setUp(void) { |
| | memset(&gSAX, 0, sizeof(gSAX)); |
| | gSAX.startElement = onStartElement; |
| | gSAX.endElement = onEndElement; |
| | gSAX.characters = onCharacters; |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | static void run_case(const char *html, int options, const char *expectedLog) { |
| | EventLog log; |
| | log.buf[0] = '\0'; |
| |
|
| | htmlParserCtxtPtr ctxt = htmlCreateMemoryParserCtxt(html, (int)strlen(html)); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "htmlCreateMemoryParserCtxt returned NULL"); |
| |
|
| | ctxt->sax = &gSAX; |
| | ctxt->userData = &log; |
| | ctxt->options = options; |
| |
|
| | htmlParseElement(ctxt); |
| |
|
| | TEST_ASSERT_EQUAL_STRING_MESSAGE(expectedLog, log.buf, "Unexpected SAX event sequence"); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| |
|
| | void test_htmlParseElement_null_context_safe(void) { |
| | |
| | htmlParseElement(NULL); |
| | TEST_ASSERT_TRUE(1); |
| | } |
| |
|
| | void test_htmlParseElement_empty_input_no_events(void) { |
| | run_case("", 0, ""); |
| | } |
| |
|
| | void test_htmlParseElement_parses_simple_element(void) { |
| | run_case("<p>hi</p>", 0, "[S:p][T:hi][E:p]"); |
| | } |
| |
|
| | void test_htmlParseElement_self_closing_xml_style_non_html5(void) { |
| | |
| | run_case("<br/>", 0, "[S:br][E:br]"); |
| | } |
| |
|
| | void test_htmlParseElement_self_closing_xml_style_html5(void) { |
| | |
| | run_case("<br/>", HTML_PARSE_HTML5, "[S:br]"); |
| | } |
| |
|
| | void test_htmlParseElement_dtd_empty_element_non_html5(void) { |
| | |
| | run_case("<br>", 0, "[S:br][E:br]"); |
| | } |
| |
|
| | void test_htmlParseElement_dtd_empty_element_html5(void) { |
| | |
| | run_case("<br>", HTML_PARSE_HTML5, "[S:br]"); |
| | } |
| |
|
| | void test_htmlParseElement_auto_close_on_eof_non_html5(void) { |
| | |
| | run_case("<div><span>t", 0, "[S:div][S:span][T:t][E:span][E:div]"); |
| | } |
| |
|
| | void test_htmlParseElement_auto_close_on_eof_html5(void) { |
| | |
| | run_case("<div><span>t", HTML_PARSE_HTML5, "[S:div][S:span][T:t]"); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_htmlParseElement_null_context_safe); |
| | RUN_TEST(test_htmlParseElement_empty_input_no_events); |
| | RUN_TEST(test_htmlParseElement_parses_simple_element); |
| | RUN_TEST(test_htmlParseElement_self_closing_xml_style_non_html5); |
| | RUN_TEST(test_htmlParseElement_self_closing_xml_style_html5); |
| | RUN_TEST(test_htmlParseElement_dtd_empty_element_non_html5); |
| | RUN_TEST(test_htmlParseElement_dtd_empty_element_html5); |
| | RUN_TEST(test_htmlParseElement_auto_close_on_eof_non_html5); |
| | RUN_TEST(test_htmlParseElement_auto_close_on_eof_html5); |
| | return UNITY_END(); |
| | } |