| | #include "unity/unity.h" |
| | #include <libxml/HTMLparser.h> |
| |
|
| | #include <stdlib.h> |
| | #include <string.h> |
| |
|
| | |
| | extern void test_htmlCharDataSAXCallback(htmlParserCtxtPtr ctxt, const xmlChar *buf, int size, int mode); |
| |
|
| | typedef struct { |
| | int chars_calls; |
| | int ign_calls; |
| | int cdata_calls; |
| | char chars_text[512]; |
| | char ign_text[512]; |
| | char cdata_text[512]; |
| | } Capture; |
| |
|
| | static void reset_capture(Capture *cap) { |
| | if (!cap) return; |
| | memset(cap, 0, sizeof(*cap)); |
| | } |
| |
|
| | static void cb_characters(void *userData, const xmlChar *ch, int len) { |
| | Capture *cap = (Capture *)userData; |
| | if (!cap || !ch || len <= 0) return; |
| | int copy = len; |
| | if (copy > (int)(sizeof(cap->chars_text) - 1 - (int)strlen(cap->chars_text))) |
| | copy = (int)(sizeof(cap->chars_text) - 1 - strlen(cap->chars_text)); |
| | strncat(cap->chars_text, (const char *)ch, copy); |
| | cap->chars_calls++; |
| | } |
| |
|
| | static void cb_ignorableWhitespace(void *userData, const xmlChar *ch, int len) { |
| | Capture *cap = (Capture *)userData; |
| | if (!cap || !ch || len <= 0) return; |
| | int copy = len; |
| | if (copy > (int)(sizeof(cap->ign_text) - 1 - (int)strlen(cap->ign_text))) |
| | copy = (int)(sizeof(cap->ign_text) - 1 - strlen(cap->ign_text)); |
| | strncat(cap->ign_text, (const char *)ch, copy); |
| | cap->ign_calls++; |
| | } |
| |
|
| | static void cb_cdataBlock(void *userData, const xmlChar *ch, int len) { |
| | Capture *cap = (Capture *)userData; |
| | if (!cap || !ch || len <= 0) return; |
| | int copy = len; |
| | if (copy > (int)(sizeof(cap->cdata_text) - 1 - (int)strlen(cap->cdata_text))) |
| | copy = (int)(sizeof(cap->cdata_text) - 1 - strlen(cap->cdata_text)); |
| | strncat(cap->cdata_text, (const char *)ch, copy); |
| | cap->cdata_calls++; |
| | } |
| |
|
| | static void prepare_sax(xmlSAXHandler *sax, |
| | xmlCharactersSAXFunc chars, |
| | xmlIgnorableWhitespaceSAXFunc ign, |
| | xmlCDataBlockSAXFunc cdata) { |
| | memset(sax, 0, sizeof(*sax)); |
| | sax->characters = chars; |
| | sax->ignorableWhitespace = ign; |
| | sax->cdataBlock = cdata; |
| | } |
| |
|
| | void setUp(void) { |
| | |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_null_sax(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | Capture cap; |
| | reset_capture(&cap); |
| |
|
| | ctxt->sax = NULL; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 0; |
| | ctxt->name = (const xmlChar *)"div"; |
| |
|
| | const char *data = "abc"; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), 0); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_disabled_sax(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, cb_cdataBlock); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 1; |
| | ctxt->keepBlanks = 0; |
| | ctxt->name = (const xmlChar *)"div"; |
| |
|
| | const char *data = "abc"; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), 0); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_html_leading_ws_keepBlanks_false(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, cb_cdataBlock); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 0; |
| | ctxt->name = (const xmlChar *)"html"; |
| |
|
| | const char *data = " \t\nabc"; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), 0); |
| |
|
| | TEST_ASSERT_EQUAL_INT(1, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_STRING(" \t\n", cap.ign_text); |
| |
|
| | TEST_ASSERT_EQUAL_INT(1, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_STRING("abc", cap.chars_text); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_head_leading_ws_keepBlanks_true(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, cb_cdataBlock); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 1; |
| | ctxt->name = (const xmlChar *)"head"; |
| |
|
| | const char *data = " abc"; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), 0); |
| |
|
| | TEST_ASSERT_EQUAL_INT(2, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_STRING(" abc", cap.chars_text); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_html_only_ws_keepBlanks_false(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, cb_cdataBlock); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 0; |
| | ctxt->name = (const xmlChar *)"html"; |
| |
|
| | const char *data = " "; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), 0); |
| |
|
| | TEST_ASSERT_EQUAL_INT(1, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_STRING(" ", cap.ign_text); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_cdata_mode_nonzero(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, cb_cdataBlock); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 0; |
| | ctxt->name = (const xmlChar *)"div"; |
| |
|
| | const char *data = " CDATA <kept> "; |
| | |
| | int mode = 9999; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), mode); |
| |
|
| | TEST_ASSERT_EQUAL_INT(0, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_INT(1, cap.cdata_calls); |
| | TEST_ASSERT_EQUAL_STRING(" CDATA <kept> ", cap.cdata_text); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | |
| | void test_htmlCharDataSAXCallback_nonzero_mode_no_cdataBlock_falls_back(void) { |
| | htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
| | TEST_ASSERT_NOT_NULL(ctxt); |
| |
|
| | xmlSAXHandler sax; |
| | Capture cap; |
| | reset_capture(&cap); |
| | |
| | prepare_sax(&sax, cb_characters, cb_ignorableWhitespace, NULL); |
| |
|
| | ctxt->sax = &sax; |
| | ctxt->userData = ∩ |
| | ctxt->disableSAX = 0; |
| | ctxt->keepBlanks = 1; |
| | ctxt->name = (const xmlChar *)"div"; |
| |
|
| | const char *data = "abc"; |
| | int mode = 9999; |
| | test_htmlCharDataSAXCallback(ctxt, (const xmlChar *)data, (int)strlen(data), mode); |
| |
|
| | TEST_ASSERT_EQUAL_INT(1, cap.chars_calls); |
| | TEST_ASSERT_EQUAL_STRING("abc", cap.chars_text); |
| | TEST_ASSERT_EQUAL_INT(0, cap.ign_calls); |
| | TEST_ASSERT_EQUAL_INT(0, cap.cdata_calls); |
| |
|
| | htmlFreeParserCtxt(ctxt); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_htmlCharDataSAXCallback_null_sax); |
| | RUN_TEST(test_htmlCharDataSAXCallback_disabled_sax); |
| | RUN_TEST(test_htmlCharDataSAXCallback_html_leading_ws_keepBlanks_false); |
| | RUN_TEST(test_htmlCharDataSAXCallback_head_leading_ws_keepBlanks_true); |
| | RUN_TEST(test_htmlCharDataSAXCallback_html_only_ws_keepBlanks_false); |
| | RUN_TEST(test_htmlCharDataSAXCallback_cdata_mode_nonzero); |
| | RUN_TEST(test_htmlCharDataSAXCallback_nonzero_mode_no_cdataBlock_falls_back); |
| | return UNITY_END(); |
| | } |