File size: 4,928 Bytes
6baed57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <stdlib.h>
#include <string.h>

/* 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: <div><dd/></div> 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();
}