From 85fe3b67a67825dfc5e43959f001b2a7159dc23f Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Sun, 13 Apr 2025 10:45:35 +0200 Subject: new directory structure --- tests/makefile | 0 tests/src/csv-test.c | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 627 insertions(+) create mode 100644 tests/makefile create mode 100644 tests/src/csv-test.c (limited to 'tests') diff --git a/tests/makefile b/tests/makefile new file mode 100644 index 0000000..e69de29 diff --git a/tests/src/csv-test.c b/tests/src/csv-test.c new file mode 100644 index 0000000..c99c049 --- /dev/null +++ b/tests/src/csv-test.c @@ -0,0 +1,627 @@ +#undef NDEBUG + +#include +#include +#include +#include +#include + +#include "csv.h" + +#define FMEMOPEN(f, data) \ + f = fmemopen(data, sizeof(data) - 1, "r"); \ + assert(f != NULL) + +#define FMEMCLOSE(f) \ + (void) fclose(f); \ + f = NULL + +#define UNUSED(x) (void) (x) + +void +test_empty_object(void) +{ + { + csv_t csv = { 0 }; + assert(csv_nfields(&csv) == 0); + } + + { + csv_t csv; + csv_init(&csv); + assert(csv_nfields(&csv) == 0); + } +} + +void +test_line_endings1(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "A,B,C\r\n" + "D,E,F\n"; + + FMEMOPEN(file, data); + + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "D") == 0); + assert(strcmp(csv_field(&csv, 1), "E") == 0); + assert(strcmp(csv_field(&csv, 2), "F") == 0); + + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +void +test_line_endings2(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "A,B,C\r\n" + "D,E,F"; + + FMEMOPEN(file, data); + + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "D") == 0); + assert(strcmp(csv_field(&csv, 1), "E") == 0); + assert(strcmp(csv_field(&csv, 2), "F") == 0); + + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +void +test_empty_fields(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "\n" + "\r" + "\r\n" + "\"\"\n" + "\"\"\r" + "\"\"\r\n" + ",\n" + ",\r" + ",\r\n" + "\"\",\"\"\n" + "\"\",\"\"\r" + "\"\",\"\"\r\n" + ",,\n" + ",,\r" + ",,\r\n" + "\"\",\"\",\n" + "\"\",\"\",\r" + "\"\",\"\",\r\n" + ",,"; + + FMEMOPEN(file, data); + + // Line 1 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 2 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 3 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 4 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 5 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 6 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "") == 0); + + // Line 7 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 8 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 9 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 10 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 11 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 12 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + + // Line 13 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 14 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 15 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 16 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 17 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 18 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // Line 19 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "") == 0); + assert(strcmp(csv_field(&csv, 1), "") == 0); + assert(strcmp(csv_field(&csv, 2), "") == 0); + + // EOF + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +void +test_simple_fields(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "A\n" + "A\r" + "A\r\n" + "\"A\"\n" + "\"A\"\r" + "\"A\"\r\n" + "A,B\n" + "A,B\r" + "A,B\r\n" + "\"A\",\"B\"\n" + "\"A\",\"B\"\r" + "\"A\",\"B\"\r\n" + "A,B,C\n" + "A,B,C\r" + "A,B,C\r\n" + "\"A\",\"B\",C\n" + "\"A\",\"B\",C\r" + "\"A\",\"B\",C\r\n" + "A,B,C"; + + FMEMOPEN(file, data); + + // Line 1 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 2 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 3 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 4 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 5 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 6 + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + + // Line 7 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 8 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 9 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 10 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 11 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 12 + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + + // Line 13 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 14 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 15 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 16 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 17 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 18 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // Line 19 + assert(csv_read(&csv, file) == 3); + assert(csv_nfields(&csv) == 3); + assert(strcmp(csv_field(&csv, 0), "A") == 0); + assert(strcmp(csv_field(&csv, 1), "B") == 0); + assert(strcmp(csv_field(&csv, 2), "C") == 0); + + // EOF + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +void +test_quoted_fields(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "foo \"baz\" bar,foo \"\"baz\"\" bar,\"foo \"\"baz\"\" bar\",\"foo \"baz\" bar\",\"foo \"\"baz\"\", bar\""; + + FMEMOPEN(file, data); + + assert(csv_read(&csv, file) == 5); + assert(csv_nfields(&csv) == 5); + assert(strcmp(csv_field(&csv, 0), "foo \"baz\" bar") == 0); + assert(strcmp(csv_field(&csv, 1), "foo \"\"baz\"\" bar") == 0); + assert(strcmp(csv_field(&csv, 2), "foo \"baz\" bar") == 0); + assert(strcmp(csv_field(&csv, 3), "foo \"baz\" bar") == 0); + assert(strcmp(csv_field(&csv, 4), "foo \"baz\", bar") == 0); + + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +void +test_wrong_quoted_field(void) +{ + FILE *file = NULL; + csv_t csv = { 0 }; + + char data[] = "\"foo"; + + FMEMOPEN(file, data); + + assert(csv_read(&csv, file) == 1); + assert(csv_nfields(&csv) == 1); + assert(strcmp(csv_field(&csv, 0), "foo") == 0); + + assert(csv_read(&csv, file) == 0); + + FMEMCLOSE(file); +} + +static void +cb_error(csv_err_t err, void *cb_arg) +{ + longjmp(*((jmp_buf *) cb_arg), err); +} + +void +test_out_of_range_error(void) +{ + jmp_buf env; + csv_options_t csv_options = csv_default_options; + csv_options.cb_error = cb_error; + csv_options.cb_error_arg = &env; + + csv_t csv; + csv_init_opt(&csv, &csv_options); + + FILE *file = NULL; + char data[] = ","; + + FMEMOPEN(file, data); + + switch ( setjmp(env) ) { + case CSV_ERR_OK: + assert(csv_read(&csv, file) == 2); + assert(csv_nfields(&csv) == 2); + + // force an "out of range"-Exception! + assert(strcmp(csv_field(&csv, 2), "will fail") == 0); + break; + + case CSV_ERR_OUT_OF_RANGE: + csv_cleanup(&csv); + break; + + default: + assert(!"this should not be happen!"); + } + + FMEMCLOSE(file); +} + +void +test_read_error(void) +{ + jmp_buf env; + csv_options_t csv_options = csv_default_options; + csv_options.cb_error = cb_error; + csv_options.cb_error_arg = &env; + + csv_t csv; + csv_init_opt(&csv, &csv_options); + + FILE *file = fopen("/dev/null", "r"); + assert(file != NULL); + (void) fputc('T', file); // Set Error-Flag! + + switch ( setjmp(env) ) { + case CSV_ERR_OK: + assert(csv_read(&csv, file) == 0); + break; + + case CSV_ERR_IO_READ: + csv_cleanup(&csv); + break; + + default: + assert(!"this should not be happen!"); + } + + (void) fclose(file); +} + +void * +my_allocate(size_t n, size_t size, void *cb_arg) +{ + UNUSED(cb_arg); + + void *ptr = calloc(n, size); + + return ptr; +} + +void * +my_allocate_null(size_t n, size_t size, void *cb_arg) +{ + UNUSED(n); + UNUSED(size); + UNUSED(cb_arg); + + return NULL; +} + +void * +my_reallocate(void *ptr, size_t n, size_t size, void *cb_arg) +{ + UNUSED(ptr); + UNUSED(n); + UNUSED(size); + UNUSED(cb_arg); + + return NULL; +} + +void +my_free(void *ptr, size_t n, size_t size, void *cb_arg) +{ + UNUSED(n); + UNUSED(size); + UNUSED(cb_arg); + + free(ptr); +} + +void +test_allocation_error1(void) +{ + jmp_buf env; + + csv_options_t csv_options = csv_default_options; + csv_options.cb_error = cb_error; + csv_options.cb_error_arg = &env; + csv_options.cb_allocate = my_allocate; + csv_options.cb_reallocate = my_reallocate; + csv_options.cb_free = my_free; + + csv_t csv; + csv_init_opt(&csv, &csv_options); + + char data[] = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T"; + + FILE *file = NULL; + FMEMOPEN(file, data); + assert(file != NULL); + + switch ( setjmp(env) ) { + case CSV_ERR_OK: + assert(csv_read(&csv, file) == 20); + assert(!"this should not be happen!"); + break; + + case CSV_ERR_OUT_OF_MEMORY: + csv_cleanup(&csv); + break; + + default: + assert(!"this should not be happen!"); + } + + FMEMCLOSE(file); +} + +void +show_version(void) +{ + const char *version = csv_version; + + printf("libcsv - version: "); + for ( ; *version; ++version ) { + putchar(*version); + } + + printf(", build date: "); + for ( ++version; *version; ++version ) { + putchar(*version); + } + + printf(", build time: "); + for ( ++version; *version; ++version ) { + putchar(*version); + } + putchar('\n'); +} + +int +main(void) +{ + show_version(); + + test_empty_object(); + test_line_endings1(); + test_line_endings2(); + test_empty_fields(); + test_simple_fields(); + test_quoted_fields(); + test_wrong_quoted_field(); + + test_out_of_range_error(); + test_read_error(); + + test_allocation_error1(); + + puts("all tests passed..."); + + return EXIT_SUCCESS; +} -- cgit v1.3