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