|
|
#include "../../unity/unity.h" |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <fcntl.h> |
|
|
#include <sys/stat.h> |
|
|
#include <sys/types.h> |
|
|
#include <errno.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
int saved_fd; |
|
|
int tmp_fd; |
|
|
char path[64]; |
|
|
} capture_ctx; |
|
|
|
|
|
static int begin_capture(capture_ctx *ctx) { |
|
|
strcpy(ctx->path, "/tmp/nl_cap_XXXXXX"); |
|
|
ctx->tmp_fd = mkstemp(ctx->path); |
|
|
if (ctx->tmp_fd < 0) return -1; |
|
|
|
|
|
ctx->saved_fd = dup(fileno(stdout)); |
|
|
if (ctx->saved_fd < 0) { |
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return -1; |
|
|
} |
|
|
|
|
|
fflush(stdout); |
|
|
if (dup2(ctx->tmp_fd, fileno(stdout)) < 0) { |
|
|
close(ctx->tmp_fd); |
|
|
close(ctx->saved_fd); |
|
|
unlink(ctx->path); |
|
|
return -1; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
static char *end_capture(capture_ctx *ctx) { |
|
|
fflush(stdout); |
|
|
|
|
|
|
|
|
dup2(ctx->saved_fd, fileno(stdout)); |
|
|
close(ctx->saved_fd); |
|
|
|
|
|
|
|
|
struct stat st; |
|
|
if (fstat(ctx->tmp_fd, &st) != 0) { |
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
off_t sz = st.st_size; |
|
|
if (lseek(ctx->tmp_fd, 0, SEEK_SET) < 0) { |
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
char *buf = (char *)malloc((size_t)sz + 1); |
|
|
if (!buf) { |
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
ssize_t rd = read(ctx->tmp_fd, buf, (size_t)sz); |
|
|
if (rd < 0) { |
|
|
free(buf); |
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return NULL; |
|
|
} |
|
|
buf[rd] = '\0'; |
|
|
|
|
|
close(ctx->tmp_fd); |
|
|
unlink(ctx->path); |
|
|
return buf; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *set_line(const char *s) { |
|
|
size_t len = strlen(s); |
|
|
char *copy = (char *)malloc(len); |
|
|
memcpy(copy, s, len); |
|
|
line_buf.buffer = copy; |
|
|
line_buf.length = len; |
|
|
return copy; |
|
|
} |
|
|
|
|
|
|
|
|
static char *call_and_capture_proc_text(const char *content) { |
|
|
capture_ctx ctx; |
|
|
if (begin_capture(&ctx) != 0) { |
|
|
return NULL; |
|
|
} |
|
|
char *mem = set_line(content); |
|
|
|
|
|
proc_text(); |
|
|
char *out = end_capture(&ctx); |
|
|
free(mem); |
|
|
return out; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void reset_proc_text_static_state(void) { |
|
|
const char *saved_type = current_type; |
|
|
intmax_t saved_blank_join = blank_join; |
|
|
char const *saved_sep = separator_str; |
|
|
char const *saved_fmt = lineno_format; |
|
|
int saved_width = lineno_width; |
|
|
char const *saved_no_line_fmt = print_no_line_fmt; |
|
|
intmax_t saved_line_no = line_no; |
|
|
intmax_t saved_incr = page_incr; |
|
|
|
|
|
current_type = "a"; |
|
|
blank_join = 2; |
|
|
separator_str = "|"; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
lineno_width = 2; |
|
|
print_no_line_fmt = ""; |
|
|
line_no = 1; |
|
|
page_incr = 1; |
|
|
|
|
|
capture_ctx ctx; |
|
|
if (begin_capture(&ctx) == 0) { |
|
|
char *mem = set_line("R\n"); |
|
|
proc_text(); |
|
|
char *d = end_capture(&ctx); |
|
|
free(mem); |
|
|
free(d); |
|
|
} |
|
|
|
|
|
|
|
|
current_type = saved_type; |
|
|
blank_join = saved_blank_join; |
|
|
separator_str = saved_sep; |
|
|
lineno_format = saved_fmt; |
|
|
lineno_width = saved_width; |
|
|
print_no_line_fmt = saved_no_line_fmt; |
|
|
line_no = saved_line_no; |
|
|
page_incr = saved_incr; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
separator_str = "|"; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
lineno_width = 3; |
|
|
page_incr = 1; |
|
|
line_no = 1; |
|
|
line_no_overflow = false; |
|
|
print_no_line_fmt = "U"; |
|
|
current_type = "n"; |
|
|
blank_join = 1; |
|
|
reset_proc_text_static_state(); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void test_proc_text_a_blank_join_1(void) { |
|
|
current_type = "a"; |
|
|
blank_join = 1; |
|
|
separator_str = "|"; |
|
|
lineno_width = 3; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
print_no_line_fmt = "<>"; |
|
|
line_no = 7; |
|
|
page_incr = 1; |
|
|
|
|
|
char *out1 = call_and_capture_proc_text("X\n"); |
|
|
TEST_ASSERT_NOT_NULL(out1); |
|
|
TEST_ASSERT_EQUAL_STRING(" 7|X\n", out1); |
|
|
free(out1); |
|
|
TEST_ASSERT_EQUAL_INT64(8, line_no); |
|
|
|
|
|
char *out2 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(out2); |
|
|
TEST_ASSERT_EQUAL_STRING(" 8|\n", out2); |
|
|
free(out2); |
|
|
TEST_ASSERT_EQUAL_INT64(9, line_no); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void test_proc_text_a_blank_join_gt1_sequence(void) { |
|
|
current_type = "a"; |
|
|
blank_join = 3; |
|
|
separator_str = "|"; |
|
|
lineno_width = 2; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
print_no_line_fmt = "U"; |
|
|
line_no = 1; |
|
|
page_incr = 1; |
|
|
|
|
|
char *o1 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o1); |
|
|
TEST_ASSERT_EQUAL_STRING("U\n", o1); |
|
|
free(o1); |
|
|
TEST_ASSERT_EQUAL_INT64(1, line_no); |
|
|
|
|
|
char *o2 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o2); |
|
|
TEST_ASSERT_EQUAL_STRING("U\n", o2); |
|
|
free(o2); |
|
|
TEST_ASSERT_EQUAL_INT64(1, line_no); |
|
|
|
|
|
char *o3 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o3); |
|
|
TEST_ASSERT_EQUAL_STRING(" 1|\n", o3); |
|
|
free(o3); |
|
|
TEST_ASSERT_EQUAL_INT64(2, line_no); |
|
|
|
|
|
char *o4 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o4); |
|
|
TEST_ASSERT_EQUAL_STRING("U\n", o4); |
|
|
free(o4); |
|
|
TEST_ASSERT_EQUAL_INT64(2, line_no); |
|
|
|
|
|
char *o5 = call_and_capture_proc_text("abc\n"); |
|
|
TEST_ASSERT_NOT_NULL(o5); |
|
|
TEST_ASSERT_EQUAL_STRING(" 2|abc\n", o5); |
|
|
free(o5); |
|
|
TEST_ASSERT_EQUAL_INT64(3, line_no); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_proc_text_t_type(void) { |
|
|
current_type = "t"; |
|
|
print_no_line_fmt = "X"; |
|
|
separator_str = "|"; |
|
|
lineno_width = 2; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
line_no = 42; |
|
|
page_incr = 1; |
|
|
|
|
|
char *o1 = call_and_capture_proc_text("hello\n"); |
|
|
TEST_ASSERT_NOT_NULL(o1); |
|
|
TEST_ASSERT_EQUAL_STRING("42|hello\n", o1); |
|
|
free(o1); |
|
|
TEST_ASSERT_EQUAL_INT64(43, line_no); |
|
|
|
|
|
char *o2 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o2); |
|
|
TEST_ASSERT_EQUAL_STRING("X\n", o2); |
|
|
free(o2); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT64(43, line_no); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_proc_text_n_type(void) { |
|
|
current_type = "n"; |
|
|
print_no_line_fmt = "Z"; |
|
|
separator_str = "|"; |
|
|
lineno_width = 2; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
line_no = 5; |
|
|
page_incr = 1; |
|
|
|
|
|
char *o1 = call_and_capture_proc_text("q\n"); |
|
|
TEST_ASSERT_NOT_NULL(o1); |
|
|
TEST_ASSERT_EQUAL_STRING("Zq\n", o1); |
|
|
free(o1); |
|
|
TEST_ASSERT_EQUAL_INT64(5, line_no); |
|
|
|
|
|
char *o2 = call_and_capture_proc_text("\n"); |
|
|
TEST_ASSERT_NOT_NULL(o2); |
|
|
TEST_ASSERT_EQUAL_STRING("Z\n", o2); |
|
|
free(o2); |
|
|
TEST_ASSERT_EQUAL_INT64(5, line_no); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void test_proc_text_p_type_regex(void) { |
|
|
|
|
|
current_type = "p"; |
|
|
current_regex = &body_regex; |
|
|
|
|
|
|
|
|
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 *errmsg = re_compile_pattern("foo", strlen("foo"), &body_regex); |
|
|
TEST_ASSERT_NULL_MESSAGE(errmsg, "Failed to compile regex pattern"); |
|
|
|
|
|
print_no_line_fmt = "N"; |
|
|
separator_str = "|"; |
|
|
lineno_width = 2; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
line_no = 5; |
|
|
page_incr = 1; |
|
|
|
|
|
char *o1 = call_and_capture_proc_text("foo\n"); |
|
|
TEST_ASSERT_NOT_NULL(o1); |
|
|
TEST_ASSERT_EQUAL_STRING(" 5|foo\n", o1); |
|
|
free(o1); |
|
|
TEST_ASSERT_EQUAL_INT64(6, line_no); |
|
|
|
|
|
char *o2 = call_and_capture_proc_text("bar\n"); |
|
|
TEST_ASSERT_NOT_NULL(o2); |
|
|
TEST_ASSERT_EQUAL_STRING("Nbar\n", o2); |
|
|
free(o2); |
|
|
TEST_ASSERT_EQUAL_INT64(6, line_no); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_proc_text_page_incr(void) { |
|
|
current_type = "a"; |
|
|
blank_join = 1; |
|
|
separator_str = "|"; |
|
|
lineno_width = 3; |
|
|
lineno_format = FORMAT_RIGHT_NOLZ; |
|
|
print_no_line_fmt = ""; |
|
|
line_no = 10; |
|
|
page_incr = 10; |
|
|
|
|
|
char *o = call_and_capture_proc_text("X\n"); |
|
|
TEST_ASSERT_NOT_NULL(o); |
|
|
TEST_ASSERT_EQUAL_STRING(" 10|X\n", o); |
|
|
free(o); |
|
|
TEST_ASSERT_EQUAL_INT64(20, line_no); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
|
|
|
RUN_TEST(test_proc_text_a_blank_join_1); |
|
|
RUN_TEST(test_proc_text_a_blank_join_gt1_sequence); |
|
|
RUN_TEST(test_proc_text_t_type); |
|
|
RUN_TEST(test_proc_text_n_type); |
|
|
RUN_TEST(test_proc_text_p_type_regex); |
|
|
RUN_TEST(test_proc_text_page_incr); |
|
|
|
|
|
return UNITY_END(); |
|
|
} |