| | #include "unity/unity.h" |
| | #include <libxml/HTMLtree.h> |
| |
|
| | #include <libxml/tree.h> |
| | #include <libxml/xmlIO.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| |
|
| | |
| | void test_htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlAttrPtr cur); |
| |
|
| | |
| | typedef struct { |
| | char *data; |
| | size_t len; |
| | size_t cap; |
| | } Accum; |
| |
|
| | static void Accum_init(Accum *a) { |
| | a->data = NULL; |
| | a->len = 0; |
| | a->cap = 0; |
| | } |
| |
|
| | static void Accum_free(Accum *a) { |
| | free(a->data); |
| | a->data = NULL; |
| | a->len = 0; |
| | a->cap = 0; |
| | } |
| |
|
| | static int acc_write(void *context, const char *buffer, int len) { |
| | Accum *a = (Accum *)context; |
| | if (len <= 0) |
| | return 0; |
| | size_t need = a->len + (size_t)len + 1; |
| | if (need > a->cap) { |
| | size_t newcap = a->cap ? a->cap : 64; |
| | while (newcap < need) |
| | newcap *= 2; |
| | char *nd = (char *)realloc(a->data, newcap); |
| | if (nd == NULL) |
| | return -1; |
| | a->data = nd; |
| | a->cap = newcap; |
| | } |
| | memcpy(a->data + a->len, buffer, (size_t)len); |
| | a->len += (size_t)len; |
| | a->data[a->len] = '\0'; |
| | return len; |
| | } |
| |
|
| | static int acc_close(void *context) { |
| | (void)context; |
| | return 0; |
| | } |
| |
|
| | static xmlOutputBufferPtr makeOutputBuffer(Accum *a) { |
| | Accum_init(a); |
| | xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(acc_write, acc_close, a, NULL); |
| | return buf; |
| | } |
| |
|
| | void setUp(void) { |
| | |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | static void make_doc_and_root(const char *rootName, xmlDocPtr *pdoc, xmlNodePtr *proot) { |
| | xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(doc, "xmlNewDoc failed"); |
| | xmlNodePtr root = xmlNewNode(NULL, BAD_CAST rootName); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(root, "xmlNewNode failed"); |
| | xmlDocSetRootElement(doc, root); |
| | *pdoc = doc; |
| | *proot = root; |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_basic_escape_text(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("div", &doc, &node); |
| |
|
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "title", BAD_CAST "Tom & \"Jerry\""); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " title=\"Tom & "Jerry"\""; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_boolean_selected_lowercase(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("option", &doc, &node); |
| |
|
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "selected", BAD_CAST "selected"); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " selected"; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_boolean_selected_uppercase(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("option", &doc, &node); |
| |
|
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "SELECTED", BAD_CAST "true"); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " SELECTED"; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_null_value_no_children(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("div", &doc, &node); |
| |
|
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "data", NULL); |
| | TEST_ASSERT_NOT_NULL(attr); |
| | TEST_ASSERT_NULL(attr->children); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " data"; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_namespaced_attr_with_escape(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("div", &doc, &node); |
| |
|
| | xmlNsPtr ns = xmlNewNs(node, BAD_CAST "http://example.com/ns", BAD_CAST "p"); |
| | TEST_ASSERT_NOT_NULL(ns); |
| |
|
| | xmlAttrPtr attr = xmlNewNsProp(node, ns, BAD_CAST "id", BAD_CAST "alpha&beta"); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " p:id=\"alpha&beta\""; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_uri_href_serialization(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("a", &doc, &node); |
| |
|
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "href", BAD_CAST " Ab c&\"Z"); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " href=\" Ab%20c&"Z\""; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | |
| | void test_htmlAttrDumpOutput_entity_ref_in_value(void) { |
| | xmlDocPtr doc = NULL; |
| | xmlNodePtr node = NULL; |
| | make_doc_and_root("div", &doc, &node); |
| |
|
| | |
| | xmlAttrPtr attr = xmlNewProp(node, BAD_CAST "data", NULL); |
| | TEST_ASSERT_NOT_NULL(attr); |
| |
|
| | xmlNodePtr t1 = xmlNewText(BAD_CAST "X"); |
| | xmlNodePtr ref = xmlNewReference(doc, BAD_CAST "copy"); |
| | xmlNodePtr t2 = xmlNewText(BAD_CAST "Y"); |
| | TEST_ASSERT_NOT_NULL(t1); |
| | TEST_ASSERT_NOT_NULL(ref); |
| | TEST_ASSERT_NOT_NULL(t2); |
| |
|
| | |
| | xmlAddChild((xmlNodePtr)attr, t1); |
| | xmlAddChild((xmlNodePtr)attr, ref); |
| | xmlAddChild((xmlNodePtr)attr, t2); |
| |
|
| | Accum acc; |
| | xmlOutputBufferPtr buf = makeOutputBuffer(&acc); |
| | TEST_ASSERT_NOT_NULL(buf); |
| |
|
| | test_htmlAttrDumpOutput(buf, attr); |
| | xmlOutputBufferFlush(buf); |
| | xmlOutputBufferClose(buf); |
| |
|
| | const char *expected = " data=\"X©Y\""; |
| | TEST_ASSERT_NOT_NULL(acc.data); |
| | TEST_ASSERT_EQUAL_STRING(expected, acc.data); |
| |
|
| | Accum_free(&acc); |
| | xmlFreeDoc(doc); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_htmlAttrDumpOutput_basic_escape_text); |
| | RUN_TEST(test_htmlAttrDumpOutput_boolean_selected_lowercase); |
| | RUN_TEST(test_htmlAttrDumpOutput_boolean_selected_uppercase); |
| | RUN_TEST(test_htmlAttrDumpOutput_null_value_no_children); |
| | RUN_TEST(test_htmlAttrDumpOutput_namespaced_attr_with_escape); |
| | RUN_TEST(test_htmlAttrDumpOutput_uri_href_serialization); |
| | RUN_TEST(test_htmlAttrDumpOutput_entity_ref_in_value); |
| | return UNITY_END(); |
| | } |