|
|
#include "unity/unity.h" |
|
|
#include <libxml/HTMLparser.h> |
|
|
#include <libxml/parser.h> |
|
|
#include <libxml/xmlerror.h> |
|
|
#include <libxml/encoding.h> |
|
|
|
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
int startCount; |
|
|
int endCount; |
|
|
int charsCount; |
|
|
char collected[512]; |
|
|
size_t collectedLen; |
|
|
} TestSAXState; |
|
|
|
|
|
|
|
|
static void test_startDocument(void *ctx) { |
|
|
TestSAXState *st = (TestSAXState *)ctx; |
|
|
st->startCount++; |
|
|
} |
|
|
|
|
|
static void test_endDocument(void *ctx) { |
|
|
TestSAXState *st = (TestSAXState *)ctx; |
|
|
st->endCount++; |
|
|
} |
|
|
|
|
|
static void test_characters(void *ctx, const xmlChar *ch, int len) { |
|
|
TestSAXState *st = (TestSAXState *)ctx; |
|
|
if (st->collectedLen + (size_t)len >= sizeof(st->collected)) |
|
|
len = (int)(sizeof(st->collected) - st->collectedLen - 1); |
|
|
if (len > 0) { |
|
|
memcpy(st->collected + st->collectedLen, ch, (size_t)len); |
|
|
st->collectedLen += (size_t)len; |
|
|
st->collected[st->collectedLen] = '\0'; |
|
|
} |
|
|
st->charsCount++; |
|
|
} |
|
|
|
|
|
|
|
|
static htmlParserCtxtPtr create_push_ctxt(TestSAXState *state) { |
|
|
xmlSAXHandler sax; |
|
|
memset(&sax, 0, sizeof(sax)); |
|
|
sax.startDocument = test_startDocument; |
|
|
sax.endDocument = test_endDocument; |
|
|
sax.characters = test_characters; |
|
|
|
|
|
htmlParserCtxtPtr ctxt = htmlCreatePushParserCtxt(&sax, state, NULL, 0, NULL, XML_CHAR_ENCODING_NONE); |
|
|
return ctxt; |
|
|
} |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
xmlInitParser(); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void test_htmlParseChunk_invalid_arguments(void) { |
|
|
|
|
|
int ret = htmlParseChunk(NULL, "x", 1, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_ARGUMENT, ret); |
|
|
|
|
|
|
|
|
TestSAXState st; |
|
|
memset(&st, 0, sizeof(st)); |
|
|
htmlParserCtxtPtr ctxt = create_push_ctxt(&st); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
TEST_ASSERT_NOT_NULL(ctxt->input); |
|
|
TEST_ASSERT_NOT_NULL(ctxt->input->buf); |
|
|
|
|
|
|
|
|
ret = htmlParseChunk(ctxt, NULL, 1, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_ARGUMENT, ret); |
|
|
|
|
|
|
|
|
ret = htmlParseChunk(ctxt, "x", -5, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_ARGUMENT, ret); |
|
|
|
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
static void test_htmlParseChunk_partial_then_resume_starts_document(void) { |
|
|
TestSAXState st; |
|
|
memset(&st, 0, sizeof(st)); |
|
|
htmlParserCtxtPtr ctxt = create_push_ctxt(&st); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
|
|
|
int ret = htmlParseChunk(ctxt, "<", 1, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_OK, ret); |
|
|
TEST_ASSERT_EQUAL_INT(0, st.startCount); |
|
|
TEST_ASSERT_EQUAL_INT(0, st.endCount); |
|
|
|
|
|
|
|
|
ret = htmlParseChunk(ctxt, "html>", 5, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_OK, ret); |
|
|
TEST_ASSERT_EQUAL_INT(1, st.startCount); |
|
|
TEST_ASSERT_EQUAL_INT(0, st.endCount); |
|
|
|
|
|
|
|
|
st.collectedLen = 0; |
|
|
st.collected[0] = '\0'; |
|
|
ret = htmlParseChunk(ctxt, "<body>Hi", 9, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_OK, ret); |
|
|
TEST_ASSERT_TRUE(st.charsCount >= 1); |
|
|
TEST_ASSERT_NOT_NULL(strstr(st.collected, "Hi")); |
|
|
|
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
static void test_htmlParseChunk_terminate_calls_endDocument(void) { |
|
|
TestSAXState st; |
|
|
memset(&st, 0, sizeof(st)); |
|
|
htmlParserCtxtPtr ctxt = create_push_ctxt(&st); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
|
|
|
const char *chunk1 = "<!DOCTYPE html><html><body>Hello"; |
|
|
int ret = htmlParseChunk(ctxt, chunk1, (int)strlen(chunk1), 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_OK, ret); |
|
|
TEST_ASSERT_EQUAL_INT(1, st.startCount); |
|
|
TEST_ASSERT_EQUAL_INT(0, st.endCount); |
|
|
|
|
|
|
|
|
ret = htmlParseChunk(ctxt, NULL, 0, 1); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_OK, ret); |
|
|
TEST_ASSERT_EQUAL_INT(1, st.endCount); |
|
|
|
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
static void test_htmlParseChunk_respects_stop_parser(void) { |
|
|
TestSAXState st; |
|
|
memset(&st, 0, sizeof(st)); |
|
|
htmlParserCtxtPtr ctxt = create_push_ctxt(&st); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
|
|
|
xmlStopParser(ctxt); |
|
|
|
|
|
int ret = htmlParseChunk(ctxt, "<html>", 6, 0); |
|
|
TEST_ASSERT_EQUAL_INT(XML_ERR_USER_STOP, ret); |
|
|
|
|
|
htmlFreeParserCtxt(ctxt); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_htmlParseChunk_invalid_arguments); |
|
|
RUN_TEST(test_htmlParseChunk_partial_then_resume_starts_document); |
|
|
RUN_TEST(test_htmlParseChunk_terminate_calls_endDocument); |
|
|
RUN_TEST(test_htmlParseChunk_respects_stop_parser); |
|
|
int rc = UNITY_END(); |
|
|
xmlCleanupParser(); |
|
|
return rc; |
|
|
} |