aboutsummaryrefslogtreecommitdiff
path: root/tests/test_strlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_strlist.c')
-rw-r--r--tests/test_strlist.c617
1 files changed, 617 insertions, 0 deletions
diff --git a/tests/test_strlist.c b/tests/test_strlist.c
new file mode 100644
index 0000000..aa9eb4e
--- /dev/null
+++ b/tests/test_strlist.c
@@ -0,0 +1,617 @@
+#include "testing.h"
+
+#define BOILERPLATE_TEST_STRLIST_AS_TYPE(FUNC, TYPE) \
+do { \
+ struct StrList *list; \
+ list = strlist_init(); \
+ for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { \
+ strlist_append(&list, (char *) tc[i].data); \
+ result = FUNC(list, i); \
+ if (!strlist_errno) { \
+ OMC_ASSERT(result == (TYPE) tc[i].expected, "unexpected numeric result"); \
+ } \
+ } \
+ guard_strlist_free(&list); \
+} while (0)
+
+void test_strlist_init() {
+ struct StrList *list;
+ list = strlist_init();
+ OMC_ASSERT(list != NULL, "list should not be NULL");
+ OMC_ASSERT(list->num_alloc == 1, "fresh list should have one record allocated");
+ OMC_ASSERT(list->num_inuse == 0, "fresh list should have no records in use");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_free() {
+ struct StrList *list;
+ list = strlist_init();
+ strlist_free(&list);
+ // Not entirely sure what to assert here. On failure, it'll probably segfault.
+}
+
+void test_strlist_append() {
+ struct testcase {
+ const char *data;
+ const size_t expected_in_use;
+ const char *expected;
+ };
+
+ struct testcase tc[] = {
+ {.data = "I have a pencil box.", .expected_in_use = 1},
+ {.data = "A rectangular pencil box.", .expected_in_use = 2},
+ {.data = "If I need a pencil I know where to get one.", .expected_in_use = 3},
+ };
+
+ struct StrList *list;
+ list = strlist_init();
+ for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
+ strlist_append(&list, (char *) tc[i].data);
+ OMC_ASSERT(list->num_inuse == tc[i].expected_in_use, "incorrect number of records in use");
+ OMC_ASSERT(list->num_alloc == tc[i].expected_in_use + 1, "incorrect number of records allocated");
+ OMC_ASSERT(strcmp(strlist_item(list, i), tc[i].data) == 0, "value was appended incorrectly. data mismatch.");
+ }
+ guard_strlist_free(&list);
+}
+
+void test_strlist_append_many_records() {
+ struct StrList *list;
+ list = strlist_init();
+ size_t maxrec = 10240;
+ const char *data = "There are many strings but this one is mine.";
+ for (size_t i = 0; i < maxrec; i++) {
+ strlist_append(&list, (char *) data);
+ }
+ OMC_ASSERT(strlist_count(list) == maxrec, "record count mismatch");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_set() {
+ struct StrList *list;
+ list = strlist_init();
+ size_t maxrec = 100;
+ const char *data = "There are many strings but this one is mine.";
+ const char *replacement_short = "A shorter string.";
+ const char *replacement_long = "A longer string ensures the array grows correctly.";
+ int set_resize_long_all_ok = 0;
+ int set_resize_short_all_ok = 0;
+
+ for (size_t i = 0; i < maxrec; i++) {
+ strlist_append(&list, (char *) data);
+ }
+
+ for (size_t i = 0; i < maxrec; i++) {
+ int result;
+ strlist_set(&list, i, (char *) replacement_long);
+ result = strcmp(strlist_item(list, i), replacement_long) == 0;
+ set_resize_long_all_ok += result;
+ }
+ OMC_ASSERT(set_resize_long_all_ok == (int) maxrec, "Replacing record with longer strings failed");
+
+ for (size_t i = 0; i < maxrec; i++) {
+ int result;
+ strlist_set(&list, i, (char *) replacement_short);
+ result = strcmp(strlist_item(list, i), replacement_short) == 0;
+ set_resize_short_all_ok += result;
+ }
+ OMC_ASSERT(set_resize_short_all_ok == (int) maxrec, "Replacing record with shorter strings failed");
+
+ OMC_ASSERT(strlist_count(list) == maxrec, "record count mismatch");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_append_file() {
+ struct testcase {
+ const char *origin;
+ const char **expected;
+ };
+ const char *expected[] = {
+ "Do not delete this file.\n",
+ "Do not delete this file.\n",
+ "Do not delete this file.\n",
+ "Do not delete this file.\n",
+ NULL,
+ };
+ const char *local_filename = "test_strlist_append_file.txt";
+
+ struct testcase tc[] = {
+ {.origin = "https://ssb.stsci.edu/jhunk/omc_test/test_strlist_append_file_from_remote.txt", .expected = expected},
+ {.origin = local_filename, .expected = expected},
+ };
+
+ FILE *fp;
+ fp = fopen(local_filename, "w");
+ if (!fp) {
+ OMC_ASSERT(false, "unable to open local file for writing");
+ }
+ for (size_t i = 0; expected[i] != NULL; i++) {
+ fprintf(fp, "%s", expected[i]);
+ }
+ fclose(fp);
+
+ for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
+ struct StrList *list;
+ list = strlist_init();
+ if (!list) {
+ OMC_ASSERT(false, "failed to create list");
+ return;
+ }
+ strlist_append_file(list, (char *) tc[i].origin, NULL);
+ for (size_t z = 0; z < strlist_count(list); z++) {
+ const char *left;
+ const char *right;
+ left = strlist_item(list, z);
+ right = expected[z];
+ OMC_ASSERT(strcmp(left, right) == 0, "file content is different than expected");
+ }
+ OMC_ASSERT(strcmp_array(list->data, expected) == 0, "file contents does not match expected values");
+ guard_strlist_free(&list);
+ }
+}
+
+void test_strlist_append_strlist() {
+ struct StrList *left;
+ struct StrList *right;
+ left = strlist_init();
+ right = strlist_init();
+
+ strlist_append(&right, "A");
+ strlist_append(&right, "B");
+ strlist_append(&right, "C");
+ strlist_append_strlist(left, right);
+ OMC_ASSERT(strlist_cmp(left, right) == 0, "left and right should be identical");
+ strlist_append_strlist(left, right);
+ OMC_ASSERT(strlist_cmp(left, right) == 1, "left and right should be different");
+ OMC_ASSERT(strlist_count(left) > strlist_count(right), "left should be larger than right");
+ guard_strlist_free(&left);
+ guard_strlist_free(&right);
+}
+
+void test_strlist_append_array() {
+ const char *data[] = {
+ "Appending",
+ "Some",
+ "Data",
+ NULL,
+ };
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_array(list, (char **) data);
+ size_t result = 0;
+ for (size_t i = 0; i < strlist_count(list); i++) {
+ char *item = strlist_item(list, i);
+ result += strcmp(item, data[i]) == 0;
+ }
+ OMC_ASSERT(result == strlist_count(list), "result is not identical to input");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_append_tokenize() {
+ const char *data = "This is a test.\nWe will split this string\ninto three list records\n";
+ size_t line_count = num_chars(data, '\n');
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_tokenize(list, (char *) data, "\n");
+ // note: the trailing '\n' in the data is parsed as a token
+ OMC_ASSERT(line_count + 1 == strlist_count(list), "unexpected number of lines in array");
+ int trailing_item_is_empty = isempty(strlist_item(list, strlist_count(list) - 1));
+ OMC_ASSERT(trailing_item_is_empty, "trailing record should be an empty string");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_copy() {
+ struct StrList *list = strlist_init();
+ struct StrList *list_copy;
+
+ strlist_append(&list, "Make a copy");
+ strlist_append(&list, "of this data");
+ strlist_append(&list, "1:1, please");
+
+ OMC_ASSERT(strlist_copy(NULL) == NULL, "NULL argument should return NULL");
+
+ list_copy = strlist_copy(list);
+ OMC_ASSERT(strlist_cmp(list, list_copy) == 0, "list was copied incorrectly");
+ guard_strlist_free(&list);
+ guard_strlist_free(&list_copy);
+}
+
+void test_strlist_remove() {
+ const char *data[] = {
+ "keep this",
+ "remove this",
+ "keep this",
+ "remove this",
+ "keep this",
+ "remove this",
+ };
+ struct StrList *list;
+ list = strlist_init();
+ size_t data_size = sizeof(data) / sizeof(*data);
+ for (size_t i = 0; i < data_size; i++) {
+ strlist_append(&list, (char *) data[i]);
+ }
+
+ size_t len_before = strlist_count(list);
+ size_t removed = 0;
+ for (size_t i = 0; i < len_before; i++) {
+ char *item = strlist_item(list, i);
+ if (startswith(item, "remove")) {
+ strlist_remove(list, i);
+ removed++;
+ }
+ }
+ size_t len_after = strlist_count(list);
+ OMC_ASSERT(len_before == data_size, "list length before modification is incorrect. new records?");
+ OMC_ASSERT(len_after == (len_before - removed), "list length after modification is incorrect. not enough records removed.");
+
+ guard_strlist_free(&list);
+}
+
+void test_strlist_cmp() {
+ struct StrList *left;
+ struct StrList *right;
+
+ left = strlist_init();
+ right = strlist_init();
+ OMC_ASSERT(strlist_cmp(NULL, NULL) == -1, "NULL first argument should return -1");
+ OMC_ASSERT(strlist_cmp(left, NULL) == -2, "NULL second argument should return -2");
+ OMC_ASSERT(strlist_cmp(left, right) == 0, "should be the same");
+ strlist_append(&left, "left");
+ OMC_ASSERT(strlist_cmp(left, right) == 1, "should return 1");
+ strlist_append(&right, "right");
+ OMC_ASSERT(strlist_cmp(left, right) == 1, "should return 1");
+ strlist_append(&left, "left again");
+ strlist_append(&left, "left again");
+ strlist_append(&left, "left again");
+ OMC_ASSERT(strlist_cmp(left, right) == 1, "should return 1");
+ OMC_ASSERT(strlist_cmp(right, left) == 1, "should return 1");
+ guard_strlist_free(&left);
+ guard_strlist_free(&right);
+}
+
+void test_strlist_reverse() {
+ const char *data[] = {
+ "a", "b", "c", "d", NULL
+ };
+ const char *expected[] = {
+ "d", "c", "b", "a", NULL
+ };
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_array(list, (char **) data);
+
+ strlist_reverse(list);
+ int result = 0;
+ for (size_t i = 0; i < strlist_count(list); i++) {
+ char *item = strlist_item(list, i);
+ result += strcmp(item, expected[i]) == 0;
+ }
+ OMC_ASSERT(result == (int) strlist_count(list), "alphabetic sort failed");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_count() {
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append(&list, "abc");
+ strlist_append(&list, "123");
+ strlist_append(&list, "def");
+ strlist_append(&list, "456");
+ OMC_ASSERT(strlist_count(NULL) == 0, "NULL input should produce a zero result");
+ OMC_ASSERT(strlist_count(list) == 4, "incorrect record count");
+
+ guard_strlist_free(&list);
+}
+
+void test_strlist_sort_alphabetic() {
+ const char *data[] = {
+ "b", "c", "d", "a", NULL
+ };
+ const char *expected[] = {
+ "a", "b", "c", "d", NULL
+ };
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_array(list, (char **) data);
+
+ strlist_sort(list, OMC_SORT_ALPHA);
+ int result = 0;
+ for (size_t i = 0; i < strlist_count(list); i++) {
+ char *item = strlist_item(list, i);
+ result += strcmp(item, expected[i]) == 0;
+ }
+ OMC_ASSERT(result == (int) strlist_count(list), "alphabetic sort failed");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_sort_len_ascending() {
+ const char *data[] = {
+ "bb", "ccc", "dddd", "a", NULL
+ };
+ const char *expected[] = {
+ "a", "bb", "ccc", "dddd", NULL
+ };
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_array(list, (char **) data);
+
+ strlist_sort(list, OMC_SORT_LEN_ASCENDING);
+ int result = 0;
+ for (size_t i = 0; i < strlist_count(list); i++) {
+ char *item = strlist_item(list, i);
+ result += strcmp(item, expected[i]) == 0;
+ }
+ OMC_ASSERT(result == (int) strlist_count(list), "ascending sort failed");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_sort_len_descending() {
+ const char *data[] = {
+ "bb", "ccc", "dddd", "a", NULL
+ };
+ const char *expected[] = {
+ "dddd", "ccc", "bb", "a", NULL
+ };
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append_array(list, (char **) data);
+
+ strlist_sort(list, OMC_SORT_LEN_DESCENDING);
+ int result = 0;
+ for (size_t i = 0; i < strlist_count(list); i++) {
+ char *item = strlist_item(list, i);
+ result += strcmp(item, expected[i]) == 0;
+ }
+ OMC_ASSERT(result == (int) strlist_count(list), "descending sort failed");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_item_as_str() {
+ struct StrList *list;
+ list = strlist_init();
+ strlist_append(&list, "hello");
+ OMC_ASSERT(strcmp(strlist_item_as_str(list, 0), "hello") == 0, "unexpected string result");
+ guard_strlist_free(&list);
+}
+
+void test_strlist_item_as_char() {
+ char result = 0;
+ struct testcase {
+ const char *data;
+ const char expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-129", .expected = 127}, // rollover
+ {.data = "-128", .expected = -128},
+ {.data = "-1", .expected = -1},
+ {.data = "1", .expected = 1},
+ {.data = "127", .expected = 127},
+ {.data = "128", .expected = -128}, // rollover
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_char, char);
+}
+
+void test_strlist_item_as_uchar() {
+ int result;
+ struct testcase {
+ const char *data;
+ const unsigned char expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = 255},
+ {.data = "1", .expected = 1},
+ {.data = "255", .expected = 255},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_uchar, unsigned char);
+}
+
+void test_strlist_item_as_short() {
+ int result;
+ struct testcase {
+ const char *data;
+ const short expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-32769", .expected = 32767}, // rollover
+ {.data = "-32768", .expected = -32768},
+ {.data = "-1", .expected = -1},
+ {.data = "1", .expected = 1},
+ {.data = "32767", .expected = 32767},
+ {.data = "32768", .expected = -32768}, // rollover
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_short, short);
+}
+
+void test_strlist_item_as_ushort() {
+ int result;
+ struct testcase {
+ const char *data;
+ const unsigned short expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = 65535},
+ {.data = "1", .expected = 1},
+ {.data = "65535", .expected = 65535},
+ {.data = "65536", .expected = 0}, // rollover
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_ushort, unsigned short);
+}
+
+// From here on the values are different between architectures. Do very basic tests.
+void test_strlist_item_as_int() {
+ int result;
+ struct testcase {
+ const char *data;
+ const int expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = -1},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_int, int);
+}
+
+void test_strlist_item_as_uint() {
+ unsigned int result;
+ struct testcase {
+ const char *data;
+ const unsigned int expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = UINT_MAX},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_uint, unsigned int);
+}
+
+void test_strlist_item_as_long() {
+ long result;
+ struct testcase {
+ const char *data;
+ const long expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = -1},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_long, long);
+}
+
+void test_strlist_item_as_ulong() {
+ unsigned long result;
+ struct testcase {
+ const char *data;
+ const unsigned long expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = ULONG_MAX},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_ulong, unsigned long);
+}
+
+void test_strlist_item_as_long_long() {
+ long long result;
+ struct testcase {
+ const char *data;
+ const long long expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = -1},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_long_long, long long);
+}
+
+void test_strlist_item_as_ulong_long() {
+ unsigned long long result;
+ struct testcase {
+ const char *data;
+ const unsigned long long expected;
+ };
+ struct testcase tc[] = {
+ {.data = "-1", .expected = ULLONG_MAX},
+ {.data = "1", .expected = 1},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_ulong_long, unsigned long long);
+}
+
+void test_strlist_item_as_float() {
+ float result;
+ struct testcase {
+ const char *data;
+ const float expected;
+ };
+ struct testcase tc[] = {
+ {.data = "1.0", .expected = 1.0f},
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_float, float);
+}
+
+void test_strlist_item_as_double() {
+ double result;
+ struct testcase {
+ const char *data;
+ const double expected;
+ };
+ struct testcase tc[] = {
+ {.data = "1.0", .expected = 1.0f},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_float, double);
+}
+
+void test_strlist_item_as_long_double() {
+ long double result;
+ struct testcase {
+ const char *data;
+ const long double expected;
+ };
+ struct testcase tc[] = {
+ {.data = "1.0", .expected = 1.0f},
+ {.data = "abc", .expected = 0}, // error
+ };
+
+ BOILERPLATE_TEST_STRLIST_AS_TYPE(strlist_item_as_float, long double);
+}
+
+int main(int argc, char *argv[]) {
+ OMC_TEST_BEGIN_MAIN();
+ OMC_TEST_FUNC *tests[] = {
+ test_strlist_init,
+ test_strlist_free,
+ test_strlist_append,
+ test_strlist_append_many_records,
+ test_strlist_set,
+ test_strlist_append_file,
+ test_strlist_append_strlist,
+ test_strlist_append_tokenize,
+ test_strlist_append_array,
+ test_strlist_copy,
+ test_strlist_remove,
+ test_strlist_cmp,
+ test_strlist_sort_alphabetic,
+ test_strlist_sort_len_ascending,
+ test_strlist_sort_len_descending,
+ test_strlist_reverse,
+ test_strlist_count,
+ test_strlist_item_as_str,
+ test_strlist_item_as_char,
+ test_strlist_item_as_uchar,
+ test_strlist_item_as_short,
+ test_strlist_item_as_ushort,
+ test_strlist_item_as_int,
+ test_strlist_item_as_uint,
+ test_strlist_item_as_long,
+ test_strlist_item_as_ulong,
+ test_strlist_item_as_long_long,
+ test_strlist_item_as_ulong_long,
+ test_strlist_item_as_float,
+ test_strlist_item_as_double,
+ test_strlist_item_as_long_double,
+ };
+ OMC_TEST_RUN(tests);
+ OMC_TEST_END_MAIN();
+} \ No newline at end of file