#include "utilities/HashTable.h" #include "utilities/lookup3.h" #include "unittest/TestSuite.h" typedef struct HashTableObjectKeyTest HashTableObjectKeyTest; #define HashTableObjectKeyTest_superclass HashTableObjectKey #define HashTableObjectKeyTest_ivars \ HashTableObjectKey_ivars \ uint32_t firstHalf; \ uint32_t secondHalf; #define HashTableObjectKeyTest_vtable(self_type) \ HashTableObjectKey_vtable(self_type) stemobject_declare(HashTableObjectKeyTest) HashTableObjectKeyTest * HashTableObjectKeyTest_create(uint32_t firstHalf, uint32_t secondHalf); bool HashTableObjectKeyTest_init(HashTableObjectKeyTest * self, uint32_t firstHalf, uint32_t secondHalf); void HashTableObjectKeyTest_dispose(HashTableObjectKeyTest * self); HashTableObjectKeyTest * HashTableObjectKeyTest_copy(HashTableObjectKeyTest * self); bool HashTableObjectKeyTest_isEqual(HashTableObjectKeyTest * self, compat_type(HashTableObjectKeyTest *) compareUntyped); uint32_t HashTableObjectKeyTest_hash(HashTableObjectKeyTest * self); #define stemobject_implementation HashTableObjectKeyTest stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(copy); stemobject_vtable_entry(isEqual); stemobject_vtable_entry(hash); stemobject_vtable_end(); HashTableObjectKeyTest * HashTableObjectKeyTest_create(uint32_t firstHalf, uint32_t secondHalf) { stemobject_create_implementation(init, firstHalf, secondHalf) } bool HashTableObjectKeyTest_init(HashTableObjectKeyTest * self, uint32_t firstHalf, uint32_t secondHalf) { call_super(init, self); self->firstHalf = firstHalf; self->secondHalf = secondHalf; return true; } void HashTableObjectKeyTest_dispose(HashTableObjectKeyTest * self) { call_super_virtual(dispose, self); } HashTableObjectKeyTest * HashTableObjectKeyTest_copy(HashTableObjectKeyTest * self) { return HashTableObjectKeyTest_create(self->firstHalf, self->secondHalf); } bool HashTableObjectKeyTest_isEqual(HashTableObjectKeyTest * self, compat_type(HashTableObjectKeyTest *) compareUntyped) { HashTableObjectKeyTest * compare = compareUntyped; if (!StemObject_isExactClass(compare, &HashTableObjectKeyTest_class)) { return false; } return self->firstHalf == compare->firstHalf && self->secondHalf == compare->secondHalf; } uint32_t HashTableObjectKeyTest_hash(HashTableObjectKeyTest * self) { return hashword(&self->secondHalf, 1, hashword(&self->firstHalf, 1, 0)); } #undef stemobject_implementation static void testInit(void) { HashTable * hashTable = HashTable_create(0); TestCase_assertPointerNonNULL(hashTable); TestCase_assertSizeEqual(hashTable->entryDataSize, 0); TestCase_assertSizeEqual(hashTable->densityMax, HASH_TABLE_DENSITY_DEFAULT); TestCase_assertSizeEqual(hashTable->bucketCount, 8); for (unsigned int bucketIndex = 0; bucketIndex < 8; bucketIndex++) { TestCase_assertSizeEqual(hashTable->buckets[bucketIndex].count, 0); TestCase_assertSizeEqual(hashTable->buckets[bucketIndex].allocatedCount, 0); TestCase_assertPointerNULL(hashTable->buckets[bucketIndex].entries); } TestCase_assertSizeEqual(hashTable->count, 0); HashTable_dispose(hashTable); hashTable = HashTable_create(1); TestCase_assertPointerNonNULL(hashTable); TestCase_assertSizeEqual(hashTable->entryDataSize, 1); TestCase_assertSizeEqual(hashTable->densityMax, HASH_TABLE_DENSITY_DEFAULT); TestCase_assertSizeEqual(hashTable->bucketCount, 8); for (unsigned int bucketIndex = 0; bucketIndex < 8; bucketIndex++) { TestCase_assertSizeEqual(hashTable->buckets[bucketIndex].count, 0); TestCase_assertSizeEqual(hashTable->buckets[bucketIndex].allocatedCount, 0); TestCase_assertPointerNULL(hashTable->buckets[bucketIndex].entries); } TestCase_assertSizeEqual(hashTable->count, 0); HashTable_dispose(hashTable); } static void testKeyMacros(void) { const char * string = "hello"; HashTable_key key = HashTable_stringKey(string); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringPointerEqual(key.data.string.characters, string); TestCase_assertSizeEqual(key.data.string.length, 5); string = "Hello 2"; key = HashTable_stringKey(string); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringPointerEqual(key.data.string.characters, string); TestCase_assertSizeEqual(key.data.string.length, 7); key = HashTable_stringKeyWithLength(string, 4); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringPointerEqual(key.data.string.characters, string); TestCase_assertSizeEqual(key.data.string.length, 4); key = HashTable_stringKeyWithLength(string + 1, 3); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringPointerEqual(key.data.string.characters, string + 1); TestCase_assertSizeEqual(key.data.string.length, 3); key = HashTable_byteKey(string, 4); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_BYTES); TestCase_assertPointerEqual(key.data.bytes.data, string); TestCase_assertSizeEqual(key.data.string.length, 4); key = HashTable_byteKey(string + 1, 3); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_BYTES); TestCase_assertPointerEqual(key.data.bytes.data, string + 1); TestCase_assertSizeEqual(key.data.string.length, 3); key = HashTable_uint32Key(0); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32); TestCase_assertUIntEqual(key.data.uint32, 0); key = HashTable_uint32Key(1); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32); TestCase_assertUIntEqual(key.data.uint32, 1); key = HashTable_uint32PairKey(0, 1); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32_PAIR); TestCase_assertUIntEqual(key.data.uint32Pair.first, 0); TestCase_assertUIntEqual(key.data.uint32Pair.second, 1); key = HashTable_uint32PairKey(3, 2); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32_PAIR); TestCase_assertUIntEqual(key.data.uint32Pair.first, 3); TestCase_assertUIntEqual(key.data.uint32Pair.second, 2); key = HashTable_uint32PairKeyUnordered(0, 1); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32_PAIR); TestCase_assertUIntEqual(key.data.uint32Pair.first, 0); TestCase_assertUIntEqual(key.data.uint32Pair.second, 1); key = HashTable_uint32PairKeyUnordered(3, 2); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32_PAIR); TestCase_assertUIntEqual(key.data.uint32Pair.first, 2); TestCase_assertUIntEqual(key.data.uint32Pair.second, 3); key = HashTable_pointerKey(NULL); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_POINTER); TestCase_assertPointerNULL(key.data.pointer); key = HashTable_pointerKey((void *) 0x1); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_POINTER); TestCase_assertPointerEqual(key.data.pointer, (void *) 0x1); key = HashTable_stringLiteralKey("hello"); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringEqual(key.data.string.characters, "hello"); TestCase_assertSizeEqual(key.data.string.length, 5); key = HashTable_stringLiteralKey("key2"); TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_STRING); TestCase_assertStringEqual(key.data.string.characters, "key2"); TestCase_assertSizeEqual(key.data.string.length, 4); } struct dataStruct { float a; uint32_t b; void * c; }; static void testSetGet(void) { HashTable * hashTable = HashTable_create(sizeof(uint32_t)); uint32_t * entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNULL(entryUInt32); uint32_t value = 1; uint32_t * setResult = HashTable_set(hashTable, HashTable_uint32Key(0), &value); TestCase_assertSizeEqual(hashTable->count, 1); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 1); TestCase_assertPointerEqual(setResult, entryUInt32); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNULL(entryUInt32); setResult = HashTable_set(hashTable, HashTable_uint32Key(1), &value); TestCase_assertSizeEqual(hashTable->count, 2); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 1); TestCase_assertPointerUnequal(setResult, entryUInt32); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 1); TestCase_assertPointerEqual(setResult, entryUInt32); value = 2; HashTable_set(hashTable, HashTable_uint32Key(2), &value); TestCase_assertSizeEqual(hashTable->count, 3); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 2); HashTable_set(hashTable, HashTable_uint32Key(0), &value); TestCase_assertSizeEqual(hashTable->count, 3); entryUInt32 = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 2); value = 3; HashTable_set(hashTable, HashTable_stringKey("hi"), &value); TestCase_assertSizeEqual(hashTable->count, 4); entryUInt32 = HashTable_get(hashTable, HashTable_stringKey("hi")); TestCase_assertPointerNonNULL(entryUInt32); TestCase_assertUIntEqual(*entryUInt32, 3); HashTable_dispose(hashTable); hashTable = HashTable_create(sizeof(struct dataStruct)); struct dataStruct valueStruct = {1.0f, 2, (void *) 0x3}; HashTable_set(hashTable, HashTable_uint32Key(0), &valueStruct); struct dataStruct * entryStruct = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entryStruct); TestCase_assertPointerUnequal(entryStruct, &valueStruct); TestCase_assertFloatEqual(entryStruct->a, 1.0f); TestCase_assertUIntEqual(entryStruct->b, 2); TestCase_assertPointerEqual(entryStruct->c, 0x3); valueStruct.a = 2.25f; valueStruct.b = 5; valueStruct.c = NULL; HashTable_set(hashTable, HashTable_uint32Key(1), &valueStruct); entryStruct = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entryStruct); TestCase_assertPointerUnequal(entryStruct, &valueStruct); TestCase_assertFloatEqual(entryStruct->a, 1.0f); TestCase_assertUIntEqual(entryStruct->b, 2); TestCase_assertPointerEqual(entryStruct->c, 0x3); entryStruct = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(entryStruct); TestCase_assertPointerUnequal(entryStruct, &valueStruct); TestCase_assertFloatEqual(entryStruct->a, 2.25f); TestCase_assertUIntEqual(entryStruct->b, 5); TestCase_assertPointerEqual(entryStruct->c, NULL); entryStruct = HashTable_set(hashTable, HashTable_uint32Key(2), NULL); TestCase_assertPointerNonNULL(entryStruct); entryStruct->a = 3.0f; entryStruct->b = 7; entryStruct->c = (void *) 0x1; entryStruct = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entryStruct); TestCase_assertFloatEqual(entryStruct->a, 3.0f); TestCase_assertUIntEqual(entryStruct->b, 7); TestCase_assertPointerEqual(entryStruct->c, (void *) 0x1); HashTable_dispose(hashTable); } static void testDeleteValues(void) { HashTable * hashTable = HashTable_create(1); bool success = HashTable_delete(hashTable, HashTable_uint32Key(1)); TestCase_assertBoolFalse(success); uint8_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(0), &value); value = 1; HashTable_set(hashTable, HashTable_uint32Key(1), &value); value = 2; HashTable_set(hashTable, HashTable_uint32Key(2), &value); TestCase_assertSizeEqual(hashTable->count, 3); uint8_t * entry = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 1); entry = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 2); success = HashTable_delete(hashTable, HashTable_uint32Key(1)); TestCase_assertBoolTrue(success); TestCase_assertSizeEqual(hashTable->count, 2); entry = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 2); success = HashTable_delete(hashTable, HashTable_uint32Key(0)); TestCase_assertBoolTrue(success); TestCase_assertSizeEqual(hashTable->count, 1); entry = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 2); success = HashTable_delete(hashTable, HashTable_uint32Key(0)); TestCase_assertBoolFalse(success); success = HashTable_delete(hashTable, HashTable_uint32Key(2)); TestCase_assertBoolTrue(success); TestCase_assertSizeEqual(hashTable->count, 0); entry = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNULL(entry); HashTable_set(hashTable, HashTable_uint32Key(0), &value); HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_uint32Key(2), &value); TestCase_assertSizeEqual(hashTable->count, 3); HashTable_deleteAll(hashTable); TestCase_assertSizeEqual(hashTable->count, 0); entry = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNULL(entry); HashTable_dispose(hashTable); } static void testCopy(void) { HashTable * hashTable = HashTable_create(4); hashTable->densityMax = 5; uint32_t value32 = 0; HashTable_set(hashTable, HashTable_uint32Key(0), &value32); value32 = 1; HashTable_set(hashTable, HashTable_uint32Key(1), &value32); HashTable * copy = HashTable_copy(hashTable); HashTable_dispose(hashTable); TestCase_assertPointerNonNULL(copy); TestCase_assertSizeEqual(copy->count, 2); TestCase_assertSizeEqual(copy->entryDataSize, 4); TestCase_assertSizeEqual(copy->densityMax, 5); uint32_t * entry32 = HashTable_get(copy, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entry32); TestCase_assertUIntEqual(*entry32, 0); entry32 = HashTable_get(copy, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(entry32); TestCase_assertUIntEqual(*entry32, 1); HashTable_dispose(copy); hashTable = HashTable_create(2); hashTable->densityMax = 8; uint16_t value16 = 5; HashTable_set(hashTable, HashTable_stringKey("a"), &value16); value16 = 3; HashTable_set(hashTable, HashTable_stringKey("b"), &value16); value16 = 9; HashTable_set(hashTable, HashTable_stringKey("c"), &value16); copy = HashTable_copy(hashTable); HashTable_dispose(hashTable); TestCase_assertPointerNonNULL(copy); TestCase_assertSizeEqual(copy->count, 3); TestCase_assertSizeEqual(copy->entryDataSize, 2); TestCase_assertSizeEqual(copy->densityMax, 8); uint16_t * entry16 = HashTable_get(copy, HashTable_stringKey("a")); TestCase_assertPointerNonNULL(entry16); TestCase_assertUIntEqual(*entry16, 5); entry16 = HashTable_get(copy, HashTable_stringKey("b")); TestCase_assertPointerNonNULL(entry16); TestCase_assertUIntEqual(*entry16, 3); entry16 = HashTable_get(copy, HashTable_stringKey("c")); TestCase_assertPointerNonNULL(entry16); TestCase_assertUIntEqual(*entry16, 9); HashTable_dispose(copy); } static void testListKeys(void) { HashTable * hashTable = HashTable_create(4); HashTableObjectKeyTest * objectKeyTest = HashTableObjectKeyTest_create(1, 2); uint32_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_stringKey("string"), &value); HashTable_set(hashTable, HashTable_byteKey("hi", 2), &value); HashTable_set(hashTable, HashTable_pointerKey((void *) 0x4), &value); HashTable_set(hashTable, HashTable_objectKey(objectKeyTest), &value); HashTable_set(hashTable, HashTable_uint32PairKey(5, 6), &value); size_t keyCount = 0; HashTable_key * keys = HashTable_listKeys(hashTable, &keyCount); TestCase_assertSizeEqual(keyCount, 6); TestCase_assertPointerNonNULL(keys); HashTable_key * stringKey = NULL, * byteKey = NULL, * uint32Key = NULL, * uint32PairKey, * pointerKey = NULL, * objectKey = NULL; for (unsigned int keyIndex = 0; keyIndex < 6; keyIndex++) { switch (keys[keyIndex].type) { case HASH_KEY_TYPE_STRING: stringKey = &keys[keyIndex]; break; case HASH_KEY_TYPE_BYTES: byteKey = &keys[keyIndex]; break; case HASH_KEY_TYPE_UINT32: uint32Key = &keys[keyIndex]; break; case HASH_KEY_TYPE_UINT32_PAIR: uint32PairKey = &keys[keyIndex]; break; case HASH_KEY_TYPE_POINTER: pointerKey = &keys[keyIndex]; break; case HASH_KEY_TYPE_OBJECT: objectKey = &keys[keyIndex]; break; } } TestCase_assertPointerNonNULL(stringKey); TestCase_assertPointerNonNULL(byteKey); TestCase_assertPointerNonNULL(uint32Key); TestCase_assertPointerNonNULL(uint32PairKey); TestCase_assertPointerNonNULL(pointerKey); TestCase_assertPointerNonNULL(objectKey); TestCase_assertStringEqual(stringKey->data.string.characters, "string"); TestCase_assertSizeEqual(stringKey->data.string.length, 6); TestCase_assert(!memcmp(byteKey->data.bytes.data, "hi", 2), "Expected \"hi\" but got \"%.*s\"", (int) byteKey->data.bytes.length, (char *) byteKey->data.bytes.data); TestCase_assertSizeEqual(byteKey->data.bytes.length, 2); TestCase_assertUIntEqual(uint32Key->data.uint32, 1); TestCase_assertUIntEqual(uint32PairKey->data.uint32Pair.first, 5); TestCase_assertUIntEqual(uint32PairKey->data.uint32Pair.second, 6); TestCase_assertPointerEqual(pointerKey->data.pointer, (void *) 0x4); TestCase_assertPointerUnequal(objectKey->data.object, (HashTableObjectKey *) objectKey); TestCase_assertBoolTrue(call_virtual(isEqual, objectKeyTest, objectKey->data.object)); free(keys); HashTable_dispose(hashTable); HashTableObjectKeyTest_dispose(objectKeyTest); hashTable = HashTable_create(4); HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_uint32Key(2), &value); HashTable_set(hashTable, HashTable_uint32Key(3), &value); keyCount = 0; keys = HashTable_listKeys(hashTable, &keyCount); TestCase_assertSizeEqual(keyCount, 3); TestCase_assertPointerNonNULL(keys); HashTable_key * key1 = NULL, * key2 = NULL, * key3 = NULL; for (unsigned int keyIndex = 0; keyIndex < 3; keyIndex++) { switch (keys[keyIndex].data.uint32) { case 1: key1 = &keys[keyIndex]; break; case 2: key2 = &keys[keyIndex]; break; case 3: key3 = &keys[keyIndex]; break; } } TestCase_assertPointerNonNULL(key1); TestCase_assertPointerNonNULL(key2); TestCase_assertPointerNonNULL(key3); TestCase_assertIntEqual(key1->type, HASH_KEY_TYPE_UINT32); TestCase_assertIntEqual(key2->type, HASH_KEY_TYPE_UINT32); TestCase_assertIntEqual(key3->type, HASH_KEY_TYPE_UINT32); free(keys); HashTable_dispose(hashTable); } static void testKeyAtIndex(void) { HashTable * hashTable = HashTable_create(4); HashTableObjectKeyTest * objectKeyTest = HashTableObjectKeyTest_create(1, 2); uint32_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_stringKey("string"), &value); HashTable_set(hashTable, HashTable_byteKey("hi", 2), &value); HashTable_set(hashTable, HashTable_pointerKey((void *) 0x4), &value); HashTable_set(hashTable, HashTable_objectKey(objectKeyTest), &value); HashTable_set(hashTable, HashTable_uint32PairKey(5, 6), &value); HashTable_key * keys1[6]; keys1[0] = HashTable_keyAtIndex(hashTable, 0); TestCase_assertPointerNonNULL(keys1[0]); keys1[1] = HashTable_keyAtIndex(hashTable, 1); TestCase_assertPointerNonNULL(keys1[1]); keys1[2] = HashTable_keyAtIndex(hashTable, 2); TestCase_assertPointerNonNULL(keys1[2]); keys1[3] = HashTable_keyAtIndex(hashTable, 3); TestCase_assertPointerNonNULL(keys1[3]); keys1[4] = HashTable_keyAtIndex(hashTable, 4); TestCase_assertPointerNonNULL(keys1[4]); keys1[5] = HashTable_keyAtIndex(hashTable, 5); TestCase_assertPointerNonNULL(keys1[5]); TestCase_assertPointerNULL(HashTable_keyAtIndex(hashTable, 6)); HashTable_key * stringKey = NULL, * byteKey = NULL, * uint32Key = NULL, * uint32PairKey, * pointerKey = NULL, * objectKey = NULL; for (unsigned int keyIndex = 0; keyIndex < 6; keyIndex++) { switch (keys1[keyIndex]->type) { case HASH_KEY_TYPE_STRING: stringKey = keys1[keyIndex]; break; case HASH_KEY_TYPE_BYTES: byteKey = keys1[keyIndex]; break; case HASH_KEY_TYPE_UINT32: uint32Key = keys1[keyIndex]; break; case HASH_KEY_TYPE_UINT32_PAIR: uint32PairKey = keys1[keyIndex]; break; case HASH_KEY_TYPE_POINTER: pointerKey = keys1[keyIndex]; break; case HASH_KEY_TYPE_OBJECT: objectKey = keys1[keyIndex]; break; } } TestCase_assertPointerNonNULL(stringKey); TestCase_assertPointerNonNULL(byteKey); TestCase_assertPointerNonNULL(uint32Key); TestCase_assertPointerNonNULL(uint32PairKey); TestCase_assertPointerNonNULL(pointerKey); TestCase_assertPointerNonNULL(objectKey); TestCase_assertStringEqual(stringKey->data.string.characters, "string"); TestCase_assertSizeEqual(stringKey->data.string.length, 6); TestCase_assert(!memcmp(byteKey->data.bytes.data, "hi", 2), "Expected \"hi\" but got \"%.*s\"", (int) byteKey->data.bytes.length, (char *) byteKey->data.bytes.data); TestCase_assertSizeEqual(byteKey->data.bytes.length, 2); TestCase_assertUIntEqual(uint32Key->data.uint32, 1); TestCase_assertUIntEqual(uint32PairKey->data.uint32Pair.first, 5); TestCase_assertUIntEqual(uint32PairKey->data.uint32Pair.second, 6); TestCase_assertPointerEqual(pointerKey->data.pointer, (void *) 0x4); TestCase_assertPointerUnequal(objectKey->data.object, (HashTableObjectKey *) objectKey); TestCase_assertBoolTrue(call_virtual(isEqual, objectKeyTest, objectKey->data.object)); HashTable_dispose(hashTable); hashTable = HashTable_create(4); HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_uint32Key(2), &value); HashTable_set(hashTable, HashTable_uint32Key(3), &value); HashTable_key * keys2[3]; keys2[0] = HashTable_keyAtIndex(hashTable, 0); TestCase_assertPointerNonNULL(keys1[0]); keys2[1] = HashTable_keyAtIndex(hashTable, 1); TestCase_assertPointerNonNULL(keys1[1]); keys2[2] = HashTable_keyAtIndex(hashTable, 2); TestCase_assertPointerNonNULL(keys1[2]); TestCase_assertPointerNULL(HashTable_keyAtIndex(hashTable, 3)); HashTable_key * key1 = NULL, * key2 = NULL, * key3 = NULL; for (unsigned int keyIndex = 0; keyIndex < 3; keyIndex++) { switch (keys2[keyIndex]->data.uint32) { case 1: key1 = keys2[keyIndex]; break; case 2: key2 = keys2[keyIndex]; break; case 3: key3 = keys2[keyIndex]; break; } } TestCase_assertPointerNonNULL(key1); TestCase_assertPointerNonNULL(key2); TestCase_assertPointerNonNULL(key3); TestCase_assertIntEqual(key1->type, HASH_KEY_TYPE_UINT32); TestCase_assertIntEqual(key2->type, HASH_KEY_TYPE_UINT32); TestCase_assertIntEqual(key3->type, HASH_KEY_TYPE_UINT32); HashTable_dispose(hashTable); } static void testHasNonStringKeys(void) { HashTable * hashTable = HashTable_create(4); TestCase_assertBoolFalse(HashTable_hasNonStringKeys(hashTable)); uint32_t value = 0; HashTable_set(hashTable, HashTable_stringKey("a"), &value); TestCase_assertBoolFalse(HashTable_hasNonStringKeys(hashTable)); HashTable_set(hashTable, HashTable_uint32Key(0), &value); TestCase_assertBoolTrue(HashTable_hasNonStringKeys(hashTable)); HashTable_delete(hashTable, HashTable_uint32Key(0)); HashTable_set(hashTable, HashTable_byteKey(&value, 4), &value); TestCase_assertBoolTrue(HashTable_hasNonStringKeys(hashTable)); HashTable_delete(hashTable, HashTable_byteKey(&value, 4)); HashTable_set(hashTable, HashTable_pointerKey(&value), &value); TestCase_assertBoolTrue(HashTable_hasNonStringKeys(hashTable)); HashTable_delete(hashTable, HashTable_pointerKey(&value)); TestCase_assertBoolFalse(HashTable_hasNonStringKeys(hashTable)); HashTable_dispose(hashTable); } static void testMerge(void) { HashTable * hashTable1 = HashTable_create(4); uint32_t value = 0; HashTable_set(hashTable1, HashTable_uint32Key(0), &value); value = 1; HashTable_set(hashTable1, HashTable_uint32Key(1), &value); HashTable * hashTable2 = HashTable_create(4); value = 2; HashTable_set(hashTable2, HashTable_uint32Key(1), &value); value = 3; HashTable_set(hashTable2, HashTable_uint32Key(2), &value); HashTable_merge(hashTable1, hashTable2); HashTable_dispose(hashTable2); TestCase_assertSizeEqual(hashTable1->count, 3); uint32_t * entry = HashTable_get(hashTable1, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable1, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 2); entry = HashTable_get(hashTable1, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 3); HashTable_dispose(hashTable1); hashTable1 = HashTable_create(4); value = 4; HashTable_set(hashTable1, HashTable_stringKey("a"), &value); value = 5; HashTable_set(hashTable1, HashTable_stringKey("b"), &value); hashTable2 = HashTable_create(4); value = 6; HashTable_set(hashTable2, HashTable_stringKey("a"), &value); HashTable_merge(hashTable1, hashTable2); HashTable_dispose(hashTable2); TestCase_assertSizeEqual(hashTable1->count, 2); entry = HashTable_get(hashTable1, HashTable_stringKey("a")); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 6); entry = HashTable_get(hashTable1, HashTable_stringKey("b")); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 5); HashTable_dispose(hashTable1); } static void testDensityMax(void) { HashTable * hashTable = HashTable_create(1); hashTable->densityMax = 1; uint8_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(0), &value); value = 1; HashTable_set(hashTable, HashTable_uint32Key(1), &value); value = 2; HashTable_set(hashTable, HashTable_uint32Key(2), &value); value = 3; HashTable_set(hashTable, HashTable_uint32Key(3), &value); value = 4; HashTable_set(hashTable, HashTable_uint32Key(4), &value); value = 5; HashTable_set(hashTable, HashTable_uint32Key(5), &value); value = 6; HashTable_set(hashTable, HashTable_uint32Key(6), &value); value = 7; HashTable_set(hashTable, HashTable_uint32Key(7), &value); TestCase_assertSizeEqual(hashTable->bucketCount, 8); value = 8; HashTable_set(hashTable, HashTable_uint32Key(8), &value); TestCase_assertSizeEqual(hashTable->bucketCount, 16); uint8_t * result = HashTable_get(hashTable, HashTable_uint32Key(0)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 0); result = HashTable_get(hashTable, HashTable_uint32Key(1)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 1); result = HashTable_get(hashTable, HashTable_uint32Key(2)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 2); result = HashTable_get(hashTable, HashTable_uint32Key(3)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 3); result = HashTable_get(hashTable, HashTable_uint32Key(4)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 4); result = HashTable_get(hashTable, HashTable_uint32Key(5)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 5); result = HashTable_get(hashTable, HashTable_uint32Key(6)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 6); result = HashTable_get(hashTable, HashTable_uint32Key(7)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 7); result = HashTable_get(hashTable, HashTable_uint32Key(8)); TestCase_assertPointerNonNULL(result); TestCase_assertUIntEqual(*result, 8); HashTable_dispose(hashTable); hashTable = HashTable_create(1); hashTable->densityMax = 2; HashTable_set(hashTable, HashTable_uint32Key(0), &value); HashTable_set(hashTable, HashTable_uint32Key(1), &value); HashTable_set(hashTable, HashTable_uint32Key(2), &value); HashTable_set(hashTable, HashTable_uint32Key(3), &value); HashTable_set(hashTable, HashTable_uint32Key(4), &value); HashTable_set(hashTable, HashTable_uint32Key(5), &value); HashTable_set(hashTable, HashTable_uint32Key(6), &value); HashTable_set(hashTable, HashTable_uint32Key(7), &value); TestCase_assertSizeEqual(hashTable->bucketCount, 8); HashTable_set(hashTable, HashTable_uint32Key(8), &value); TestCase_assertSizeEqual(hashTable->bucketCount, 8); HashTable_dispose(hashTable); } static bool foreachCallback1(HashTable * hashTable, HashTable_key key, void * value, void * context) { uint8_t * results = context; TestCase_assertIntEqual(key.type, HASH_KEY_TYPE_UINT32); TestCase_assert(key.data.uint32 < 3, "Unexpected uint32 key value: %u", key.data.uint32); results[key.data.uint32] = *((uint8_t *) value); return true; } static unsigned int foreachCallback2CallCount; static bool foreachCallback2(HashTable * hashTable, HashTable_key key, void * value, void * context) { *((HashTable_key *) context) = key; *((uint8_t *) value) = 10; foreachCallback2CallCount++; return false; } static void testForeach(void) { HashTable * hashTable = HashTable_create(1); uint8_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(0), &value); value = 2; HashTable_set(hashTable, HashTable_uint32Key(1), &value); value = 5; HashTable_set(hashTable, HashTable_uint32Key(2), &value); uint8_t results[3] = {0xFF, 0xFF, 0xFF}; HashTable_foreach(hashTable, foreachCallback1, results); TestCase_assertUIntEqual(results[0], 0); TestCase_assertUIntEqual(results[1], 2); TestCase_assertUIntEqual(results[2], 5); HashTable_key modifiedKey = {.type = HASH_KEY_TYPE_STRING}; foreachCallback2CallCount = 0; HashTable_foreach(hashTable, foreachCallback2, &modifiedKey); TestCase_assertIntEqual(modifiedKey.type, HASH_KEY_TYPE_UINT32); uint8_t * modifiedValue = HashTable_get(hashTable, modifiedKey); TestCase_assertPointerNonNULL(modifiedValue); TestCase_assertUIntEqual(*modifiedValue, 10); TestCase_assertUIntEqual(foreachCallback2CallCount, 1); HashTable_dispose(hashTable); } static void testObjectKeys(void) { HashTableObjectKeyTest * key1 = HashTableObjectKeyTest_create(0, 0); HashTableObjectKeyTest * key2 = HashTableObjectKeyTest_create(0, 1); HashTableObjectKeyTest * key3 = HashTableObjectKeyTest_create(1, 0); HashTableObjectKeyTest * key1Again = HashTableObjectKeyTest_create(0, 0); HashTable * hashTable = HashTable_create(1); uint8_t * entry = HashTable_get(hashTable, HashTable_objectKey(key1)); TestCase_assertPointerNULL(entry); uint8_t value = 0; HashTable_set(hashTable, HashTable_objectKey(key1), &value); entry = HashTable_get(hashTable, HashTable_objectKey(key1)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable, HashTable_objectKey(key2)); TestCase_assertPointerNULL(entry); entry = HashTable_get(hashTable, HashTable_objectKey(key1Again)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); value = 1; HashTable_set(hashTable, HashTable_objectKey(key2), &value); entry = HashTable_get(hashTable, HashTable_objectKey(key1)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable, HashTable_objectKey(key2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 1); value = 2; HashTable_set(hashTable, HashTable_objectKey(key3), &value); entry = HashTable_get(hashTable, HashTable_objectKey(key1)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 0); entry = HashTable_get(hashTable, HashTable_objectKey(key2)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 1); entry = HashTable_get(hashTable, HashTable_objectKey(key3)); TestCase_assertPointerNonNULL(entry); TestCase_assertUIntEqual(*entry, 2); HashTable_dispose(hashTable); HashTableObjectKeyTest_dispose(key1); HashTableObjectKeyTest_dispose(key2); HashTableObjectKeyTest_dispose(key3); HashTableObjectKeyTest_dispose(key1Again); } static bool deleteMatchingCallback(HashTable * hashTable, HashTable_key key, void * value, void * context) { uint32_t * threshold = context; uint32_t * valueUInt32 = value; TestCase_assertUIntEqual(*valueUInt32, key.data.uint32); return key.data.uint32 > *threshold; } static void testDeleteMatching(void) { HashTable * hashTable = HashTable_create(sizeof(uint32_t)); bool result = HashTable_deleteMatching(hashTable, deleteMatchingCallback, NULL); TestCase_assertBoolFalse(result); uint32_t value = 0; HashTable_set(hashTable, HashTable_uint32Key(0), &value); value = 1; HashTable_set(hashTable, HashTable_uint32Key(1), &value); value = 2; HashTable_set(hashTable, HashTable_uint32Key(2), &value); value = 3; HashTable_set(hashTable, HashTable_uint32Key(3), &value); uint32_t threshold = 1; HashTable_deleteMatching(hashTable, deleteMatchingCallback, &threshold); TestCase_assertSizeEqual(hashTable->count, 2); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(0))); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(1))); TestCase_assertPointerNULL(HashTable_get(hashTable, HashTable_uint32Key(2))); TestCase_assertPointerNULL(HashTable_get(hashTable, HashTable_uint32Key(3))); value = 5; HashTable_set(hashTable, HashTable_uint32Key(5), &value); value = 9; HashTable_set(hashTable, HashTable_uint32Key(9), &value); value = 10; HashTable_set(hashTable, HashTable_uint32Key(10), &value); value = 11; HashTable_set(hashTable, HashTable_uint32Key(11), &value); value = 12; HashTable_set(hashTable, HashTable_uint32Key(12), &value); threshold = 9; HashTable_deleteMatching(hashTable, deleteMatchingCallback, &threshold); TestCase_assertSizeEqual(hashTable->count, 4); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(0))); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(1))); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(5))); TestCase_assertPointerNonNULL(HashTable_get(hashTable, HashTable_uint32Key(9))); TestCase_assertPointerNULL(HashTable_get(hashTable, HashTable_uint32Key(10))); TestCase_assertPointerNULL(HashTable_get(hashTable, HashTable_uint32Key(11))); TestCase_assertPointerNULL(HashTable_get(hashTable, HashTable_uint32Key(12))); HashTable_dispose(hashTable); } TEST_SUITE(HashTableTest, testInit, testKeyMacros, testSetGet, testDeleteValues, testCopy, testListKeys, testKeyAtIndex, testHasNonStringKeys, testMerge, testDensityMax, testForeach, testObjectKeys, testDeleteMatching)