| | #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(); |
| | } |