|
|
#include "unity/unity.h" |
|
|
#include <libxml/HTMLparser.h> |
|
|
|
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
|
|
|
void test_htmlStartCharData(htmlParserCtxtPtr ctxt); |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
int start_count; |
|
|
int end_count; |
|
|
xmlChar* start_names[16]; |
|
|
xmlChar* end_names[16]; |
|
|
} TestSAXRec; |
|
|
|
|
|
static void recordStartElement(void *ctx, const xmlChar *name, const xmlChar **atts) { |
|
|
(void)atts; |
|
|
TestSAXRec *rec = (TestSAXRec *)ctx; |
|
|
if (rec == NULL) return; |
|
|
if (rec->start_count < (int)(sizeof(rec->start_names)/sizeof(rec->start_names[0]))) { |
|
|
rec->start_names[rec->start_count] = xmlStrdup(name); |
|
|
} |
|
|
rec->start_count++; |
|
|
} |
|
|
|
|
|
static void recordEndElement(void *ctx, const xmlChar *name) { |
|
|
TestSAXRec *rec = (TestSAXRec *)ctx; |
|
|
if (rec == NULL) return; |
|
|
if (rec->end_count < (int)(sizeof(rec->end_names)/sizeof(rec->end_names[0]))) { |
|
|
rec->end_names[rec->end_count] = xmlStrdup(name); |
|
|
} |
|
|
rec->end_count++; |
|
|
} |
|
|
|
|
|
static void freeRec(TestSAXRec *rec) { |
|
|
if (!rec) return; |
|
|
for (int i = 0; i < rec->start_count; i++) { |
|
|
if (rec->start_names[i]) xmlFree(rec->start_names[i]); |
|
|
rec->start_names[i] = NULL; |
|
|
} |
|
|
for (int i = 0; i < rec->end_count; i++) { |
|
|
if (rec->end_names[i]) xmlFree(rec->end_names[i]); |
|
|
rec->end_names[i] = NULL; |
|
|
} |
|
|
rec->start_count = 0; |
|
|
rec->end_count = 0; |
|
|
} |
|
|
|
|
|
static void initSAX(xmlSAXHandler *sax) { |
|
|
memset(sax, 0, sizeof(*sax)); |
|
|
sax->startElement = recordStartElement; |
|
|
sax->endElement = recordEndElement; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
xmlInitParser(); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
xmlCleanupParser(); |
|
|
} |
|
|
|
|
|
|
|
|
static htmlParserCtxtPtr create_ctxt_with_rec(TestSAXRec *rec) { |
|
|
htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "htmlNewParserCtxt failed"); |
|
|
static xmlSAXHandler sax; |
|
|
initSAX(&sax); |
|
|
ctxt->sax = &sax; |
|
|
ctxt->userData = rec; |
|
|
|
|
|
ctxt->name = NULL; |
|
|
ctxt->nameNr = 0; |
|
|
|
|
|
ctxt->options = 0; |
|
|
return ctxt; |
|
|
} |
|
|
|
|
|
|
|
|
void test_htmlStartCharData_returns_early_with_HTML5_option(void) { |
|
|
TestSAXRec rec; |
|
|
memset(&rec, 0, sizeof(rec)); |
|
|
htmlParserCtxtPtr ctxt = create_ctxt_with_rec(&rec); |
|
|
ctxt->options |= HTML_PARSE_HTML5; |
|
|
|
|
|
test_htmlStartCharData(ctxt); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rec.start_count); |
|
|
TEST_ASSERT_EQUAL_INT(0, rec.end_count); |
|
|
|
|
|
freeRec(&rec); |
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
|
|
|
void test_htmlStartCharData_returns_early_with_NOIMPLIED_option(void) { |
|
|
TestSAXRec rec; |
|
|
memset(&rec, 0, sizeof(rec)); |
|
|
htmlParserCtxtPtr ctxt = create_ctxt_with_rec(&rec); |
|
|
ctxt->options |= HTML_PARSE_NOIMPLIED; |
|
|
|
|
|
test_htmlStartCharData(ctxt); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rec.start_count); |
|
|
TEST_ASSERT_EQUAL_INT(0, rec.end_count); |
|
|
|
|
|
freeRec(&rec); |
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
|
|
|
void test_htmlStartCharData_implies_html_and_body_when_stack_empty(void) { |
|
|
TestSAXRec rec; |
|
|
memset(&rec, 0, sizeof(rec)); |
|
|
htmlParserCtxtPtr ctxt = create_ctxt_with_rec(&rec); |
|
|
|
|
|
ctxt->options = 0; |
|
|
|
|
|
ctxt->name = NULL; |
|
|
ctxt->nameNr = 0; |
|
|
|
|
|
test_htmlStartCharData(ctxt); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(2, rec.start_count); |
|
|
TEST_ASSERT_EQUAL_INT(0, rec.end_count); |
|
|
TEST_ASSERT_NOT_NULL(rec.start_names[0]); |
|
|
TEST_ASSERT_NOT_NULL(rec.start_names[1]); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "html", rec.start_names[0])); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "body", rec.start_names[1])); |
|
|
TEST_ASSERT_TRUE_MESSAGE(ctxt->nameNr >= 2, "Expected at least 2 elements on the stack"); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "body", ctxt->name)); |
|
|
|
|
|
freeRec(&rec); |
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
|
|
|
void test_htmlStartCharData_implies_body_when_only_html_present(void) { |
|
|
TestSAXRec rec; |
|
|
memset(&rec, 0, sizeof(rec)); |
|
|
htmlParserCtxtPtr ctxt = create_ctxt_with_rec(&rec); |
|
|
ctxt->options = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (ctxt->nameTab == NULL || ctxt->nameMax < 2) { |
|
|
|
|
|
ctxt->nameMax = 8; |
|
|
ctxt->nameTab = (const xmlChar **) xmlMalloc(ctxt->nameMax * sizeof(const xmlChar *)); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt->nameTab, "Failed to allocate nameTab"); |
|
|
} |
|
|
ctxt->nameNr = 1; |
|
|
ctxt->nameTab[0] = BAD_CAST "html"; |
|
|
ctxt->name = ctxt->nameTab[0]; |
|
|
|
|
|
test_htmlStartCharData(ctxt); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(1, rec.start_count); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "body", rec.start_names[0])); |
|
|
TEST_ASSERT_TRUE_MESSAGE(ctxt->nameNr >= 2, "Expected body to be pushed on the stack"); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "body", ctxt->name)); |
|
|
|
|
|
freeRec(&rec); |
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
|
|
|
void test_htmlStartCharData_no_duplication_when_body_present(void) { |
|
|
TestSAXRec rec; |
|
|
memset(&rec, 0, sizeof(rec)); |
|
|
htmlParserCtxtPtr ctxt = create_ctxt_with_rec(&rec); |
|
|
ctxt->options = 0; |
|
|
|
|
|
|
|
|
if (ctxt->nameTab == NULL || ctxt->nameMax < 2) { |
|
|
ctxt->nameMax = 8; |
|
|
ctxt->nameTab = (const xmlChar **) xmlMalloc(ctxt->nameMax * sizeof(const xmlChar *)); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt->nameTab, "Failed to allocate nameTab"); |
|
|
} |
|
|
ctxt->nameNr = 2; |
|
|
ctxt->nameTab[0] = BAD_CAST "html"; |
|
|
ctxt->nameTab[1] = BAD_CAST "body"; |
|
|
ctxt->name = ctxt->nameTab[1]; |
|
|
|
|
|
test_htmlStartCharData(ctxt); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rec.start_count); |
|
|
TEST_ASSERT_EQUAL_INT(0, rec.end_count); |
|
|
TEST_ASSERT_EQUAL_INT(2, ctxt->nameNr); |
|
|
TEST_ASSERT_TRUE(xmlStrEqual(BAD_CAST "body", ctxt->name)); |
|
|
|
|
|
freeRec(&rec); |
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_htmlStartCharData_returns_early_with_HTML5_option); |
|
|
RUN_TEST(test_htmlStartCharData_returns_early_with_NOIMPLIED_option); |
|
|
RUN_TEST(test_htmlStartCharData_implies_html_and_body_when_stack_empty); |
|
|
RUN_TEST(test_htmlStartCharData_implies_body_when_only_html_present); |
|
|
RUN_TEST(test_htmlStartCharData_no_duplication_when_body_present); |
|
|
return UNITY_END(); |
|
|
} |