#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();
}