cs240/hw/hw10/extra_tests.c
2018-10-15 17:20:57 -04:00

486 lines
13 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hashtable.h"
#define PASS 1
#define FAIL 0
char* test_discriptions[] = {"Basic test to verify that the table is created correctly",
"Basic test to add a single key",
"Basic set/get pair test",
"Basic test for get() without key",
"A few sets and gets, without any chaining",
"Basic test to see if chaining works"};
int test1() {
/**
* Basic test to verify that the table is created correctly
*/
int ret = PASS;
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) {
printf("Failed to create hashtable!\n");
return FAIL;
}
if (ht->table_len != 1024) {
printf("The hashtable we just created has the wrong table_len!\n");
ret= FAIL;
}
int i;
for (i = 0; i < 1024; i++)
if (ht->table[i] != NULL) {
printf("The hashtable we just created has an entry != NULL even though we have not added anything!\n Remember to clear your newly allcoated memory, or use calloc()\n");
ret= FAIL;
}
free_hashtable(ht);
return ret;
}
/**
* Basic test to add a single key
*/
int test2() {
int ret = 1;
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) {
printf("Failed to create hashtable!\n");
return FAIL;
}
if (set(ht, "Hi bob", 0) != 0) {
printf("set() Failed to set a simple key-value pair!\n");
ret= FAIL;
}
free_hashtable(ht);
return ret;
}
/**
* Basic set/get pair test
*/
int test3() {
int ret = PASS;
double val;
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) {
printf("Failed to create hashtable!\n");
return FAIL;
}
if (set(ht, "Hello", 4.5) != 0) {
printf("set() Failed to set a simple key-value pair!\n");
ret= FAIL;
}
if (get(ht, "Hello", &val) != 0 || val != 4.5) {
printf("get() Failed to get a simple key-value pair we just set, or the value was off!\n");
ret= FAIL;
}
free_hashtable(ht);
return ret;
}
/**
* Basic test for get() without key
*/
int test4() {
int ret = PASS;
double val;
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) {
printf("Failed to create hashtable!\n");
return FAIL;
}
if (get(ht, "No such key", &val) != -1) ret = FAIL;
free_hashtable(ht);
return ret;
}
/**
* A few sets and gets, without any chaining
*/
int test5() {
int ret = PASS;
double val;
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL){
printf("Failed to create hashtable!\n");
return FAIL;
}
/* Use same buffer to catch shallow copies */
char buf[1024];
/* Add four keys */
int i;
for (i = 1; i <= 4; i++) {
sprintf(buf, "MyKey:%d", i);
if (set(ht, buf, 45.0 + i) != 0){
printf("set() Failed to set key: %s\n", buf);
ret= FAIL;
}
if (key_exists(ht, buf) != 1) {
printf("key_exists() Failed to find key we only just set: %s\n", buf);
ret= FAIL; }
}
/* Remove the middle key */
strcpy(buf, "MyKey:2");
if (remove_key(ht, buf) != 0){
printf("remove_key() returned that it Failed to remove key: %s\n", buf);
ret= FAIL;
}
if (key_exists(ht, buf) != 0) {
printf("key_exists() found the key we only just removed: %s\n", buf);
ret= FAIL;
}
/* Ensure we can access two of the others */
strcpy(buf, "MyKey:1");
if (get(ht, buf, &val) != 0 || val != 46.0) {
printf("get() could not get: %s, or the value was wrong.\n", buf);
ret= FAIL;
}
strcpy(buf, "MyKey:4");
if (get(ht, buf, &val) != 0 || val != 49.0) {
printf("get() could not get: %s, or the value was wrong.\n", buf);
ret= FAIL;
}
free_hashtable(ht);
return ret;
}
/**
* Basic test to see if chaining works
*/
int test6() {
int ret = PASS;
double val;
hashtable_t* ht = create_hashtable(1); //This hashtable is WAYYYY TOO SMALL! This will cause chaining
if (ht == NULL){
printf("Failed to create hashtable!\n");
return FAIL;
}
/* Use same buffer to catch shallow copies */
char buf[1024];
/* Add four keys */
int i;
for (i = 1; i <= 4; i++) {
sprintf(buf, "MyKey:%d", i);
if (set(ht, buf, 45.0 + i) != 0){
printf("set() Failed to set key: %s\n", buf);
ret= FAIL;
}
if (key_exists(ht, buf) != 1) {
printf("key_exists() Failed to find key we only just set: %s\n", buf);
ret= FAIL;
}
}
/* Remove the middle key */
strcpy(buf, "MyKey:2");
if (remove_key(ht, buf) != 0){
printf("remove_key() returned that it Failed to remove key: %s\n", buf);
ret= FAIL;
}
if (key_exists(ht, buf) != 0) {
printf("key_exists() found the key we only just removed: %s\n", buf);
ret= FAIL;
}
/* Ensure we can access two of the others */
strcpy(buf, "MyKey:1");
if (get(ht, buf, &val) != 0 || val != 46.0) {
printf("get() could not get: %s, or the value was wrong.\n", buf);
ret= FAIL;
}
strcpy(buf, "MyKey:4");
if (get(ht, buf, &val) != 0 || val != 49.0) {
printf("get() could not get: %s, or the value was wrong.\n", buf);
ret= FAIL;
}
free_hashtable(ht);
return ret;
}
/** START INSTUCTOR TESTS **/
/** Parameter testing **/
/**
* Validate create_hashtable() parameter handling
*/
int test7() {
/* Invalid parameter to create_hashtable() */
hashtable_t* ht = create_hashtable(-1);
if (ht != NULL) return FAIL;
ht = create_hashtable(0);
if (ht != NULL) return FAIL;
return PASS;
}
/**
* Validate free_hashtable() parameter handling
*/
int test8() {
/* Shouldn't crash and Valgrind should come up clean here */
free_hashtable(NULL);
return PASS;
}
/**
* Validate remove_key() parameter handling
*/
int test9() {
hashtable_t* ht = NULL;
if (remove_key(ht, "Key") != -1) return FAIL;
if ((ht = create_hashtable(1024)) == NULL) return FAIL;
if (remove_key(ht, NULL) != -1) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Validate get() parameter handling
*/
int test10() {
hashtable_t* ht = NULL;
/* NULL hashtable param */
double val;
if (get(ht, "Key", &val) != -1) return FAIL;
if ((ht = create_hashtable(256)) == NULL) return FAIL;
if (get(ht, NULL, &val) != -1) return FAIL;
if (get(ht, "Key", NULL) != -1) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Validate set() parameter handling
*/
int test11() {
hashtable_t* ht = NULL;
if (set(ht, "Key", 4.5) != -1) return FAIL;
if ((ht = create_hashtable(1024)) == NULL) return FAIL;
if (set(ht, NULL, 4.5) != -1) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Validate key_exists() parameter handling
*/
int test12() {
hashtable_t* ht = NULL;
if (key_exists(ht, "Key") != -1) return FAIL;
if ((ht = create_hashtable(1024)) == NULL) return FAIL;
if (key_exists(ht, NULL) != -1) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test two nodes in single chain
*/
int test13() {
/* Size 1 forces collisions */
hashtable_t* ht = create_hashtable(1);
if (ht->table_len != 1) return FAIL;
if (ht == NULL) return FAIL;
if (set(ht, "OurKey", 2.4) != 0) return FAIL;
if (set(ht, "OurOtherKey", -0.5) != 0) return FAIL;
double val;
if (get(ht, "OurKey", &val) != 0 || val != 2.4) return FAIL;
if (get(ht, "OurOtherKey", &val) != 0 || val != -0.5) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test basic removal
*/
int test14() {
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) return FAIL;
if (set(ht, "MyKeyForLater", -1040.0) != 0) return FAIL;
if (remove_key(ht, "MyKeyForLater") != 0) return FAIL;
if (key_exists(ht, "MyKeyForLater") != 0) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test very long keys and deep copy
*/
int test15() {
char buf[1024];
char buf2[1024];
memset(buf, 'a', 1023);
memset(buf2, 'a', 1023);
buf[1023] = '\0';
buf2[1023] = '\0';
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) return FAIL;
if (set(ht, buf, 2.4) != 0) return FAIL;
double val;
if (get(ht, buf, &val) != 0 || val != 2.4) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test deep vs. shallow copy of strings
*/
int test16() {
char buf[1024];
char buf2[1024];
memset(buf, 'a', 1023);
memset(buf2, 'a', 1023);
buf[1023] = '\0';
buf2[1023] = '\0';
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) return FAIL;
if (set(ht, buf, 2.4) != 0) return FAIL;
memset(buf, 'b', 1023);
if (set(ht, buf, -5.0) != 0) return FAIL;
double val;
if (get(ht, buf2, &val) != 0 || val != 2.4) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test more complex insertion/deletion sequence
*/
int test17() {
/* Use same buffer to catch shallow copies */
char buf[1024];
hashtable_t* ht = create_hashtable(1024);
if (ht == NULL) return FAIL;
strcpy(buf, "NonExistantKey");
if (key_exists(ht, buf) != 0) return FAIL;
double val;
if (get(ht, buf, &val) != -1) return FAIL;
/* Add four keys */
int i;
for (i = 1; i <= 4; i++) {
sprintf(buf, "MyKey:%d", i);
if (set(ht, buf, 45.0 + i) != 0) return FAIL;
if (key_exists(ht, buf) != 1) return FAIL;
}
/* Remove the middle key */
strcpy(buf, "MyKey:2");
if (remove_key(ht, buf) != 0) return FAIL;
if (key_exists(ht, buf) != 0) return FAIL;
/* Ensure we can access two of the others */
strcpy(buf, "MyKey:1");
if (get(ht, buf, &val) != 0 || val != 46.0) return FAIL;
strcpy(buf, "MyKey:4");
if (get(ht, buf, &val) != 0 || val != 49.0) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Same as previous test, but force chaining
*/
int test18() {
/* Use same buffer to catch shallow copies */
char buf[1024];
hashtable_t* ht = create_hashtable(1);
if (ht == NULL) return FAIL;
strcpy(buf, "NonExistantKey");
if (key_exists(ht, buf) != 0) return FAIL;
double val;
if (get(ht, buf, &val) != -1) return FAIL;
/* Add four keys */
int i;
for (i = 1; i <= 4; i++) {
sprintf(buf, "MyKey:%d", i);
if (set(ht, buf, 45.0 + i) != 0) return FAIL;
if (key_exists(ht, buf) != 1) return FAIL;
}
/* Remove the middle key */
strcpy(buf, "MyKey:2");
if (remove_key(ht, buf) != 0) return FAIL;
if (key_exists(ht, buf) != 0) return FAIL;
/* Ensure we can access two of the others */
strcpy(buf, "MyKey:1");
if (get(ht, buf, &val) != 0 || val != 46.0) return FAIL;
strcpy(buf, "MyKey:4");
if (get(ht, buf, &val) != 0 || val != 49.0) return FAIL;
free_hashtable(ht);
return PASS;
}
/**
* Test that they are storing in the correct slots
* and aren't playing tricks internally
*/
int test19() {
hashtable_t* ht = create_hashtable(32);
if (ht == NULL) return FAIL;
if (ht->table_len != 32) return FAIL;
int i;
for (i = 0; i < ht->table_len; i++)
if (ht->table[i] != NULL) return FAIL;
if (set(ht, "MyKey", 10) != 0) return FAIL;
if (set(ht, "MyOtherKey", 20) != 0) return FAIL;
if (ht->table[hash("MyKey") % ht->table_len] == NULL) return FAIL;
if (ht->table[hash("MyOtherKey") % ht->table_len] == NULL) return FAIL;
free_hashtable(ht);
return PASS;
}
/** END INSTURCTOR TESTS **/
int dispatch_test(int (*test)(), int idx) {
int ret = test();
if(idx< 7){
printf("\n********TEST %d: %s********\n", idx, test_discriptions[idx-1]);
}
if (ret == PASS) fprintf(stderr, "PASS: test%d\n", idx);
else fprintf(stderr, "FAIL: test%d\n", idx);
return ret;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s <caseid>\n", argv[0]);
return 1;
}
int (*tests[])() = {
test1, test2, test3,
test4, test5, test6,
test7, test8, test9,
test10, test11, test12,
test13, test14, test15,
test16, test17, test18,
test19
};
const int testcount = sizeof(tests)/sizeof(int(*)());
int testcase = atoi(argv[1]);
if (testcase == 0) {
int idx, ret = 1;
for (idx = 1; idx <= testcount; idx++)
ret = dispatch_test(tests[idx - 1], idx) && ret;
return !ret;
} else {
return !dispatch_test(tests[testcase - 1], testcase);
}
}