File size: 6,070 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/xmlerror.h>
#include <libxml/parser.h>
#include <string.h>
#include <stdlib.h>

/* The wrapper provided in the module for the static function */
void test_htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts);

static htmlParserCtxtPtr make_ctxt(void) {
    htmlParserCtxtPtr ctxt = htmlNewParserCtxt();
    TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML parser context");
    xmlCtxtResetLastError(ctxt);
    return ctxt;
}

void setUp(void) {
    /* Setup code here, or leave empty */
}

void tearDown(void) {
    /* Cleanup code here, or leave empty */
}

static void assert_encoding_equals_case_insensitive(const xmlChar *enc, const char *expected) {
    TEST_ASSERT_NOT_NULL_MESSAGE(enc, "Encoding was not set");
    TEST_ASSERT_EQUAL_INT_MESSAGE(0, xmlStrcasecmp(enc, BAD_CAST expected),
                                  "Declared encoding does not match expected (case-insensitive compare)");
}

void test_htmlCheckMeta_charset_utf8_sets_declared_encoding(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "charset", BAD_CAST "utf-8",
        NULL
    };

    TEST_ASSERT_NULL_MESSAGE(ctxt->encoding, "Precondition failed: encoding should start as NULL");
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    assert_encoding_equals_case_insensitive(ctxt->encoding, "utf-8");

    xmlErrorPtr err = xmlCtxtGetLastError(ctxt);
    TEST_ASSERT_TRUE_MESSAGE(err == NULL || err->code == 0,
                             "Unexpected error after setting UTF-8 encoding");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_http_equiv_content_type_sets_declared_encoding(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "http-equiv", BAD_CAST "Content-Type",
        BAD_CAST "content", BAD_CAST "text/html; charset=ISO-8859-1",
        NULL
    };

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    assert_encoding_equals_case_insensitive(ctxt->encoding, "ISO-8859-1");

    xmlErrorPtr err = xmlCtxtGetLastError(ctxt);
    TEST_ASSERT_TRUE_MESSAGE(err == NULL || err->code == 0,
                             "Unexpected error after setting ISO-8859-1 encoding");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_charset_precedence_over_http_equiv(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "http-equiv", BAD_CAST "Content-Type",
        BAD_CAST "content", BAD_CAST "text/html; charset=ISO-8859-1",
        BAD_CAST "charset", BAD_CAST "utf-8",
        NULL
    };

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    /* charset attribute should take precedence */
    assert_encoding_equals_case_insensitive(ctxt->encoding, "utf-8");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_non_ascii_incompatible_emits_error_and_ignores(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "charset", BAD_CAST "utf-16",
        NULL
    };

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    /* Should not set encoding due to non-ASCII-compatibility */
    TEST_ASSERT_NULL_MESSAGE(ctxt->encoding, "Encoding should not be set for non-ASCII-compatible charset");

    xmlErrorPtr err = xmlCtxtGetLastError(ctxt);
    TEST_ASSERT_NOT_NULL_MESSAGE(err, "Expected an error for non-ASCII-compatible charset");
    TEST_ASSERT_EQUAL_INT_MESSAGE(XML_ERR_UNSUPPORTED_ENCODING, err->code,
                                  "Expected XML_ERR_UNSUPPORTED_ENCODING error code");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_null_context_no_crash(void) {
    const xmlChar *atts[] = {
        BAD_CAST "charset", BAD_CAST "utf-8",
        NULL
    };

    /* Just ensure no crash; nothing to assert on context */
    test_htmlCheckMeta(NULL, atts);

    TEST_ASSERT_TRUE(1);
}

void test_htmlCheckMeta_null_atts_no_action(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, NULL);

    TEST_ASSERT_NULL_MESSAGE(ctxt->encoding, "Encoding should remain NULL when atts is NULL");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_content_without_http_equiv_no_action(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "content", BAD_CAST "text/html; charset=UTF-8",
        NULL
    };

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    TEST_ASSERT_NULL_MESSAGE(ctxt->encoding, "Encoding should not be set without http-equiv=Content-Type");

    htmlFreeParserCtxt(ctxt);
}

void test_htmlCheckMeta_case_insensitive_matching(void) {
    htmlParserCtxtPtr ctxt = make_ctxt();

    const xmlChar *atts[] = {
        BAD_CAST "HTTP-EQUIV", BAD_CAST "content-type",
        BAD_CAST "CoNtEnT", BAD_CAST "text/html; charset=iso-8859-1",
        NULL
    };

    TEST_ASSERT_NULL(ctxt->encoding);
    xmlCtxtResetLastError(ctxt);

    test_htmlCheckMeta(ctxt, atts);

    assert_encoding_equals_case_insensitive(ctxt->encoding, "iso-8859-1");

    htmlFreeParserCtxt(ctxt);
}

int main(void) {
    xmlInitParser();

    UNITY_BEGIN();
    RUN_TEST(test_htmlCheckMeta_charset_utf8_sets_declared_encoding);
    RUN_TEST(test_htmlCheckMeta_http_equiv_content_type_sets_declared_encoding);
    RUN_TEST(test_htmlCheckMeta_charset_precedence_over_http_equiv);
    RUN_TEST(test_htmlCheckMeta_non_ascii_incompatible_emits_error_and_ignores);
    RUN_TEST(test_htmlCheckMeta_null_context_no_crash);
    RUN_TEST(test_htmlCheckMeta_null_atts_no_action);
    RUN_TEST(test_htmlCheckMeta_content_without_http_equiv_no_action);
    RUN_TEST(test_htmlCheckMeta_case_insensitive_matching);
    int res = UNITY_END();

    xmlCleanupParser();
    return res;
}