#include "unity/unity.h" #include #include #include #include #include /* 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(); }