#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "q1.h"
#define LIST_AS_STR_MAX_SIZE 3000
#define NODE_AS_STR_MAX_SIZE 50
Node copyNode(Node n) {
Node newNode = malloc(sizeof(*n));
newNode->x = n->x;
return newNode;
}
void freeListSol(Node list) {
if (list == NULL) {
return;
}
Node prev;
while (list) {
prev = list;
list = list->next;
free(prev);
}
}
int getListLength(Node list) {
int count = 0;
while (list) {
count++;
list = list->next;
}
return count;
}
bool isListSorted(Node list) {
if (list == NULL) {
return true;
}
int prev = list->x;
list = list->next;
while (list != NULL) {
if (prev > list->x) {
return false;
}
prev = list->x;
list = list->next;
}
return true;
}
Node copyList(Node list) {
Node head = malloc(sizeof(*head)), curr = head;
head->next = NULL;
while (list) {
curr->next = malloc(sizeof(*curr));
curr = curr->next;
curr->next = NULL;
curr->x = list->x;
list = list->next;
}
if (curr == head) {
free(head);
return NULL;
}
curr = head->next;
free(head);
return curr;
}
Node sortedMergeSol(Node a, Node b) {
Node result = NULL; /* Base cases */
if (a == NULL)
return copyList(b);
else if (b == NULL)
return copyList(a); /* Pick either a or b, and recur */
if (a->x <= b->x) {
result = copyNode(a);
result->next = sortedMergeSol(a->next, b);
} else {
result = copyNode(b);
result->next = sortedMergeSol(a, b->next);
}
return (result);
}
char *listToString(Node list) {
char *str = malloc(sizeof(char) * LIST_AS_STR_MAX_SIZE);
assert(str != NULL);
str[0] = '\0';
char buff[NODE_AS_STR_MAX_SIZE];
while (list != NULL) {
sprintf(buff, "%d->", list->x);
strncat(str, buff, NODE_AS_STR_MAX_SIZE);
list = list->next;
}
strcat(str, "NULL");
return str;
}
bool areListsEqual(Node list1, Node list2) {
while (list1 != NULL || list2 != NULL) {
if (list1 == NULL || list2 == NULL || list1->x != list2->x) {
return false;
}
list1 = list1->next;
list2 = list2->next;
}
return true;
}
bool testOnce(int test_num) {
Node lists[] = {malloc(sizeof(*lists[0])), malloc(sizeof(*lists[1]))};
for (int i = 0; i < 2; i++) {
Node curr = lists[i];
curr->x = rand() % 100 - 40;
int count = rand() % 20; // Random length for the list
int tmp_value;
while (count > 0) {
curr->next = malloc(sizeof(*lists[i]));
// tmp_value = rand() % 1;
tmp_value = rand() % 400;
tmp_value = tmp_value ? (rand() % 5) : (-1);
curr->next->x =
curr->x +
tmp_value; // Generate a series which is likely rising
curr = curr->next;
count--;
}
curr->next = NULL;
curr = lists[i];
lists[i] = lists[i]->next;
free(curr);
}
char *list1_before = listToString(lists[0]);
char *list2_before = listToString(lists[1]);
// printf("List1 before:\n\t%s\n", list1_before);
Node merged_actual = NULL, merged_expected = NULL;
Node *merge_actual_address = (rand() % 10) ? &merged_actual : NULL;
ErrorCode merge_status =
mergeSortedLists(lists[0], lists[1], merge_actual_address);
char *list1_after = listToString(lists[0]);
char *list2_after = listToString(lists[1]);
if (merge_actual_address && lists[0] && lists[1] &&
isListSorted(lists[0]) && isListSorted(lists[1])) {
merged_expected = sortedMergeSol(lists[0], lists[1]);
}
bool status = true;
if (lists[0] == NULL || lists[1] == NULL) {
if (merge_status != EMPTY_LIST) {
printf("Extecped status EMPTY_LIST (%d) but got %d\n", EMPTY_LIST,
merge_status);
status = false;
}
} else if (!isListSorted(lists[0]) || !isListSorted(lists[1])) {
if (merge_status != UNSORTED_LIST) {
printf("Extecped status UNSORTED_LIST (%d) but got %d\n",
UNSORTED_LIST, merge_status);
status = false;
}
} else if (merge_actual_address == NULL) {
if (merge_status != NULL_ARGUMENT) {
printf("Extecped status NULL_ARGUMENT (%d) but got %d\n",
NULL_ARGUMENT, merge_status);
status = false;
}
} else if (merge_status == MEMORY_ERROR) {
if (merged_actual != NULL) {
printf(
"Extecped merged_actual (MEMORY_ERROR) to be NULL but got %p\n",
(void *)merged_actual);
status = false;
}
} else {
status = status && areListsEqual(merged_actual, merged_expected);
}
char *merged_expected_str = NULL, *merged_actual_str = NULL;
if (strcmp(list1_before, list1_after) ||
strcmp(list2_before, list2_after) || !status) {
fprintf(stderr, "\n\n======= Test #%d Failed ========\n", test_num);
fprintf(stderr, "List1 before:\n");
fprintf(stderr, "\t%s\n", list1_before);
fprintf(stderr, "List2 before:\n");
fprintf(stderr, "\t%s\n", list2_before);
fprintf(stderr, "List1 after:\n");
fprintf(stderr, "\t%s\n", list1_after);
fprintf(stderr, "List2 after:\n");
fprintf(stderr, "\t%s\n", list2_after);
fprintf(stderr, "Merged expected:\n");
merged_expected_str = listToString(merged_expected);
fprintf(stderr, "\t%s\n", merged_expected_str);
fprintf(stderr, "Merged actual:\n");
merged_actual_str = listToString(merged_actual);
fprintf(stderr, "\t%s\n", merged_actual_str);
status = false;
}
free(list1_before);
free(list1_after);
free(list2_before);
free(list2_after);
free(merged_expected_str);
free(merged_actual_str);
freeListSol(merged_actual);
freeListSol(merged_expected);
freeListSol(lists[0]);
freeListSol(lists[1]);
return status;
}
void printUsage(char *name) { printf("Usage:\n%s [NUM_OF_TESTS]\n", name); }
int main(int argc, char **argv) {
int count = 0, failures = 0;
if (argc == 2 && sscanf(argv[1], "%d", &count) == 1) {
printf("Running %d random tests...\n", count);
} else {
printUsage(argv[0]);
return 1;
}
srand(time(0));
for (int i = 0; i < count; i++) {
if (!testOnce(i)) {
failures++;
}
}
printf("%d failures out of %d tests\n", failures, count);
}
Comments