File size: 6,637 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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "unity/unity.h"
#include <libxml/HTMLtree.h>

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlstring.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

/* Internal libxml buffer API used by the function under test */
#include "private/buf.h"

/* Wrapper for the static function under test (declared in the module) */
extern size_t test_htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int format);

static xmlBufPtr make_buf(void) {
    xmlBufPtr buf = xmlBufCreate();
    TEST_ASSERT_NOT_NULL_MESSAGE(buf, "Failed to create xmlBuf");
    return buf;
}

static void assert_buf_equals(xmlBufPtr buf, const char *expected) {
    size_t expected_len = strlen(expected);
    const xmlChar *content = xmlBufContent(buf);
    size_t used = xmlBufUse(buf);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)expected_len, (uint64_t)used);
    TEST_ASSERT_NOT_NULL(content);
    TEST_ASSERT_EQUAL_INT(0, memcmp((const char *)content, expected, expected_len));
}

void setUp(void) {
    /* Ensure parser is initialized for any libxml operations */
    xmlInitParser();
}

void tearDown(void) {
    /* Cleanup global state after each test */
    xmlCleanupParser();
}

/* Error handling tests */

void test_htmlBufNodeDumpFormat_null_cur_returns_minus_one(void) {
    xmlBufPtr buf = make_buf();
    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, NULL, 0);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)(size_t)-1, (uint64_t)ret);
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_null_buf_returns_minus_one(void) {
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "div");
    TEST_ASSERT_NOT_NULL(node);
    size_t ret = test_htmlBufNodeDumpFormat(NULL, NULL, node, 0);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)(size_t)-1, (uint64_t)ret);
    xmlFreeNode(node);
}

/* Basic serialization tests */

void test_htmlBufNodeDumpFormat_empty_html_empty_elem_br(void) {
    xmlBufPtr buf = make_buf();
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "br");
    TEST_ASSERT_NOT_NULL(node);

    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    const char *expected = "<br>";
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(expected), (uint64_t)ret);
    assert_buf_equals(buf, expected);

    xmlFreeNode(node);
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_non_empty_without_children_div(void) {
    xmlBufPtr buf = make_buf();
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "div");
    TEST_ASSERT_NOT_NULL(node);

    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    const char *expected = "<div></div>";
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(expected), (uint64_t)ret);
    assert_buf_equals(buf, expected);

    xmlFreeNode(node);
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_text_child_with_escaping(void) {
    xmlBufPtr buf = make_buf();
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "div");
    TEST_ASSERT_NOT_NULL(node);
    xmlNodePtr text = xmlNewText(BAD_CAST "5 < 6 & 7");
    TEST_ASSERT_NOT_NULL(text);
    xmlAddChild(node, text);

    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    const char *expected = "<div>5 &lt; 6 &amp; 7</div>";
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(expected), (uint64_t)ret);
    assert_buf_equals(buf, expected);

    xmlFreeNode(node); /* Frees children as well */
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_namespace_prefix_and_declaration(void) {
    xmlBufPtr buf = make_buf();
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "span");
    TEST_ASSERT_NOT_NULL(node);

    /* Declare and set namespace prefix x with href "urn:test" */
    xmlNsPtr ns = xmlNewNs(node, BAD_CAST "urn:test", BAD_CAST "x");
    TEST_ASSERT_NOT_NULL(ns);
    xmlSetNs(node, ns);

    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    const char *expected = "<x:span xmlns:x=\"urn:test\"></x:span>";
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(expected), (uint64_t)ret);
    assert_buf_equals(buf, expected);

    xmlFreeNode(node);
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_multiple_calls_append_and_return_increment(void) {
    xmlBufPtr buf = make_buf();
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "div");
    TEST_ASSERT_NOT_NULL(node);

    const char *once = "<div></div>";

    size_t ret1 = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(once), (uint64_t)ret1);
    assert_buf_equals(buf, once);

    size_t before = xmlBufUse(buf);
    size_t ret2 = test_htmlBufNodeDumpFormat(buf, NULL, node, 0);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(once), (uint64_t)ret2);
    size_t after = xmlBufUse(buf);
    TEST_ASSERT_EQUAL_UINT64((uint64_t)(before + strlen(once)), (uint64_t)after);

    const xmlChar *content = xmlBufContent(buf);
    TEST_ASSERT_NOT_NULL(content);
    TEST_ASSERT_EQUAL_INT(0, memcmp((const char *)content, once, strlen(once)));
    TEST_ASSERT_EQUAL_INT(0, memcmp((const char *)content + strlen(once), once, strlen(once)));

    xmlFreeNode(node);
    xmlBufFree(buf);
}

void test_htmlBufNodeDumpFormat_formatting_newlines_with_block_children(void) {
    xmlBufPtr buf = make_buf();

    /* Build: <div><span>1</span><span>2</span></div> to trigger newlines with format=1 */
    xmlNodePtr div = xmlNewNode(NULL, BAD_CAST "div");
    TEST_ASSERT_NOT_NULL(div);
    xmlNodePtr span1 = xmlNewNode(NULL, BAD_CAST "span");
    xmlAddChild(span1, xmlNewText(BAD_CAST "1"));
    xmlAddChild(div, span1);
    xmlNodePtr span2 = xmlNewNode(NULL, BAD_CAST "span");
    xmlAddChild(span2, xmlNewText(BAD_CAST "2"));
    xmlAddChild(div, span2);

    size_t ret = test_htmlBufNodeDumpFormat(buf, NULL, div, 1);

    /* Expected behavior: newline after opening div and before closing div */
    const char *expected = "<div>\n<span>1</span><span>2</span>\n</div>";
    TEST_ASSERT_EQUAL_UINT64((uint64_t)strlen(expected), (uint64_t)ret);
    assert_buf_equals(buf, expected);

    xmlFreeNode(div);
    xmlBufFree(buf);
}

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_htmlBufNodeDumpFormat_null_cur_returns_minus_one);
    RUN_TEST(test_htmlBufNodeDumpFormat_null_buf_returns_minus_one);
    RUN_TEST(test_htmlBufNodeDumpFormat_empty_html_empty_elem_br);
    RUN_TEST(test_htmlBufNodeDumpFormat_non_empty_without_children_div);
    RUN_TEST(test_htmlBufNodeDumpFormat_text_child_with_escaping);
    RUN_TEST(test_htmlBufNodeDumpFormat_namespace_prefix_and_declaration);
    RUN_TEST(test_htmlBufNodeDumpFormat_multiple_calls_append_and_return_increment);
    RUN_TEST(test_htmlBufNodeDumpFormat_formatting_newlines_with_block_children);
    return UNITY_END();
}