|
|
#include "unity/unity.h" |
|
|
#include <libxml/HTMLparser.h> |
|
|
|
|
|
#include <libxml/parser.h> |
|
|
#include <libxml/parserInternals.h> |
|
|
#include <libxml/xmlmemory.h> |
|
|
#include <libxml/xmlstring.h> |
|
|
#include <limits.h> |
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
|
|
|
int test_htmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name, |
|
|
unsigned hashValue, int aindex); |
|
|
|
|
|
static void *alloc_attr_hash(unsigned size) { |
|
|
|
|
|
size_t per_bucket_bytes = 64; |
|
|
size_t total = (size_t)size * per_bucket_bytes; |
|
|
void *buf = xmlMalloc(total); |
|
|
if (buf != NULL) { |
|
|
memset(buf, 0xFF, total); |
|
|
} |
|
|
return buf; |
|
|
} |
|
|
|
|
|
static const xmlChar **alloc_atts(size_t count) { |
|
|
const xmlChar **atts = (const xmlChar **) xmlMalloc(sizeof(const xmlChar *) * count); |
|
|
if (atts != NULL) { |
|
|
memset(atts, 0, sizeof(const xmlChar *) * count); |
|
|
} |
|
|
return atts; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
static void cleanup_ctxt_custom_buffers(xmlParserCtxtPtr ctxt, |
|
|
void *savedHash, const xmlChar **savedAtts, |
|
|
void *ourHash, const xmlChar **ourAtts) { |
|
|
|
|
|
ctxt->attrHash = (void *)savedHash; |
|
|
ctxt->atts = (const xmlChar **)savedAtts; |
|
|
if (ourHash) xmlFree(ourHash); |
|
|
if (ourAtts) xmlFree((void *)ourAtts); |
|
|
} |
|
|
|
|
|
void test_htmlAttrHashInsert_inserts_and_detects_duplicate(void) { |
|
|
htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
|
|
|
void *savedHash = (void *)ctxt->attrHash; |
|
|
const xmlChar **savedAtts = ctxt->atts; |
|
|
|
|
|
unsigned size = 8; |
|
|
void *hashTable = alloc_attr_hash(size); |
|
|
TEST_ASSERT_NOT_NULL(hashTable); |
|
|
|
|
|
size_t attsCap = 16; |
|
|
const xmlChar **atts = alloc_atts(attsCap); |
|
|
TEST_ASSERT_NOT_NULL(atts); |
|
|
|
|
|
ctxt->attrHash = (void *)hashTable; |
|
|
ctxt->atts = (const xmlChar **)atts; |
|
|
|
|
|
|
|
|
const xmlChar *name1 = BAD_CAST "foo"; |
|
|
int aindex1 = 5; |
|
|
TEST_ASSERT_TRUE(aindex1 >= 0 && (size_t)aindex1 < attsCap); |
|
|
atts[aindex1] = name1; |
|
|
|
|
|
|
|
|
int r1 = test_htmlAttrHashInsert(ctxt, size, name1, 3U, aindex1); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r1); |
|
|
|
|
|
|
|
|
int r2 = test_htmlAttrHashInsert(ctxt, size, name1, 3U, 11); |
|
|
TEST_ASSERT_EQUAL_INT(aindex1, r2); |
|
|
|
|
|
cleanup_ctxt_custom_buffers((xmlParserCtxtPtr)ctxt, savedHash, savedAtts, hashTable, atts); |
|
|
xmlFreeParserCtxt((xmlParserCtxtPtr)ctxt); |
|
|
} |
|
|
|
|
|
void test_htmlAttrHashInsert_linear_probe_collision(void) { |
|
|
htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
void *savedHash = (void *)ctxt->attrHash; |
|
|
const xmlChar **savedAtts = ctxt->atts; |
|
|
|
|
|
unsigned size = 4; |
|
|
void *hashTable = alloc_attr_hash(size); |
|
|
TEST_ASSERT_NOT_NULL(hashTable); |
|
|
|
|
|
size_t attsCap = 16; |
|
|
const xmlChar **atts = alloc_atts(attsCap); |
|
|
TEST_ASSERT_NOT_NULL(atts); |
|
|
|
|
|
ctxt->attrHash = (void *)hashTable; |
|
|
ctxt->atts = (const xmlChar **)atts; |
|
|
|
|
|
|
|
|
const xmlChar *name1 = BAD_CAST "a"; |
|
|
int aindex1 = 2; |
|
|
atts[aindex1] = name1; |
|
|
int r1 = test_htmlAttrHashInsert(ctxt, size, name1, 3U, aindex1); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r1); |
|
|
|
|
|
|
|
|
const xmlChar *name2 = BAD_CAST "b"; |
|
|
int aindex2 = 3; |
|
|
atts[aindex2] = name2; |
|
|
int r2 = test_htmlAttrHashInsert(ctxt, size, name2, 7U , aindex2); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r2); |
|
|
|
|
|
|
|
|
int r3 = test_htmlAttrHashInsert(ctxt, size, name2, 7U, 9); |
|
|
TEST_ASSERT_EQUAL_INT(aindex2, r3); |
|
|
|
|
|
|
|
|
int r4 = test_htmlAttrHashInsert(ctxt, size, name1, 3U, 8); |
|
|
TEST_ASSERT_EQUAL_INT(aindex1, r4); |
|
|
|
|
|
cleanup_ctxt_custom_buffers((xmlParserCtxtPtr)ctxt, savedHash, savedAtts, hashTable, atts); |
|
|
xmlFreeParserCtxt((xmlParserCtxtPtr)ctxt); |
|
|
} |
|
|
|
|
|
void test_htmlAttrHashInsert_wraps_around_table(void) { |
|
|
htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
void *savedHash = (void *)ctxt->attrHash; |
|
|
const xmlChar **savedAtts = ctxt->atts; |
|
|
|
|
|
unsigned size = 4; |
|
|
void *hashTable = alloc_attr_hash(size); |
|
|
TEST_ASSERT_NOT_NULL(hashTable); |
|
|
|
|
|
size_t attsCap = 32; |
|
|
const xmlChar **atts = alloc_atts(attsCap); |
|
|
TEST_ASSERT_NOT_NULL(atts); |
|
|
|
|
|
ctxt->attrHash = (void *)hashTable; |
|
|
ctxt->atts = (const xmlChar **)atts; |
|
|
|
|
|
|
|
|
const xmlChar *name1 = BAD_CAST "x"; |
|
|
int aindex1 = 5; |
|
|
atts[aindex1] = name1; |
|
|
int r1 = test_htmlAttrHashInsert(ctxt, size, name1, 3U, aindex1); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r1); |
|
|
|
|
|
|
|
|
const xmlChar *name0 = BAD_CAST "y"; |
|
|
int aindex0 = 6; |
|
|
atts[aindex0] = name0; |
|
|
int r0 = test_htmlAttrHashInsert(ctxt, size, name0, 0U, aindex0); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r0); |
|
|
|
|
|
|
|
|
const xmlChar *name2 = BAD_CAST "z"; |
|
|
int aindex2 = 7; |
|
|
atts[aindex2] = name2; |
|
|
int r2 = test_htmlAttrHashInsert(ctxt, size, name2, 7U , aindex2); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r2); |
|
|
|
|
|
|
|
|
int r2b = test_htmlAttrHashInsert(ctxt, size, name2, 7U, 99); |
|
|
TEST_ASSERT_EQUAL_INT(aindex2, r2b); |
|
|
|
|
|
cleanup_ctxt_custom_buffers((xmlParserCtxtPtr)ctxt, savedHash, savedAtts, hashTable, atts); |
|
|
xmlFreeParserCtxt((xmlParserCtxtPtr)ctxt); |
|
|
} |
|
|
|
|
|
void test_htmlAttrHashInsert_pointer_equality_only(void) { |
|
|
htmlParserCtxtPtr ctxt = htmlNewParserCtxt(); |
|
|
TEST_ASSERT_NOT_NULL(ctxt); |
|
|
|
|
|
void *savedHash = (void *)ctxt->attrHash; |
|
|
const xmlChar **savedAtts = ctxt->atts; |
|
|
|
|
|
unsigned size = 8; |
|
|
void *hashTable = alloc_attr_hash(size); |
|
|
TEST_ASSERT_NOT_NULL(hashTable); |
|
|
|
|
|
size_t attsCap = 16; |
|
|
const xmlChar **atts = alloc_atts(attsCap); |
|
|
TEST_ASSERT_NOT_NULL(atts); |
|
|
|
|
|
ctxt->attrHash = (void *)hashTable; |
|
|
ctxt->atts = (const xmlChar **)atts; |
|
|
|
|
|
|
|
|
const xmlChar *nameA1 = BAD_CAST "href"; |
|
|
xmlChar *nameA2dup = xmlStrdup(nameA1); |
|
|
TEST_ASSERT_NOT_NULL(nameA2dup); |
|
|
|
|
|
int idx1 = 1; |
|
|
int idx2 = 2; |
|
|
|
|
|
atts[idx1] = nameA1; |
|
|
atts[idx2] = nameA2dup; |
|
|
|
|
|
|
|
|
int r1 = test_htmlAttrHashInsert(ctxt, size, nameA1, 5U, idx1); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r1); |
|
|
|
|
|
|
|
|
int r2 = test_htmlAttrHashInsert(ctxt, size, nameA2dup, 5U, idx2); |
|
|
TEST_ASSERT_EQUAL_INT(INT_MAX, r2); |
|
|
|
|
|
|
|
|
int r3 = test_htmlAttrHashInsert(ctxt, size, nameA1, 5U, 99); |
|
|
TEST_ASSERT_EQUAL_INT(idx1, r3); |
|
|
int r4 = test_htmlAttrHashInsert(ctxt, size, nameA2dup, 5U, 99); |
|
|
TEST_ASSERT_EQUAL_INT(idx2, r4); |
|
|
|
|
|
xmlFree(nameA2dup); |
|
|
cleanup_ctxt_custom_buffers((xmlParserCtxtPtr)ctxt, savedHash, savedAtts, hashTable, atts); |
|
|
xmlFreeParserCtxt((xmlParserCtxtPtr)ctxt); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
xmlInitParser(); |
|
|
UNITY_BEGIN(); |
|
|
|
|
|
RUN_TEST(test_htmlAttrHashInsert_inserts_and_detects_duplicate); |
|
|
RUN_TEST(test_htmlAttrHashInsert_linear_probe_collision); |
|
|
RUN_TEST(test_htmlAttrHashInsert_wraps_around_table); |
|
|
RUN_TEST(test_htmlAttrHashInsert_pointer_equality_only); |
|
|
|
|
|
int res = UNITY_END(); |
|
|
xmlCleanupParser(); |
|
|
return res; |
|
|
} |