File size: 6,604 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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <libxml/xmlmemory.h>

#include <string.h>
#include <stdlib.h>

/* Wrapper provided in the source for calling the static function */
extern int test_htmlSkipBlankChars(xmlParserCtxtPtr ctxt);

void setUp(void) {
    /* Ensure libxml is initialized */
    xmlInitParser();
}

void tearDown(void) {
    /* No global cleanup required per test */
}

/* Helper to create a parser context with a single input over given content */
static void create_ctxt_with_content(const char *content,
                                     int init_line, int init_col,
                                     xmlParserCtxtPtr *out_ctxt,
                                     xmlParserInputPtr *out_input,
                                     xmlChar **out_buf,
                                     int *out_len) {
    TEST_ASSERT_NOT_NULL_MESSAGE(out_ctxt, "out_ctxt must not be NULL");
    TEST_ASSERT_NOT_NULL_MESSAGE(out_input, "out_input must not be NULL");
    TEST_ASSERT_NOT_NULL_MESSAGE(out_buf, "out_buf must not be NULL");

    int len = (content != NULL) ? (int)strlen(content) : 0;
    xmlChar *buf = (xmlChar *)xmlMalloc((size_t)len + 1);
    TEST_ASSERT_NOT_NULL_MESSAGE(buf, "Failed to allocate buffer");
    if (len > 0 && content != NULL) {
        memcpy(buf, content, (size_t)len);
    }
    buf[len] = 0;

    htmlParserCtxtPtr hctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL_MESSAGE(hctxt, "Failed to create parser context");

    xmlParserInputPtr input = (xmlParserInputPtr)xmlMalloc(sizeof(*input));
    TEST_ASSERT_NOT_NULL_MESSAGE(input, "Failed to allocate parser input");
    memset(input, 0, sizeof(*input));
    input->base = buf;
    input->cur  = buf;
    input->end  = buf + len;
    input->line = init_line;
    input->col  = init_col;

    hctxt->input = input;

    *out_ctxt = (xmlParserCtxtPtr)hctxt;
    *out_input = input;
    *out_buf = buf;
    if (out_len)
        *out_len = len;
}

static void destroy_ctxt_with_content(xmlParserCtxtPtr ctxt,
                                      xmlParserInputPtr input,
                                      xmlChar *buf) {
    if (ctxt != NULL) {
        /* Prevent any internal free of our manually attached input */
        ctxt->input = NULL;
        htmlFreeParserCtxt((htmlParserCtxtPtr)ctxt);
    }
    if (input != NULL)
        xmlFree(input);
    if (buf != NULL)
        xmlFree(buf);
}

/* Test 1: Only spaces, verify count and col update */
void test_htmlSkipBlankChars_only_spaces(void) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    create_ctxt_with_content("    abc", 3, 5, &ctxt, &input, &buf, NULL);

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(4, ret);
    TEST_ASSERT_EQUAL_INT(3, input->line);
    TEST_ASSERT_EQUAL_INT(9, input->col);
    TEST_ASSERT_EQUAL_CHAR('a', (char)*(input->cur));

    destroy_ctxt_with_content(ctxt, input, buf);
}

/* Test 2: Mix of newline and spaces/tabs, verify line/col logic */
void test_htmlSkipBlankChars_newlines_and_spaces(void) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    /* Sequence: '\n', ' ', '\n', '\t', 'X' */
    create_ctxt_with_content("\n \n\tX", 1, 1, &ctxt, &input, &buf, NULL);

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(4, ret);
    TEST_ASSERT_EQUAL_INT(3, input->line); /* two newlines encountered */
    TEST_ASSERT_EQUAL_INT(2, input->col);  /* after last '\t' column is 2 */
    TEST_ASSERT_EQUAL_CHAR('X', (char)*(input->cur));

    destroy_ctxt_with_content(ctxt, input, buf);
}

/* Test 3: Stops at first non-whitespace and leaves cur at that char */
void test_htmlSkipBlankChars_stops_on_non_ws(void) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    create_ctxt_with_content(" \t\rA B", 1, 1, &ctxt, &input, &buf, NULL);

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(3, ret);         /* space, tab, carriage return */
    TEST_ASSERT_EQUAL_INT(1, input->line); /* no newline seen */
    TEST_ASSERT_EQUAL_INT(4, input->col);  /* 1 + 3 */
    TEST_ASSERT_EQUAL_CHAR('A', (char)*(input->cur));

    destroy_ctxt_with_content(ctxt, input, buf);
}

/* Test 4: Zero available input (cur == end) returns 0 and leaves state */
void test_htmlSkipBlankChars_zero_avail(void) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    create_ctxt_with_content("", 10, 7, &ctxt, &input, &buf, NULL);

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(0, ret);
    TEST_ASSERT_EQUAL_INT(10, input->line);
    TEST_ASSERT_EQUAL_INT(7, input->col);
    TEST_ASSERT_TRUE(input->cur == input->end);

    destroy_ctxt_with_content(ctxt, input, buf);
}

/* Test 5: Parser stopped -> no changes and return 0 */
void test_htmlSkipBlankChars_parser_stopped(void) {
    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    create_ctxt_with_content("   \n\tabc", 2, 3, &ctxt, &input, &buf, NULL);

    /* Force parser stopped */
    ctxt->instate = XML_PARSER_EOF;

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(0, ret);
    TEST_ASSERT_EQUAL_INT(2, input->line);
    TEST_ASSERT_EQUAL_INT(3, input->col);
    TEST_ASSERT_TRUE(input->cur == input->base); /* no advancement */

    destroy_ctxt_with_content(ctxt, input, buf);
}

/* Test 6: Large whitespace run to also cover res > 8 (GROW path) */
void test_htmlSkipBlankChars_large_whitespace(void) {
    char tmp[102 + 1]; /* 100 spaces + 'Z' + NUL */
    memset(tmp, ' ', 100);
    tmp[100] = 'Z';
    tmp[101] = '\0';

    xmlParserCtxtPtr ctxt = NULL;
    xmlParserInputPtr input = NULL;
    xmlChar *buf = NULL;

    create_ctxt_with_content(tmp, 1, 1, &ctxt, &input, &buf, NULL);

    int ret = test_htmlSkipBlankChars(ctxt);

    TEST_ASSERT_EQUAL_INT(100, ret);
    TEST_ASSERT_EQUAL_INT(1, input->line);
    TEST_ASSERT_EQUAL_INT(101, input->col); /* starting at 1, +100 spaces */
    TEST_ASSERT_EQUAL_CHAR('Z', (char)*(input->cur));

    destroy_ctxt_with_content(ctxt, input, buf);
}

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_htmlSkipBlankChars_only_spaces);
    RUN_TEST(test_htmlSkipBlankChars_newlines_and_spaces);
    RUN_TEST(test_htmlSkipBlankChars_stops_on_non_ws);
    RUN_TEST(test_htmlSkipBlankChars_zero_avail);
    RUN_TEST(test_htmlSkipBlankChars_parser_stopped);
    RUN_TEST(test_htmlSkipBlankChars_large_whitespace);
    return UNITY_END();
}