| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <errno.h> |
|
|
| |
| |
|
|
| |
|
|
| static void test_prepare_stdin(const char *data) |
| { |
| int fds[2]; |
| if (pipe(fds) != 0) { |
| |
| TEST_FAIL_MESSAGE("pipe() failed"); |
| } |
|
|
| |
| ssize_t len = (ssize_t)strlen(data); |
| ssize_t written = 0; |
| while (written < len) { |
| ssize_t w = write(fds[1], data + written, len - written); |
| if (w < 0) { |
| close(fds[0]); |
| close(fds[1]); |
| TEST_FAIL_MESSAGE("write() to pipe failed"); |
| } |
| written += w; |
| } |
| close(fds[1]); |
|
|
| |
| if (dup2(fds[0], STDIN_FILENO) < 0) { |
| close(fds[0]); |
| TEST_FAIL_MESSAGE("dup2() failed"); |
| } |
| close(fds[0]); |
| } |
|
|
| |
| static void test_remove_created_files(void) |
| { |
| |
| |
| if (files_created > 0) { |
| for (int i = files_created - 1; i >= 0; --i) { |
| const char *name = make_filename(i); |
| unlink(name); |
| } |
| } |
| files_created = 0; |
| } |
|
|
| |
| static char *test_slurp_file(const char *path) |
| { |
| FILE *fp = fopen(path, "rb"); |
| if (!fp) return NULL; |
| if (fseek(fp, 0, SEEK_END) != 0) { |
| fclose(fp); |
| return NULL; |
| } |
| long sz = ftell(fp); |
| if (sz < 0) { |
| fclose(fp); |
| return NULL; |
| } |
| if (fseek(fp, 0, SEEK_SET) != 0) { |
| fclose(fp); |
| return NULL; |
| } |
| char *buf = (char *)malloc((size_t)sz + 1); |
| if (!buf) { |
| fclose(fp); |
| return NULL; |
| } |
| size_t n = fread(buf, 1, (size_t)sz, fp); |
| fclose(fp); |
| buf[n] = '\0'; |
| return buf; |
| } |
|
|
| |
| static void test_drain_all_input(void) |
| { |
| struct cstring *ln; |
| while ((ln = remove_line()) != NULL) { |
| (void)ln; |
| } |
| } |
|
|
| |
| static char *test_argv_storage[4] = { (char *)"csplit", (char *)"/dummy/", (char *)"%dummy%", NULL }; |
|
|
| |
| void setUp(void) { |
| |
| suppress_count = true; |
| elide_empty_files = false; |
| remove_files = false; |
| suppress_matched = false; |
|
|
| |
| if (!filename_space) { |
| filename_space = (char *)malloc(512); |
| TEST_ASSERT_NOT_NULL_MESSAGE(filename_space, "malloc filename_space failed"); |
| } |
| prefix = "tstpr_"; |
| suffix = NULL; |
| digits = 2; |
|
|
| |
| sigemptyset(&caught_signals); |
|
|
| |
| head = NULL; |
| if (hold_area) { free(hold_area); hold_area = NULL; } |
| hold_count = 0; |
| have_read_eof = false; |
| last_line_number = 0; |
| current_line = 0; |
|
|
| |
| bytes_written = 0; |
| output_stream = NULL; |
| output_filename = NULL; |
| files_created = 0; |
|
|
| |
| global_argv = test_argv_storage; |
| } |
|
|
| |
| void tearDown(void) { |
| |
| close_output_file(); |
|
|
| |
| test_drain_all_input(); |
|
|
| |
| test_remove_created_files(); |
|
|
| |
| head = NULL; |
| if (hold_area) { free(hold_area); hold_area = NULL; } |
| hold_count = 0; |
| have_read_eof = false; |
| last_line_number = 0; |
| current_line = 0; |
| } |
|
|
| |
| static struct control *test_make_regexp_control(int argnum, const char *pattern_with_delims) |
| { |
| |
| struct control *p = extract_regexp(argnum, (pattern_with_delims[0] == '%'), pattern_with_delims); |
| return p; |
| } |
|
|
| |
| static const char *test_last_filename(void) |
| { |
| if (files_created <= 0) return NULL; |
| return make_filename(files_created - 1); |
| } |
|
|
| |
|
|
| static void test_process_regexp_match_no_offset_writes_preceding_lines(void) |
| { |
| |
| const char *input = "one\nfoo\nbar\n"; |
| test_prepare_stdin(input); |
|
|
| |
| test_argv_storage[1] = (char *)"/foo/"; |
| struct control *p = test_make_regexp_control(1, "/foo/"); |
|
|
| |
| process_regexp(p, 0); |
|
|
| |
| TEST_ASSERT_EQUAL_INT(1, files_created); |
| const char *fname = test_last_filename(); |
| TEST_ASSERT_NOT_NULL(fname); |
| char *content = test_slurp_file(fname); |
| TEST_ASSERT_NOT_NULL_MESSAGE(content, "Failed to read output file"); |
| TEST_ASSERT_EQUAL_STRING("one\n", content); |
| free(content); |
| } |
|
|
| static void test_process_regexp_positive_offset_includes_matching_line(void) |
| { |
| const char *input = "a\nfoo\nc\n"; |
| test_prepare_stdin(input); |
|
|
| |
| test_argv_storage[1] = (char *)"/foo/+1"; |
| struct control *p = test_make_regexp_control(1, "/foo/+1"); |
|
|
| process_regexp(p, 0); |
|
|
| TEST_ASSERT_EQUAL_INT(1, files_created); |
| const char *fname = test_last_filename(); |
| TEST_ASSERT_NOT_NULL(fname); |
| char *content = test_slurp_file(fname); |
| TEST_ASSERT_NOT_NULL(content); |
| TEST_ASSERT_EQUAL_STRING("a\nfoo\n", content); |
| free(content); |
| } |
|
|
| static void test_process_regexp_ignore_true_creates_no_files(void) |
| { |
| const char *input = "a\nfoo\nb\n"; |
| test_prepare_stdin(input); |
|
|
| |
| test_argv_storage[2] = (char *)"%foo%"; |
| struct control *p = test_make_regexp_control(2, "%foo%"); |
|
|
| process_regexp(p, 0); |
|
|
| TEST_ASSERT_EQUAL_INT(0, files_created); |
| |
| } |
|
|
| static void test_process_regexp_negative_offset_writes_up_to_before_previous_line(void) |
| { |
| const char *input = "a\nb\nc\nd\n"; |
| test_prepare_stdin(input); |
|
|
| |
| test_argv_storage[1] = (char *)"/c/-1"; |
| struct control *p = test_make_regexp_control(1, "/c/-1"); |
|
|
| process_regexp(p, 0); |
|
|
| TEST_ASSERT_EQUAL_INT(1, files_created); |
| const char *fname = test_last_filename(); |
| TEST_ASSERT_NOT_NULL(fname); |
| char *content = test_slurp_file(fname); |
| TEST_ASSERT_NOT_NULL(content); |
| TEST_ASSERT_EQUAL_STRING("a\n", content); |
| free(content); |
| } |
|
|
| static void test_process_regexp_suppress_matched_skips_matched_line(void) |
| { |
| const char *input = "before\nmatch\nafter\n"; |
| test_prepare_stdin(input); |
|
|
| suppress_matched = true; |
|
|
| test_argv_storage[1] = (char *)"/match/"; |
| struct control *p = test_make_regexp_control(1, "/match/"); |
|
|
| process_regexp(p, 0); |
|
|
| |
| TEST_ASSERT_EQUAL_INT(1, files_created); |
| const char *fname = test_last_filename(); |
| TEST_ASSERT_NOT_NULL(fname); |
| char *content = test_slurp_file(fname); |
| TEST_ASSERT_NOT_NULL(content); |
| TEST_ASSERT_EQUAL_STRING("before\n", content); |
| free(content); |
|
|
| |
| struct cstring *next = remove_line(); |
| TEST_ASSERT_NOT_NULL(next); |
| TEST_ASSERT_EQUAL_INT_MESSAGE((int)strlen("after\n"), (int)next->len, "Unexpected next line length"); |
| TEST_ASSERT_EQUAL_INT(0, strncmp(next->str, "after\n", next->len)); |
| } |
|
|
| |
| int main(void) |
| { |
| UNITY_BEGIN(); |
| RUN_TEST(test_process_regexp_match_no_offset_writes_preceding_lines); |
| RUN_TEST(test_process_regexp_positive_offset_includes_matching_line); |
| RUN_TEST(test_process_regexp_ignore_true_creates_no_files); |
| RUN_TEST(test_process_regexp_negative_offset_writes_up_to_before_previous_line); |
| RUN_TEST(test_process_regexp_suppress_matched_skips_matched_line); |
| return UNITY_END(); |
| } |