File size: 6,629 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 |
#include "unity/unity.h"
#include <libxml/HTMLparser.h>
#include <string.h>
#include <stdlib.h>
/* Wrapper provided in the module for calling the static function */
int test_htmlParseLookupGt(xmlParserCtxtPtr ctxt);
/* Unity hooks */
void setUp(void) {
/* No per-test setup needed */
}
void tearDown(void) {
/* No per-test teardown needed */
}
/* Helper to create an HTML parser context from a C string */
static htmlParserCtxtPtr make_ctx(const char *s) {
int len = (int)strlen(s);
htmlParserCtxtPtr ctxt = htmlCreateMemoryParserCtxt(s, len);
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt, "Failed to create HTML parser context");
TEST_ASSERT_NOT_NULL_MESSAGE(ctxt->input, "Parser input is NULL");
/* Ensure cur starts at the beginning of the buffer for our tests */
if (ctxt->input->base != NULL)
ctxt->input->cur = ctxt->input->base;
return ctxt;
}
/* Basic tag: should find '>' immediately */
void test_htmlParseLookupGt_basic_tag(void) {
htmlParserCtxtPtr ctxt = make_ctx("<a>");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* Tag with attributes and spaces before closing '>' */
void test_htmlParseLookupGt_attrs_and_spaces(void) {
htmlParserCtxtPtr ctxt = make_ctx("<a href=\"test\" >");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* '>' inside single-quoted attribute value must not terminate the tag */
void test_htmlParseLookupGt_gt_inside_single_quotes(void) {
htmlParserCtxtPtr ctxt = make_ctx("<a title='> not end' data='x'>");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* '>' inside double-quoted attribute value must not terminate the tag */
void test_htmlParseLookupGt_gt_inside_double_quotes(void) {
htmlParserCtxtPtr ctxt = make_ctx("<a title=\"> not end\" data=\"x\">");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* Incomplete tag: no closing '>' in buffer */
void test_htmlParseLookupGt_incomplete_no_gt(void) {
const char *buf = "<a href='incomplete'";
htmlParserCtxtPtr ctxt = make_ctx(buf);
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
size_t expectedIndex = (size_t)(ctxt->input->end - ctxt->input->cur);
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(-1, ret);
TEST_ASSERT_EQUAL_size_t(expectedIndex, ctxt->checkIndex);
/* endCheckState is implementation-defined but should be preserved and non-negative */
TEST_ASSERT_TRUE(ctxt->endCheckState >= 0);
htmlFreeParserCtxt(ctxt);
}
/* Repeated call on the same incomplete buffer should be idempotent */
void test_htmlParseLookupGt_incomplete_repeat_call_stable(void) {
const char *buf = "<a href='x' attr=y";
htmlParserCtxtPtr ctxt = make_ctx(buf);
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
size_t expectedIndex = (size_t)(ctxt->input->end - ctxt->input->cur);
int ret1 = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(-1, ret1);
int savedState = ctxt->endCheckState;
size_t savedIndex = ctxt->checkIndex;
int ret2 = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(-1, ret2);
TEST_ASSERT_EQUAL_size_t(expectedIndex, ctxt->checkIndex);
TEST_ASSERT_EQUAL_size_t(savedIndex, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(savedState, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* Resume scanning across buffers: first incomplete, then complete */
void test_htmlParseLookupGt_resume_scanning_across_buffers(void) {
const char *part1 = "<a href='value'";
const char *part2 = "<a href='value' data=x>";
/* First, incomplete buffer */
htmlParserCtxtPtr ctxt1 = make_ctx(part1);
ctxt1->checkIndex = 0;
ctxt1->endCheckState = 0;
int ret1 = test_htmlParseLookupGt(ctxt1);
TEST_ASSERT_EQUAL_INT(-1, ret1);
size_t savedIndex = ctxt1->checkIndex;
int savedState = ctxt1->endCheckState;
htmlFreeParserCtxt(ctxt1);
/* Now, new buffer that continues and closes the tag */
htmlParserCtxtPtr ctxt2 = make_ctx(part2);
ctxt2->checkIndex = savedIndex; /* resume offset */
ctxt2->endCheckState = savedState; /* resume state */
int ret2 = test_htmlParseLookupGt(ctxt2);
TEST_ASSERT_EQUAL_INT(0, ret2);
TEST_ASSERT_EQUAL_UINT(0, ctxt2->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt2->endCheckState);
htmlFreeParserCtxt(ctxt2);
}
/* Closing tag should be handled correctly */
void test_htmlParseLookupGt_closing_tag(void) {
htmlParserCtxtPtr ctxt = make_ctx("</div>");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
/* Self-closing tag with '/' before '>' */
void test_htmlParseLookupGt_self_closing(void) {
htmlParserCtxtPtr ctxt = make_ctx("<img alt='x'/>");
ctxt->checkIndex = 0;
ctxt->endCheckState = 0;
int ret = test_htmlParseLookupGt(ctxt);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0, ctxt->checkIndex);
TEST_ASSERT_EQUAL_INT(0, ctxt->endCheckState);
htmlFreeParserCtxt(ctxt);
}
int main(void) {
UNITY_BEGIN();
xmlInitParser();
RUN_TEST(test_htmlParseLookupGt_basic_tag);
RUN_TEST(test_htmlParseLookupGt_attrs_and_spaces);
RUN_TEST(test_htmlParseLookupGt_gt_inside_single_quotes);
RUN_TEST(test_htmlParseLookupGt_gt_inside_double_quotes);
RUN_TEST(test_htmlParseLookupGt_incomplete_no_gt);
RUN_TEST(test_htmlParseLookupGt_incomplete_repeat_call_stable);
RUN_TEST(test_htmlParseLookupGt_resume_scanning_across_buffers);
RUN_TEST(test_htmlParseLookupGt_closing_tag);
RUN_TEST(test_htmlParseLookupGt_self_closing);
xmlCleanupParser();
return UNITY_END();
} |