summaryrefslogtreecommitdiffstats
path: root/fluent-bit/tests/internal/csv.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/tests/internal/csv.c')
-rw-r--r--fluent-bit/tests/internal/csv.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/fluent-bit/tests/internal/csv.c b/fluent-bit/tests/internal/csv.c
new file mode 100644
index 00000000..ad4503eb
--- /dev/null
+++ b/fluent-bit/tests/internal/csv.c
@@ -0,0 +1,167 @@
+#include <fluent-bit/flb_csv.h>
+#include <fluent-bit/flb_sds.h>
+#include <string.h>
+
+#include "flb_tests_internal.h"
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#define row_count 3
+#define col_count 4
+
+char data[] =
+ "r0c1,,,\r"
+ ",r1c2,\"\",\"r1three\nlines\nfield\"\r\n"
+ "r2c1,r2c2,\"\"\"r2c\n3\n\",\"r2three\nlines\nfield\"\"\"\n";
+
+char *parse_expected[row_count][col_count] = {
+ { "r0c1", "", "", "" },
+ { "", "r1c2", "", "r1three\nlines\nfield" },
+ { "r2c1", "r2c2", "\"r2c\n3\n", "r2three\nlines\nfield\"" },
+};
+
+char *split_expected[row_count] = {
+ "r0c1,,,\r",
+ ",r1c2,\"\",\"r1three\nlines\nfield\"\r\n",
+ "r2c1,r2c2,\"\"\"r2c\n3\n\",\"r2three\nlines\nfield\"\"\"\n",
+};
+
+struct parse_state {
+ char **parsed;
+ size_t current_row;
+ size_t current_col;
+};
+
+static void field_parsed(void *data, const char *field, size_t field_len)
+{
+ struct parse_state *state = data;
+ size_t col = state->current_col;
+ size_t row = state->current_row;
+ char *fdup = strndup(field, field_len);
+ state->parsed[row * col_count + col] = fdup;
+ state->current_col++;
+}
+
+static char **parse_data_step(int step)
+{
+ int i;
+ size_t len = sizeof(data);
+ struct parse_state state;
+ char *bufptr;
+ struct flb_csv_state csv_state;
+ size_t field_count;
+ state.parsed = malloc(sizeof *state.parsed * row_count * col_count);
+ state.current_row = 0;
+ state.current_col = 0;
+ flb_csv_init(&csv_state, field_parsed, &state);
+ bufptr = data;
+ for (i = 0; i < sizeof(data);) {
+ int ret;
+ size_t bl = MIN(len - i, step);
+ ret = flb_csv_parse_record(&csv_state, &bufptr, &bl, &field_count);
+ i = bufptr - data;
+ if (ret == FLB_CSV_SUCCESS) {
+ TEST_CHECK(field_count == 4);
+ state.current_row++;
+ state.current_col = 0;
+ }
+ else if (ret == FLB_CSV_EOF) {
+ continue;
+ }
+ else {
+ abort();
+ };
+ }
+ flb_csv_destroy(&csv_state);
+ return state.parsed;
+}
+
+static void check_parse_result(char **result)
+{
+ int row, col;
+
+ for (row = 0; row < row_count; row++) {
+ for (col = 0; col < col_count; col++) {
+ char *res = result[row * col_count + col];
+ TEST_CHECK(strcmp(res, parse_expected[row][col]) == 0);
+ TEST_MSG("Mismatch on row %d, col %d", row, col);
+ TEST_MSG("Expected: %s", parse_expected[row][col]);
+ TEST_MSG("Result: %s", result[row * col_count + col]);
+ free(res);
+ }
+ }
+
+ free(result);
+}
+
+static void check_split_result(char **result)
+{
+ int row;
+
+ for (row = 0; row < row_count; row++) {
+ char *res = result[row];
+ TEST_CHECK(strcmp(res, split_expected[row]) == 0);
+ TEST_MSG("Mismatch on row %d", row);
+ TEST_MSG("Expected: %s", split_expected[row]);
+ TEST_MSG("Result: %s", result[row]);
+ free(res);
+ }
+
+ free(result);
+}
+
+static char **split_rows_step(int step)
+{
+ int i;
+ size_t len = sizeof(data);
+ char *bufptr;
+ char *row_start;
+ size_t current_row = 0;
+ char **result = malloc(sizeof *result * row_count);
+ struct flb_csv_state csv_state;
+ flb_csv_init(&csv_state, NULL, NULL);
+ bufptr = data;
+ row_start = data;
+ size_t field_count;
+ for (i = 0; i < len;) {
+ int ret;
+ size_t bl = MIN(len - i, step);
+ ret = flb_csv_parse_record(&csv_state, &bufptr, &bl, &field_count);
+ i = bufptr - data;
+ if (ret == FLB_CSV_SUCCESS) {
+ TEST_CHECK(field_count == 4);
+ result[current_row] = strndup(row_start, bufptr - row_start);
+ row_start = bufptr;
+ current_row++;
+ }
+ else if (ret == FLB_CSV_EOF) {
+ continue;
+ } else {
+ abort();
+ };
+ }
+ flb_csv_destroy(&csv_state);
+ return result;
+}
+
+static void test_basic()
+{
+ int step;
+ for (step = 1; step <= sizeof(data); step++) {
+ check_parse_result(parse_data_step(step));
+ }
+}
+
+static void test_split_lines()
+{
+ int step;
+ for (step = 1; step <= sizeof(data); step++) {
+ check_split_result(split_rows_step(step));
+ }
+}
+
+TEST_LIST = {
+ { "basic" , test_basic},
+ { "split_lines" , test_split_lines},
+ { 0 }
+};