#include "unity/unity.h" #include #include #include /* Forward declaration in case it's not exposed by the public header. */ int htmlAutoCloseTag(xmlDoc *doc, const xmlChar *name, xmlNode *elem); static xmlDocPtr make_doc_with_root(const char *rootName, xmlNodePtr *outRoot) { xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0"); TEST_ASSERT_NOT_NULL_MESSAGE(doc, "xmlNewDoc failed"); xmlNodePtr root = xmlNewNode(NULL, (const xmlChar *)rootName); TEST_ASSERT_NOT_NULL_MESSAGE(root, "xmlNewNode failed for root"); xmlDocSetRootElement(doc, root); if (outRoot) *outRoot = root; return doc; } void setUp(void) { /* No global setup required */ } void tearDown(void) { /* No global teardown required */ } /* elem == NULL => should return 1 */ void test_htmlAutoCloseTag_null_elem_returns_1(void) { int ret = htmlAutoCloseTag(NULL, (const xmlChar *)"li", NULL); TEST_ASSERT_EQUAL_INT(1, ret); } /* elem->name equals name => should return 0 */ void test_htmlAutoCloseTag_equal_name_returns_0(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("p", &root); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"p", root); TEST_ASSERT_EQUAL_INT(0, ret); xmlFreeDoc(doc); } /* Direct auto-close: starting 'dt' should auto-close a preceding 'dd' */ void test_htmlAutoCloseTag_direct_autoclose_dd_by_dt_returns_1(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("dd", &root); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"dt", root); TEST_ASSERT_EQUAL_INT(1, ret); xmlFreeDoc(doc); } /* No auto-close between unrelated tags: 'div' vs 'span' => 0 */ void test_htmlAutoCloseTag_no_autoclose_div_vs_span_returns_0(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("div", &root); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"span", root); TEST_ASSERT_EQUAL_INT(0, ret); xmlFreeDoc(doc); } /* Descendant triggers auto-close:
with new tag 'dt' => 1 */ void test_htmlAutoCloseTag_descendant_dd_autoclosed_by_dt_returns_1(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("div", &root); xmlNodePtr child = xmlNewNode(NULL, (const xmlChar *)"dd"); TEST_ASSERT_NOT_NULL(child); xmlAddChild(root, child); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"dt", root); TEST_ASSERT_EQUAL_INT(1, ret); xmlFreeDoc(doc); } /* Should iterate over children: first child no match, second child matches => 1 */ void test_htmlAutoCloseTag_sibling_second_child_matches_returns_1(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("div", &root); xmlNodePtr child1 = xmlNewNode(NULL, (const xmlChar *)"span"); /* no match */ xmlNodePtr child2 = xmlNewNode(NULL, (const xmlChar *)"dd"); /* dt will close */ TEST_ASSERT_NOT_NULL(child1); TEST_ASSERT_NOT_NULL(child2); xmlAddChild(root, child1); xmlAddChild(root, child2); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"dt", root); TEST_ASSERT_EQUAL_INT(1, ret); xmlFreeDoc(doc); } /* Top-level equal name should short-circuit to 0 (even if children might match) */ void test_htmlAutoCloseTag_top_equal_name_short_circuits_returns_0(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("p", &root); /* Add a child that would be closed by 'dt' to ensure it's ignored due to top-level equal-name */ xmlNodePtr child = xmlNewNode(NULL, (const xmlChar *)"dd"); TEST_ASSERT_NOT_NULL(child); xmlAddChild(root, child); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"p", root); TEST_ASSERT_EQUAL_INT(0, ret); xmlFreeDoc(doc); } /* No descendant matches: ensure returns 0 */ void test_htmlAutoCloseTag_no_descendant_match_returns_0(void) { xmlNodePtr root = NULL; xmlDocPtr doc = make_doc_with_root("div", &root); xmlNodePtr c1 = xmlNewNode(NULL, (const xmlChar *)"span"); xmlNodePtr c2 = xmlNewNode(NULL, (const xmlChar *)"em"); TEST_ASSERT_NOT_NULL(c1); TEST_ASSERT_NOT_NULL(c2); xmlAddChild(root, c1); xmlAddChild(root, c2); int ret = htmlAutoCloseTag(doc, (const xmlChar *)"span", root); TEST_ASSERT_EQUAL_INT(0, ret); xmlFreeDoc(doc); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_htmlAutoCloseTag_null_elem_returns_1); RUN_TEST(test_htmlAutoCloseTag_equal_name_returns_0); RUN_TEST(test_htmlAutoCloseTag_direct_autoclose_dd_by_dt_returns_1); RUN_TEST(test_htmlAutoCloseTag_no_autoclose_div_vs_span_returns_0); RUN_TEST(test_htmlAutoCloseTag_descendant_dd_autoclosed_by_dt_returns_1); RUN_TEST(test_htmlAutoCloseTag_sibling_second_child_matches_returns_1); RUN_TEST(test_htmlAutoCloseTag_top_equal_name_short_circuits_returns_0); RUN_TEST(test_htmlAutoCloseTag_no_descendant_match_returns_0); return UNITY_END(); }