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