| | #include "unity/unity.h" |
| | #include <libxml/HTMLparser.h> |
| | #include <libxml/xmlerror.h> |
| | #include <libxml/parser.h> |
| | #include <string.h> |
| | #include <stdlib.h> |
| |
|
| | |
| | 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) { |
| | |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | 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); |
| |
|
| | |
| | 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); |
| |
|
| | |
| | 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 |
| | }; |
| |
|
| | |
| | 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; |
| | } |