File size: 7,463 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
201
202
203
204
205
206
207
208
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <libxml/parser.h>

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

/* Helper to compute the allMask as in the implementation */
static int compute_allMask(void) {
    int allMask = 0;
    allMask |= HTML_PARSE_RECOVER;
    allMask |= HTML_PARSE_HTML5;
    allMask |= HTML_PARSE_NODEFDTD;
    allMask |= HTML_PARSE_NOERROR;
    allMask |= HTML_PARSE_NOWARNING;
    allMask |= HTML_PARSE_PEDANTIC;
    allMask |= HTML_PARSE_NOBLANKS;
    allMask |= HTML_PARSE_NONET;
    allMask |= HTML_PARSE_NOIMPLIED;
    allMask |= HTML_PARSE_COMPACT;
    allMask |= HTML_PARSE_HUGE;
    allMask |= HTML_PARSE_IGNORE_ENC;
    allMask |= HTML_PARSE_BIG_LINES;
    return allMask;
}

/* Unity fixtures */
void setUp(void) {
    /* No global setup needed */
}
void tearDown(void) {
    /* No global teardown needed */
}

/* Tests */

void test_htmlCtxtUseOptions_null_context_returns_minus1(void) {
    int ret = htmlCtxtUseOptions(NULL, 0);
    TEST_ASSERT_EQUAL_INT(-1, ret);
}

void test_htmlCtxtUseOptions_noblanks_sets_fields_and_sax_callback(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);
    TEST_ASSERT_NOT_NULL(ctxt->sax);

    int ret = htmlCtxtUseOptions(ctxt, HTML_PARSE_NOBLANKS);
    TEST_ASSERT_EQUAL_INT(0, ret);

    /* options should include NOBLANKS */
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NOBLANKS) != 0);
    /* keepBlanks should be cleared when NOBLANKS is set */
    TEST_ASSERT_EQUAL_INT(0, ctxt->keepBlanks);
    /* recovery is always set to 1 */
    TEST_ASSERT_EQUAL_INT(1, ctxt->recovery);
    /* dictNames is forced to 0 */
    TEST_ASSERT_EQUAL_INT(0, ctxt->dictNames);
    /* SAX ignorableWhitespace callback should be set to xmlSAX2IgnorableWhitespace */
    TEST_ASSERT_NOT_NULL(ctxt->sax->ignorableWhitespace);
    TEST_ASSERT(ctxt->sax->ignorableWhitespace == xmlSAX2IgnorableWhitespace);

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCtxtUseOptions_zero_options_sets_keepBlanks_1_and_no_noblanks_flag(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);

    int ret = htmlCtxtUseOptions(ctxt, 0);
    TEST_ASSERT_EQUAL_INT(0, ret);

    /* No options set */
    TEST_ASSERT_EQUAL_INT(0, ctxt->options);
    /* keepBlanks should be 1 when NOBLANKS isn't set */
    TEST_ASSERT_EQUAL_INT(1, ctxt->keepBlanks);
    /* recovery is always 1 */
    TEST_ASSERT_EQUAL_INT(1, ctxt->recovery);
    /* dictNames is forced to 0 */
    TEST_ASSERT_EQUAL_INT(0, ctxt->dictNames);

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCtxtUseOptions_preserves_keepMask_bits_from_previous_options(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);

    /* Manually pre-set keepMask bits */
    ctxt->options = HTML_PARSE_NOERROR |
                    HTML_PARSE_NOIMPLIED |
                    HTML_PARSE_COMPACT |
                    HTML_PARSE_HUGE |
                    HTML_PARSE_IGNORE_ENC |
                    HTML_PARSE_BIG_LINES;

    int ret = htmlCtxtUseOptions(ctxt, 0);
    TEST_ASSERT_EQUAL_INT(0, ret);

    /* Those bits should be preserved */
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NOERROR) != 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NOIMPLIED) != 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_COMPACT) != 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_HUGE) != 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_IGNORE_ENC) != 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_BIG_LINES) != 0);

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCtxtUseOptions_clears_non_keep_bits_from_previous_options(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);

    /* Pre-set some bits not in keepMask */
    ctxt->options = HTML_PARSE_RECOVER |
                    HTML_PARSE_PEDANTIC |
                    HTML_PARSE_NONET |
                    HTML_PARSE_HTML5 |
                    HTML_PARSE_NOBLANKS |
                    HTML_PARSE_NODEFDTD; /* Note: NODEFDTD is keepMask; include to verify mix */

    int ret = htmlCtxtUseOptions(ctxt, 0);
    TEST_ASSERT_EQUAL_INT(0, ret);

    /* Non-keep bits should be cleared */
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_RECOVER) == 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_PEDANTIC) == 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NONET) == 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_HTML5) == 0);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NOBLANKS) == 0);

    /* Keep bit (NODEFDTD) should remain set */
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_NODEFDTD) != 0);

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCtxtUseOptions_return_value_for_noent_and_unknown_bits(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);

    int allMask = compute_allMask();

    /* XML_PARSE_NOENT should be specially allowed, returning 0 */
    int ret_noent_only = htmlCtxtUseOptions(ctxt, XML_PARSE_NOENT);
    TEST_ASSERT_EQUAL_INT(0, ret_noent_only);

    /* All known bits plus NOENT should return 0 as well */
    int ret_all_known_plus_noent = htmlCtxtUseOptions(ctxt, allMask | XML_PARSE_NOENT);
    TEST_ASSERT_EQUAL_INT(0, ret_all_known_plus_noent);

    /* Find an unknown bit not in allMask nor XML_PARSE_NOENT to test return passthrough */
    unsigned int unknown = 0;
    unsigned int combined_known = (unsigned int)allMask | (unsigned int)XML_PARSE_NOENT;
    for (unsigned int i = 0; i < sizeof(unsigned int) * 8; i++) {
        unsigned int bit = 1U << i;
        if ((combined_known & bit) == 0U) {
            unknown = bit;
            break;
        }
    }

    if (unknown != 0U) {
        int ret_unknown = htmlCtxtUseOptions(ctxt, (int)unknown);
        TEST_ASSERT_EQUAL_INT((int)unknown, ret_unknown);
        /* Unknown bit must not be set in ctxt->options since it's not in allMask */
        TEST_ASSERT_TRUE(((unsigned int)ctxt->options & unknown) == 0U);
    } else {
        /* If no unknown bit found (highly unlikely), ensure at least known behavior passed */
        TEST_MESSAGE("No unknown option bit available to test passthrough return; skipping that sub-check.");
    }

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCtxtUseOptions_huge_with_null_dict_is_safe(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL(ctxt);

    /* Force dict to NULL to exercise the (dict != NULL) guard */
    xmlDictPtr saved = ctxt->dict;
    ctxt->dict = NULL;

    int ret = htmlCtxtUseOptions(ctxt, HTML_PARSE_HUGE);
    TEST_ASSERT_EQUAL_INT(0, ret);
    TEST_ASSERT_TRUE((ctxt->options & HTML_PARSE_HUGE) != 0);

    /* Restore dict to avoid side effects (though NULL is also fine for free) */
    ctxt->dict = saved;

    htmlFreeParserCtxt(ctxt);
}

/* Unity main */
int main(void) {
    UNITY_BEGIN();

    RUN_TEST(test_htmlCtxtUseOptions_null_context_returns_minus1);
    RUN_TEST(test_htmlCtxtUseOptions_noblanks_sets_fields_and_sax_callback);
    RUN_TEST(test_htmlCtxtUseOptions_zero_options_sets_keepBlanks_1_and_no_noblanks_flag);
    RUN_TEST(test_htmlCtxtUseOptions_preserves_keepMask_bits_from_previous_options);
    RUN_TEST(test_htmlCtxtUseOptions_clears_non_keep_bits_from_previous_options);
    RUN_TEST(test_htmlCtxtUseOptions_return_value_for_noent_and_unknown_bits);
    RUN_TEST(test_htmlCtxtUseOptions_huge_with_null_dict_is_safe);

    return UNITY_END();
}