|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <fcntl.h> |
|
|
#include <sys/stat.h> |
|
|
#include <errno.h> |
|
|
#include <limits.h> |
|
|
#include <signal.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void split_file (void); |
|
|
|
|
|
|
|
|
static int start_files_created = 0; |
|
|
static char test_prefix[64] = {0}; |
|
|
|
|
|
|
|
|
static char* create_temp_input_file(const char* content) { |
|
|
char templ[] = "/tmp/csplit_test_input_XXXXXX"; |
|
|
int fd = mkstemp(templ); |
|
|
if (fd < 0) { |
|
|
perror("mkstemp"); |
|
|
return NULL; |
|
|
} |
|
|
size_t len = strlen(content); |
|
|
if (len > 0) { |
|
|
ssize_t w = write(fd, content, len); |
|
|
if (w < 0 || (size_t)w != len) { |
|
|
close(fd); |
|
|
unlink(templ); |
|
|
perror("write temp input"); |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { |
|
|
close(fd); |
|
|
unlink(templ); |
|
|
perror("lseek"); |
|
|
return NULL; |
|
|
} |
|
|
close(fd); |
|
|
return strdup(templ); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char* read_file_contents(const char* path) { |
|
|
struct stat st; |
|
|
if (stat(path, &st) != 0) |
|
|
return NULL; |
|
|
size_t sz = (size_t)st.st_size; |
|
|
FILE* f = fopen(path, "rb"); |
|
|
if (!f) |
|
|
return NULL; |
|
|
char* buf = (char*)malloc(sz + 1); |
|
|
if (!buf) { |
|
|
fclose(f); |
|
|
return NULL; |
|
|
} |
|
|
size_t r = fread(buf, 1, sz, f); |
|
|
fclose(f); |
|
|
if (r != sz) { |
|
|
free(buf); |
|
|
return NULL; |
|
|
} |
|
|
buf[sz] = '\0'; |
|
|
return buf; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const char* outfile_name_for_index(int i) { |
|
|
|
|
|
return make_filename(i); |
|
|
} |
|
|
|
|
|
|
|
|
static void reset_input_state(void) { |
|
|
|
|
|
if (hold_area) { |
|
|
free(hold_area); |
|
|
hold_area = NULL; |
|
|
} |
|
|
hold_count = 0; |
|
|
have_read_eof = false; |
|
|
head = NULL; |
|
|
last_line_number = 0; |
|
|
current_line = 0; |
|
|
} |
|
|
|
|
|
|
|
|
static void prepare_environment(void) { |
|
|
|
|
|
sigemptyset(&caught_signals); |
|
|
|
|
|
|
|
|
suppress_count = true; |
|
|
|
|
|
|
|
|
remove_files = false; |
|
|
elide_empty_files = false; |
|
|
suppress_matched = false; |
|
|
|
|
|
|
|
|
digits = 2; |
|
|
suffix = NULL; |
|
|
|
|
|
|
|
|
if (!filename_space) { |
|
|
filename_space = (char*)malloc(1024); |
|
|
} |
|
|
|
|
|
|
|
|
if (test_prefix[0] == '\0') { |
|
|
snprintf(test_prefix, sizeof(test_prefix), "utcs_%ld_", (long)getpid()); |
|
|
} |
|
|
prefix = test_prefix; |
|
|
|
|
|
|
|
|
reset_input_state(); |
|
|
|
|
|
|
|
|
start_files_created = files_created; |
|
|
} |
|
|
|
|
|
|
|
|
static void cleanup_created_files(void) { |
|
|
int end = files_created; |
|
|
for (int i = start_files_created; i < end; i++) { |
|
|
const char* name = outfile_name_for_index(i); |
|
|
unlink(name); |
|
|
} |
|
|
files_created = start_files_created; |
|
|
} |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
prepare_environment(); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
cleanup_created_files(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_split_file_linecount_basic(void) { |
|
|
const char* input = "a\nb\nc\nd\ne\n"; |
|
|
char* path = create_temp_input_file(input); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp input"); |
|
|
|
|
|
set_input_file(path); |
|
|
|
|
|
|
|
|
control_used = 0; |
|
|
struct control* p = new_control_record(); |
|
|
p->lines_required = 3; |
|
|
p->argnum = 1; |
|
|
|
|
|
|
|
|
split_file(); |
|
|
|
|
|
|
|
|
int created = files_created - start_files_created; |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(2, created, "Expected exactly 2 output files"); |
|
|
|
|
|
const char* f0 = outfile_name_for_index(start_files_created + 0); |
|
|
const char* f1 = outfile_name_for_index(start_files_created + 1); |
|
|
|
|
|
char* c0 = read_file_contents(f0); |
|
|
char* c1 = read_file_contents(f1); |
|
|
|
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c0, "Failed to read first output file"); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c1, "Failed to read second output file"); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("a\nb\n", c0); |
|
|
TEST_ASSERT_EQUAL_STRING("c\nd\ne\n", c1); |
|
|
|
|
|
free(c0); |
|
|
free(c1); |
|
|
|
|
|
unlink(path); |
|
|
free(path); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_split_file_regexp_basic(void) { |
|
|
const char* input = "a\nb\nc\nd\ne\n"; |
|
|
char* path = create_temp_input_file(input); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp input"); |
|
|
|
|
|
set_input_file(path); |
|
|
|
|
|
|
|
|
control_used = 0; |
|
|
struct control* p = extract_regexp(1, false, "/^c$/"); |
|
|
(void)p; |
|
|
|
|
|
|
|
|
split_file(); |
|
|
|
|
|
|
|
|
int created = files_created - start_files_created; |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(2, created, "Expected exactly 2 output files"); |
|
|
|
|
|
const char* f0 = outfile_name_for_index(start_files_created + 0); |
|
|
const char* f1 = outfile_name_for_index(start_files_created + 1); |
|
|
|
|
|
char* c0 = read_file_contents(f0); |
|
|
char* c1 = read_file_contents(f1); |
|
|
|
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c0, "Failed to read first output file"); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c1, "Failed to read second output file"); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("a\nb\n", c0); |
|
|
TEST_ASSERT_EQUAL_STRING("c\nd\ne\n", c1); |
|
|
|
|
|
free(c0); |
|
|
free(c1); |
|
|
|
|
|
unlink(path); |
|
|
free(path); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_split_file_regexp_suppress_matched(void) { |
|
|
const char* input = "a\nb\nc\nd\ne\n"; |
|
|
char* path = create_temp_input_file(input); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp input"); |
|
|
|
|
|
set_input_file(path); |
|
|
|
|
|
|
|
|
control_used = 0; |
|
|
struct control* p = extract_regexp(1, false, "/^c$/"); |
|
|
(void)p; |
|
|
|
|
|
|
|
|
suppress_matched = true; |
|
|
|
|
|
|
|
|
split_file(); |
|
|
|
|
|
|
|
|
int created = files_created - start_files_created; |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(2, created, "Expected exactly 2 output files"); |
|
|
|
|
|
const char* f0 = outfile_name_for_index(start_files_created + 0); |
|
|
const char* f1 = outfile_name_for_index(start_files_created + 1); |
|
|
|
|
|
char* c0 = read_file_contents(f0); |
|
|
char* c1 = read_file_contents(f1); |
|
|
|
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c0, "Failed to read first output file"); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(c1, "Failed to read second output file"); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING("a\nb\n", c0); |
|
|
TEST_ASSERT_EQUAL_STRING("d\ne\n", c1); |
|
|
|
|
|
free(c0); |
|
|
free(c1); |
|
|
|
|
|
unlink(path); |
|
|
free(path); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_split_file_linecount_basic); |
|
|
RUN_TEST(test_split_file_regexp_basic); |
|
|
RUN_TEST(test_split_file_regexp_suppress_matched); |
|
|
return UNITY_END(); |
|
|
} |