|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <errno.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *testutil_build_no_line_fmt(int width, const char *sep) |
|
|
{ |
|
|
size_t seplen = strlen(sep); |
|
|
size_t len = (size_t)width + seplen; |
|
|
char *s = (char *)malloc(len + 1); |
|
|
if (!s) return NULL; |
|
|
memset(s, ' ', (size_t)width); |
|
|
memcpy(s + width, sep, seplen); |
|
|
s[len] = '\0'; |
|
|
return s; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *testutil_run_and_capture(const char *input) |
|
|
{ |
|
|
FILE *in = tmpfile(); |
|
|
if (!in) return NULL; |
|
|
|
|
|
size_t inlen = strlen(input); |
|
|
if (inlen > 0 && fwrite(input, 1, inlen, in) != inlen) { |
|
|
fclose(in); |
|
|
return NULL; |
|
|
} |
|
|
fflush(in); |
|
|
rewind(in); |
|
|
|
|
|
FILE *out = tmpfile(); |
|
|
if (!out) { |
|
|
fclose(in); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
int stdout_fd = fileno(stdout); |
|
|
int saved_fd = dup(stdout_fd); |
|
|
if (saved_fd < 0) { |
|
|
fclose(in); |
|
|
fclose(out); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
fflush(stdout); |
|
|
if (dup2(fileno(out), stdout_fd) < 0) { |
|
|
close(saved_fd); |
|
|
fclose(in); |
|
|
fclose(out); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
process_file(in); |
|
|
|
|
|
|
|
|
fflush(stdout); |
|
|
|
|
|
|
|
|
long sz = 0; |
|
|
if (fseek(out, 0, SEEK_END) == 0) { |
|
|
sz = ftell(out); |
|
|
if (sz < 0) sz = 0; |
|
|
fseek(out, 0, SEEK_SET); |
|
|
} |
|
|
|
|
|
char *buf = (char *)malloc((size_t)sz + 1); |
|
|
if (!buf) { |
|
|
|
|
|
dup2(saved_fd, stdout_fd); |
|
|
close(saved_fd); |
|
|
fclose(in); |
|
|
fclose(out); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
size_t nread = 0; |
|
|
if (sz > 0) { |
|
|
nread = fread(buf, 1, (size_t)sz, out); |
|
|
} |
|
|
buf[nread] = '\0'; |
|
|
|
|
|
|
|
|
dup2(saved_fd, stdout_fd); |
|
|
close(saved_fd); |
|
|
fclose(in); |
|
|
fclose(out); |
|
|
|
|
|
return buf; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
separator_str = "|"; |
|
|
lineno_width = 2; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
|
|
|
starting_line_number = 1; |
|
|
page_incr = 1; |
|
|
reset_numbers = true; |
|
|
blank_join = 1; |
|
|
|
|
|
|
|
|
body_type = "t"; |
|
|
header_type = "n"; |
|
|
footer_type = "n"; |
|
|
|
|
|
|
|
|
current_type = body_type; |
|
|
current_regex = &body_regex; |
|
|
|
|
|
|
|
|
body_regex.buffer = NULL; |
|
|
body_regex.allocated = 0; |
|
|
body_regex.fastmap = body_fastmap; |
|
|
body_regex.translate = NULL; |
|
|
|
|
|
header_regex.buffer = NULL; |
|
|
header_regex.allocated = 0; |
|
|
header_regex.fastmap = header_fastmap; |
|
|
header_regex.translate = NULL; |
|
|
|
|
|
footer_regex.buffer = NULL; |
|
|
footer_regex.allocated = 0; |
|
|
footer_regex.fastmap = footer_fastmap; |
|
|
footer_regex.translate = NULL; |
|
|
|
|
|
|
|
|
section_del = DEFAULT_SECTION_DELIMITERS; |
|
|
header_del = NULL; |
|
|
body_del = NULL; |
|
|
footer_del = NULL; |
|
|
header_del_len = 0; |
|
|
body_del_len = 0; |
|
|
footer_del_len = 0; |
|
|
|
|
|
|
|
|
line_no = starting_line_number; |
|
|
line_no_overflow = false; |
|
|
|
|
|
|
|
|
if (print_no_line_fmt) { |
|
|
free(print_no_line_fmt); |
|
|
print_no_line_fmt = NULL; |
|
|
} |
|
|
print_no_line_fmt = testutil_build_no_line_fmt(lineno_width, separator_str); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
if (print_no_line_fmt) { |
|
|
free(print_no_line_fmt); |
|
|
print_no_line_fmt = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void test_process_file_numbers_nonempty_lines(void) |
|
|
{ |
|
|
const char *input = "alpha\n\nbeta\n"; |
|
|
char *out = testutil_run_and_capture(input); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
|
|
|
const char *expected = " 1|alpha\n" |
|
|
" |\n" |
|
|
" 2|beta\n"; |
|
|
TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_process_file_all_lines_with_blank_join(void) |
|
|
{ |
|
|
current_type = "a"; |
|
|
blank_join = 2; |
|
|
|
|
|
|
|
|
if (print_no_line_fmt) { free(print_no_line_fmt); } |
|
|
print_no_line_fmt = testutil_build_no_line_fmt(lineno_width, separator_str); |
|
|
|
|
|
const char *input = "\n\n\n"; |
|
|
char *out = testutil_run_and_capture(input); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
|
|
|
const char *expected = " |\n" |
|
|
" 1|\n" |
|
|
" |\n"; |
|
|
TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_process_file_section_delimiters(void) |
|
|
{ |
|
|
|
|
|
section_del = "%%"; |
|
|
header_del = "%%H"; |
|
|
body_del = "%%B"; |
|
|
footer_del = "%%F"; |
|
|
header_del_len = strlen(header_del); |
|
|
body_del_len = strlen(body_del); |
|
|
footer_del_len = strlen(footer_del); |
|
|
|
|
|
|
|
|
header_type = "a"; |
|
|
body_type = "t"; |
|
|
current_type = body_type; |
|
|
|
|
|
|
|
|
if (print_no_line_fmt) { free(print_no_line_fmt); } |
|
|
print_no_line_fmt = testutil_build_no_line_fmt(lineno_width, separator_str); |
|
|
|
|
|
const char *input = "b1\n%%H\nh1\n%%B\nb2\n"; |
|
|
char *out = testutil_run_and_capture(input); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *expected = " 1|b1\n" |
|
|
"\n" |
|
|
" 1|h1\n" |
|
|
"\n" |
|
|
" 1|b2\n"; |
|
|
TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_process_file_regex_numbering(void) |
|
|
{ |
|
|
|
|
|
body_regex.buffer = NULL; |
|
|
body_regex.allocated = 0; |
|
|
body_regex.fastmap = body_fastmap; |
|
|
body_regex.translate = NULL; |
|
|
|
|
|
|
|
|
re_syntax_options = |
|
|
RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES; |
|
|
|
|
|
const char *pattern = "x"; |
|
|
const char *errmsg = re_compile_pattern(pattern, strlen(pattern), &body_regex); |
|
|
TEST_ASSERT_NULL_MESSAGE(errmsg, "Failed to compile regex pattern"); |
|
|
|
|
|
current_type = "p"; |
|
|
current_regex = &body_regex; |
|
|
|
|
|
|
|
|
if (print_no_line_fmt) { free(print_no_line_fmt); } |
|
|
print_no_line_fmt = testutil_build_no_line_fmt(lineno_width, separator_str); |
|
|
|
|
|
const char *input = "ax\nb\nx\n"; |
|
|
char *out = testutil_run_and_capture(input); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
|
|
|
const char *expected = " 1|ax\n" |
|
|
" |b\n" |
|
|
" 2|x\n"; |
|
|
TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_process_file_numbers_nonempty_lines); |
|
|
RUN_TEST(test_process_file_all_lines_with_blank_join); |
|
|
RUN_TEST(test_process_file_section_delimiters); |
|
|
RUN_TEST(test_process_file_regex_numbering); |
|
|
return UNITY_END(); |
|
|
} |