| #include "../../unity/unity.h" |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
|
|
| |
| extern struct field_range_pair *frp; |
|
|
| |
| |
| |
| static struct field_range_pair* set_frp_from_pairs(const uintmax_t (*pairs)[2], size_t count) { |
| struct field_range_pair *arr = (struct field_range_pair*) malloc(sizeof(*arr) * (count + 1)); |
| if (!arr) return NULL; |
| for (size_t i = 0; i < count; i++) { |
| arr[i].lo = pairs[i][0]; |
| arr[i].hi = pairs[i][1]; |
| } |
| |
| arr[count].lo = UINTMAX_MAX; |
| arr[count].hi = UINTMAX_MAX; |
| frp = arr; |
| return arr; |
| } |
|
|
| |
| |
| |
| |
| static char* run_cut_fields_capture( |
| const char *input, |
| const uintmax_t (*pairs)[2], size_t npairs, |
| unsigned char in_delim, |
| const char *out_delim_str, |
| bool only_delimited) |
| { |
| |
| suppress_non_delimited = only_delimited; |
|
|
| |
| delim = in_delim; |
|
|
| |
| output_delimiter_default[0] = delim; |
| if (out_delim_str == NULL) { |
| output_delimiter_string = output_delimiter_default; |
| output_delimiter_length = 1; |
| } else { |
| output_delimiter_string = (char*)out_delim_str; |
| output_delimiter_length = strlen(out_delim_str); |
| } |
|
|
| |
| line_delim = '\n'; |
|
|
| |
| struct field_range_pair *local_frp = set_frp_from_pairs(pairs, npairs); |
| if (!local_frp) { |
| |
| char *empty = (char*)malloc(1); |
| if (empty) empty[0] = '\0'; |
| return empty; |
| } |
|
|
| |
| FILE *in = tmpfile(); |
| if (!in) { |
| free(local_frp); |
| char *empty = (char*)malloc(1); |
| if (empty) empty[0] = '\0'; |
| return empty; |
| } |
| if (input && *input) { |
| fwrite(input, 1, strlen(input), in); |
| } |
| fflush(in); |
| fseek(in, 0, SEEK_SET); |
|
|
| |
| fflush(stdout); |
| int saved_stdout_fd = dup(fileno(stdout)); |
| FILE *cap = tmpfile(); |
| if (cap == NULL) { |
| fclose(in); |
| free(local_frp); |
| char *empty = (char*)malloc(1); |
| if (empty) empty[0] = '\0'; |
| return empty; |
| } |
| dup2(fileno(cap), fileno(stdout)); |
| clearerr(stdout); |
|
|
| |
| cut_fields(in); |
|
|
| |
| fflush(stdout); |
| dup2(saved_stdout_fd, fileno(stdout)); |
| close(saved_stdout_fd); |
|
|
| |
| fflush(cap); |
| fseek(cap, 0, SEEK_END); |
| long sz = ftell(cap); |
| if (sz < 0) sz = 0; |
| fseek(cap, 0, SEEK_SET); |
| char *out = (char*)malloc((size_t)sz + 1); |
| if (!out) { |
| out = (char*)malloc(1); |
| if (out) out[0] = '\0'; |
| } else { |
| size_t nread = fread(out, 1, (size_t)sz, cap); |
| out[nread] = '\0'; |
| } |
|
|
| |
| fclose(cap); |
| fclose(in); |
| free(local_frp); |
|
|
| return out; |
| } |
|
|
| void setUp(void) { |
| |
| suppress_non_delimited = false; |
| |
| delim = '\t'; |
| line_delim = '\n'; |
| output_delimiter_default[0] = delim; |
| output_delimiter_string = output_delimiter_default; |
| output_delimiter_length = 1; |
| } |
|
|
| void tearDown(void) { |
| |
| if (field_1_buffer) { |
| free(field_1_buffer); |
| field_1_buffer = NULL; |
| field_1_bufsize = 0; |
| } |
| } |
|
|
| |
| void test_cut_fields_basic_selection_default_delim(void) { |
| const char *input = "a\tb\tc\n1\t2\t3\n"; |
| const uintmax_t pairs[][2] = { {2,3} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, '\t', NULL, false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("b\tc\n2\t3\n", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_nondelimited_without_s(void) { |
| const char *input = "abc\n"; |
| const uintmax_t pairs[][2] = { {2,2} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("abc\n", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_nondelimited_with_s(void) { |
| const char *input = "abc\n"; |
| const uintmax_t pairs[][2] = { {1,1} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, true); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_custom_output_delimiter(void) { |
| const char *input = "a,b,c\nx,y,z\n"; |
| const uintmax_t pairs[][2] = { {1,1}, {3,3} }; |
| char *out = run_cut_fields_capture(input, pairs, 2, ',', ":", false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("a:c\nx:z\n", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_missing_field_produces_empty_line(void) { |
| const char *input = "a,b\nx,y\n"; |
| const uintmax_t pairs[][2] = { {3,3} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n\n", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_no_trailing_newline(void) { |
| const char *input = "a,b,c"; |
| const uintmax_t pairs[][2] = { {2,2} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("b\n", out); |
| free(out); |
| } |
|
|
| |
| void test_cut_fields_empty_selected_field(void) { |
| const char *input = "a,,c\n"; |
| const uintmax_t pairs[][2] = { {2,2} }; |
| char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n", out); |
| free(out); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_cut_fields_basic_selection_default_delim); |
| RUN_TEST(test_cut_fields_nondelimited_without_s); |
| RUN_TEST(test_cut_fields_nondelimited_with_s); |
| RUN_TEST(test_cut_fields_custom_output_delimiter); |
| RUN_TEST(test_cut_fields_missing_field_produces_empty_line); |
| RUN_TEST(test_cut_fields_no_trailing_newline); |
| RUN_TEST(test_cut_fields_empty_selected_field); |
| return UNITY_END(); |
| } |