/* REF ARRAY Implementation of the dynamic array with reference count. Copyright (C) Dmitri Pal 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config.h" #include /* for errors */ #include #include #include #include #include "ref_array.h" #define TRACE_HOME #include "trace.h" int verbose = 0; #define RAOUT(foo) \ do { \ if (verbose) foo; \ } while(0) extern void ref_array_debug(struct ref_array *ra, int num); typedef int (*test_fn)(void); /* Basic test */ int ref_array_basic_test(void) { const char *line1 = "line1"; const char *line2 = "line2"; const char *line3 = "line3"; const char *line4 = "line4"; const char *line5 = "line5"; const char *line6 = "line6"; uint32_t i; struct ref_array *ra; struct ref_array *ra2; int error = EOK; uint32_t len = 0; uint32_t other_len = 0; char *ret; char *elem; void *ptr; error = ref_array_create(&ra, sizeof(char *), 1, NULL, NULL); if (error) { printf("Failed to create array %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line1); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 1 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line2); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 2 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line3); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 3 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line4); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 4 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line5); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 5 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line6); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 6 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); RAOUT(printf("\n\nTest 1 - Printing lines.\n\n")); error = ref_array_getlen(ra, &other_len); if (error) { ref_array_destroy(ra); printf("Failed to get length %d\n", error); return error; } len = ref_array_len(ra); if (len != other_len) { ref_array_destroy(ra); printf("Lengths do not match:\n"); printf("Len : %d\n", len); printf("Get Len: %d\n", other_len); return EFAULT; } for (i = 0; i < len; i++) { ref_array_get(ra, i, &ret); RAOUT(printf("%s\n", ret)); } RAOUT(printf("\n\nTest 2 - Creating reference and then printing lines.\n\n")); ra2 = ref_array_getref(ra); ref_array_destroy(ra); for (i = 0; i < len; i++) { ret = *((char **)ref_array_get(ra2, i, NULL)); RAOUT(printf("%s\n", ret)); } RAOUT(printf("\n\nTest 3 - Get elements with copying.\n\n")); for (i = 0; i < len; i++) { ref_array_get(ra2, i, &ret); RAOUT(printf("%s\n", ret)); } RAOUT(printf("\n\nTest 4a - Get elements with copying and assignment.\n\n")); /* This is a bad practice to use one variable * as a parameter and as an acceptor for the return value. * See next example for a better way to do it. */ for (i = 0; i < len; i++) { ret = *((char **)ref_array_get(ra2, i, &ret)); RAOUT(printf("%s\n", ret)); } RAOUT(printf("\n\nTest 4b - Get elements with copying and assignment.\n\n")); for (i = 0; i < len; i++) { ret = *((char **)ref_array_get(ra2, i, &elem)); RAOUT(printf("%s\n", ret)); RAOUT(printf("%s\n", elem)); if (strcmp(ret, elem) != 0) { ref_array_destroy(ra2); printf("\nRetrieved strings were expected to be same,\n"); printf("but they are not:\n"); printf("By pointer:[%s]\nAs element:[%s]\n", ret, elem); return EFAULT; } } RAOUT(printf("\n\nTest 5 - While loop up.\n\n")); i = 0; for (;;) { ptr = ref_array_get(ra2, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } RAOUT(printf("\n\nTest 6 - While loop down.\n\n")); i = len - 1; for (;;) { ptr = ref_array_get(ra2, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i--; } else break; } RAOUT(printf("\n\nDone!!!\n\n")); ref_array_destroy(ra2); return EOK; } void array_cleanup(void *elem, ref_array_del_enum type, void *data) { RAOUT(printf("%s%s\n", (char *)data, *((char **)elem))); free(*((char **)elem)); } /* Free test */ int ref_array_free_test(void) { const char *line1 = "line1"; const char *line2 = "line2"; const char *line3 = "line3"; const char *line4 = "line4"; char text[] = "Deleting: "; char *str; uint32_t i; struct ref_array *ra; int error = EOK; char *ret; void *ptr; error = ref_array_create(&ra, sizeof(char *), 1, array_cleanup, (char *)text); if (error) { printf("Failed to create array %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); str = strdup(line1); error = ref_array_append(ra, &str); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 1 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); str = strdup(line2); error = ref_array_append(ra, &str); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 2 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); str = strdup(line3); error = ref_array_append(ra, &str); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 3 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); str = strdup(line4); error = ref_array_append(ra, &str); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 4 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } RAOUT(printf("\n\nDone!!!\n\n")); ref_array_destroy(ra); return EOK; } int ref_array_adv_test(void) { int error = EOK; const char *lines[] = { "line0", "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8", "line9" }; char text[] = "Deleting: "; char *str; uint32_t i; struct ref_array *ra; char *ret; void *ptr; int expected[] = { 0, 1, 7, 8, 9 }; int expected2[] = { 1, 7, 8, 9, 0 }; error = ref_array_create(&ra, sizeof(char *), 1, array_cleanup, (char *)text); if (error) { printf("Failed to create array %d\n", error); return error; } for (i = 0; i < 5;i++) { str = strdup(lines[i]); error = ref_array_append(ra, &str); if (error) { ref_array_destroy(ra); printf("Failed to append line %d, error %d\n", i, error); return error; } } RAOUT(printf("\nInitial array.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } /* Try to remove invalid entry */ error = ref_array_remove(ra, 1000); if (error != ERANGE) { ref_array_destroy(ra); printf("Removing entry expected error got success.\n"); return -1; } /* Try to insert invalid entry */ error = ref_array_insert(ra, 1000, &text); if (error != ERANGE) { ref_array_destroy(ra); printf("Inserting entry expected error got success.\n"); return -1; } /* Try to replace invalid entry */ error = ref_array_replace(ra, 1000, &text); if (error != ERANGE) { ref_array_destroy(ra); printf("Replacing entry expected error got success.\n"); return -1; } /* Insert several entries */ for (i = 9; i > 4; i--) { str = strdup(lines[i]); error = ref_array_insert(ra, 9 - i, &str); if (error) { ref_array_destroy(ra); free(str); printf("Failed to insert line %d, error %d\n", i, error); return error; } } /* Displpay array contents */ RAOUT(printf("\nArray with inserted values.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } /* Replace everything */ for (i = 0; i < 10;i++) { str = strdup(lines[i]); error = ref_array_replace(ra, i, &str); if (error) { ref_array_destroy(ra); free(str); printf("Failed to replace line %d, error %d\n", i, error); return error; } } /* Displpay array contents */ RAOUT(printf("\nArray with replaced values.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } /* Reset */ ref_array_reset(ra); /* Displpay array contents */ RAOUT(printf("\nEmpty array.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } /* Add everything */ for (i = 0; i < 10;i++) { str = strdup(lines[i]); error = ref_array_insert(ra, i, &str); if (error) { ref_array_destroy(ra); free(str); printf("Failed to insert into array %d\n", error); return error; } } /* Displpay array contents */ RAOUT(printf("\nAll added back.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } /* Remove part */ for (i = 0; i < 5;i++) { error = ref_array_remove(ra, 2); if (error) { ref_array_destroy(ra); printf("Failed to remive item from array %d\n", error); return error; } } /* Displpay array contents */ RAOUT(printf("\nCleaned array.\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("%s\n", ret)); i++; } else break; } RAOUT(printf("\n\nChecking for expected contents\n\n")); i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("Comparing:\n[%s]\n[%s]\n\n", ret, lines[expected[i]])); if (strcmp(ret, lines[expected[i]]) != 0) { printf("Unexpected contents of the array.\n"); ref_array_destroy(ra); return -1; } i++; } else break; } RAOUT(printf("\n\nSwap test\n\n")); if ((error = ref_array_swap(ra, 0, 1)) || (error = ref_array_swap(ra, 1, 2)) || (error = ref_array_swap(ra, 2, 3)) || (error = ref_array_swap(ra, 3, 4))) { ref_array_destroy(ra); printf("Failed to to swap %d\n", error); return error; } i = 0; for (;;) { ptr = ref_array_get(ra, i, &ret); if (ptr) { RAOUT(printf("Comparing:\n[%s]\n[%s]\n\n", ret, lines[expected2[i]])); if (strcmp(ret, lines[expected2[i]]) != 0) { printf("Unexpected contents of the array.\n"); ref_array_destroy(ra); return -1; } i++; } else break; } RAOUT(printf("\n\nDone!!!\n\n")); ref_array_destroy(ra); return EOK; } int copy_cb(void *elem, void *new_elem) { char *ne = NULL; ne = strdup(*((char **)elem)); *((char **)new_elem) = ne; RAOUT(printf("Source: %s\nCopy:%s\n", *((char **)elem), ne)); return EOK; } int ref_array_copy_test(void) { const char *line1 = "line1"; const char *line2 = "line2"; const char *line3 = "line3"; const char *line4 = "line4"; const char *line5 = "line5"; const char *line6 = "line6"; uint32_t i; struct ref_array *ra; struct ref_array *ra2; int error = EOK; uint32_t len = 6; char text[] = "Deleting: "; error = ref_array_create(&ra, sizeof(char *), 1, NULL, NULL); if (error) { printf("Failed to create array %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line1); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 1 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line2); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 2 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line3); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 3 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line4); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 4 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line5); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 5 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); error = ref_array_append(ra, &line6); if (error) { ref_array_destroy(ra); printf("Failed to append to array line 6 %d\n", error); return error; } RAOUT(ref_array_debug(ra, 0)); RAOUT(printf("\n\nCopy lines.\n\n")); error = ref_array_copy(ra, copy_cb, array_cleanup, (char *)text, &ra2); if (error) { ref_array_destroy(ra); printf("Failed to copy array %d\n", error); return error; } for (i = 0; i < len; i++) { if (strcmp(*((char **)ref_array_get(ra, i, NULL)), *((char **)ref_array_get(ra2, i, NULL))) != 0) { printf("\nRetrieved strings were expected to be same,\n"); printf("but they are not:\n"); printf("First:[%s]\nSecond:[%s]\n", *((char **)ref_array_get(ra, i, NULL)), *((char **)ref_array_get(ra2, i, NULL))); ref_array_destroy(ra); ref_array_destroy(ra2); return EFAULT; } } RAOUT(printf("\n\nSource array.\n\n")); RAOUT(ref_array_debug(ra, 0)); ref_array_destroy(ra); RAOUT(printf("\n\nAbout to destroy a copy.\n\n")); RAOUT(ref_array_debug(ra2, 0)); ref_array_destroy(ra2); RAOUT(printf("\n\nDone!!!\n\n")); return EOK; } int ref_array_copy_num_test(void) { uint32_t i,j,k; struct ref_array *ra; struct ref_array *ra2; int error = EOK; uint32_t len = 5; error = ref_array_create(&ra, sizeof(uint32_t), 1, NULL, NULL); if (error) { printf("Failed to create array %d\n", error); return error; } RAOUT(ref_array_debug(ra, 1)); for (i = 0; i < len; i++) { error = ref_array_append(ra, &i); if (error) { ref_array_destroy(ra); printf("Failed to append number to array %d\n", error); return error; } RAOUT(ref_array_debug(ra, 1)); } RAOUT(printf("\n\nCopy num test.\n\n")); error = ref_array_copy(ra, NULL, NULL, NULL, &ra2); if (error) { ref_array_destroy(ra); printf("Failed to copy array %d\n", error); return error; } for (i = 0; i < len; i++) { j = *((uint32_t *)(ref_array_get(ra, i, NULL))); k = *((uint32_t *)(ref_array_get(ra2, i, NULL))); if (j != k) { printf("\nRetrieved values were expected to be same,\n"); printf("but they are not:\n"); printf("First:[%d]\nSecond:[%d]\n", j, k); ref_array_destroy(ra); ref_array_destroy(ra2); return EFAULT; } } ref_array_destroy(ra); ref_array_destroy(ra2); RAOUT(printf("\n\nDone!!!\n\n")); return EOK; } /* Main function of the unit test */ int main(int argc, char *argv[]) { int error = 0; test_fn tests[] = { ref_array_basic_test, ref_array_free_test, ref_array_adv_test, ref_array_copy_test, ref_array_copy_num_test, NULL }; test_fn t; int i = 0; char *var; if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = 1; else { var = getenv("COMMON_TEST_VERBOSE"); if (var) verbose = 1; } RAOUT(printf("Start\n")); while ((t = tests[i++])) { error = t(); if (error) { RAOUT(printf("Failed with error %d!\n", error)); return error; } } RAOUT(printf("Success!\n")); return 0; }