|
|
#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(); |
|
|
} |