|
|
#include "../../unity/unity.h" |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/wait.h> |
|
|
#include <errno.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *read_all_fd(int fd, size_t *len_out) |
|
|
{ |
|
|
size_t cap = 1024; |
|
|
size_t len = 0; |
|
|
char *buf = (char *)malloc(cap); |
|
|
if (!buf) return NULL; |
|
|
|
|
|
while (1) { |
|
|
ssize_t n = read(fd, buf + len, cap - len); |
|
|
if (n > 0) { |
|
|
len += (size_t)n; |
|
|
if (cap - len == 0) { |
|
|
size_t new_cap = cap * 2; |
|
|
char *nbuf = (char *)realloc(buf, new_cap); |
|
|
if (!nbuf) { free(buf); return NULL; } |
|
|
buf = nbuf; |
|
|
cap = new_cap; |
|
|
} |
|
|
} else if (n == 0) { |
|
|
break; |
|
|
} else { |
|
|
if (errno == EINTR) continue; |
|
|
free(buf); |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
char *out = (char *)malloc(len + 1); |
|
|
if (!out) { free(buf); return NULL; } |
|
|
memcpy(out, buf, len); |
|
|
out[len] = '\0'; |
|
|
free(buf); |
|
|
if (len_out) *len_out = len; |
|
|
return out; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int run_do_encode_capture(const char *input, size_t inlen, |
|
|
int wrap_column, int out_to_stderr, |
|
|
char **captured_out, size_t *captured_out_len, |
|
|
char **captured_err, size_t *captured_err_len) |
|
|
{ |
|
|
int out_pipe[2]; |
|
|
int err_pipe[2]; |
|
|
|
|
|
if (pipe(out_pipe) != 0) |
|
|
return -1; |
|
|
int need_err = out_to_stderr ? 1 : 0; |
|
|
if (need_err && pipe(err_pipe) != 0) { |
|
|
close(out_pipe[0]); close(out_pipe[1]); |
|
|
return -1; |
|
|
} |
|
|
|
|
|
fflush(stdout); |
|
|
fflush(stderr); |
|
|
pid_t pid = fork(); |
|
|
if (pid < 0) { |
|
|
close(out_pipe[0]); close(out_pipe[1]); |
|
|
if (need_err) { close(err_pipe[0]); close(err_pipe[1]); } |
|
|
return -1; |
|
|
} |
|
|
|
|
|
if (pid == 0) { |
|
|
|
|
|
if (dup2(out_pipe[1], STDOUT_FILENO) < 0) _exit(127); |
|
|
close(out_pipe[0]); close(out_pipe[1]); |
|
|
|
|
|
if (need_err) { |
|
|
if (dup2(err_pipe[1], STDERR_FILENO) < 0) _exit(127); |
|
|
close(err_pipe[0]); close(err_pipe[1]); |
|
|
} |
|
|
|
|
|
|
|
|
FILE *inf = tmpfile(); |
|
|
if (!inf) _exit(127); |
|
|
if (inlen) { |
|
|
if (fwrite(input, 1, inlen, inf) != inlen) _exit(127); |
|
|
} |
|
|
rewind(inf); |
|
|
|
|
|
|
|
|
if (out_to_stderr) |
|
|
do_encode(inf, "-", stderr, (idx_t)wrap_column); |
|
|
else |
|
|
do_encode(inf, "-", stdout, (idx_t)wrap_column); |
|
|
|
|
|
|
|
|
_exit(127); |
|
|
} |
|
|
|
|
|
|
|
|
close(out_pipe[1]); |
|
|
if (need_err) close(err_pipe[1]); |
|
|
|
|
|
char *outbuf = read_all_fd(out_pipe[0], captured_out_len); |
|
|
close(out_pipe[0]); |
|
|
|
|
|
char *errbuf = NULL; size_t errlen = 0; |
|
|
if (need_err) { |
|
|
errbuf = read_all_fd(err_pipe[0], &errlen); |
|
|
close(err_pipe[0]); |
|
|
} |
|
|
|
|
|
int status = 0; |
|
|
if (waitpid(pid, &status, 0) < 0) status = -1; |
|
|
|
|
|
if (captured_out) *captured_out = outbuf; else free(outbuf); |
|
|
if (need_err) { |
|
|
if (captured_err) { *captured_err = errbuf; if (captured_err_len) *captured_err_len = errlen; } |
|
|
else free(errbuf); |
|
|
} else { |
|
|
if (captured_err) *captured_err = NULL; if (captured_err_len) *captured_err_len = 0; |
|
|
} |
|
|
|
|
|
return status; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
#if BASE_TYPE == 42 |
|
|
|
|
|
base_length = base64_length_wrapper; |
|
|
required_padding = base64_required_padding; |
|
|
isubase = isubase64; |
|
|
base_encode = base64_encode; |
|
|
|
|
|
|
|
|
base_encode_ctx_init = NULL; |
|
|
base_encode_ctx = NULL; |
|
|
base_encode_ctx_finalize = NULL; |
|
|
#endif |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void assert_child_ok(int status) |
|
|
{ |
|
|
TEST_ASSERT_TRUE_MESSAGE(WIFEXITED(status), "Child did not exit normally"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, WEXITSTATUS(status), "Child exit status not 0"); |
|
|
} |
|
|
|
|
|
void test_do_encode_empty_input_no_wrap(void) |
|
|
{ |
|
|
const char *input = ""; |
|
|
char *out = NULL; size_t outlen = 0; |
|
|
int status = run_do_encode_capture(input, strlen(input), 0, 0, &out, &outlen, NULL, NULL); |
|
|
TEST_ASSERT_NOT_EQUAL(-1, status); |
|
|
assert_child_ok(status); |
|
|
TEST_ASSERT_EQUAL_size_t(0, outlen); |
|
|
if (out) free(out); |
|
|
} |
|
|
|
|
|
void test_do_encode_base64_no_wrap_foo(void) |
|
|
{ |
|
|
const char *input = "foo"; |
|
|
char *out = NULL; size_t outlen = 0; |
|
|
int status = run_do_encode_capture(input, strlen(input), 0, 0, &out, &outlen, NULL, NULL); |
|
|
TEST_ASSERT_NOT_EQUAL(-1, status); |
|
|
assert_child_ok(status); |
|
|
TEST_ASSERT_EQUAL_STRING_LEN("Zm9v", out, 4); |
|
|
TEST_ASSERT_EQUAL_size_t(4, outlen); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
void test_do_encode_wrap4_exact_boundary_newline_once(void) |
|
|
{ |
|
|
const char *input = "foo"; |
|
|
char *out = NULL; size_t outlen = 0; |
|
|
int status = run_do_encode_capture(input, strlen(input), 4, 0, &out, &outlen, NULL, NULL); |
|
|
TEST_ASSERT_NOT_EQUAL(-1, status); |
|
|
assert_child_ok(status); |
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING_LEN("Zm9v\n", out, 5); |
|
|
TEST_ASSERT_EQUAL_size_t(5, outlen); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
void test_do_encode_wrap4_inserts_mid_and_final_newlines(void) |
|
|
{ |
|
|
const char *input = "foobar"; |
|
|
char *out = NULL; size_t outlen = 0; |
|
|
int status = run_do_encode_capture(input, strlen(input), 4, 0, &out, &outlen, NULL, NULL); |
|
|
TEST_ASSERT_NOT_EQUAL(-1, status); |
|
|
assert_child_ok(status); |
|
|
|
|
|
const char *expected = "Zm9v\nYmFy\n"; |
|
|
TEST_ASSERT_EQUAL_size_t(strlen(expected), outlen); |
|
|
TEST_ASSERT_EQUAL_STRING_LEN(expected, out, outlen); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
void test_do_encode_newlines_go_to_out_stream(void) |
|
|
{ |
|
|
const char *input = "foobar"; |
|
|
char *capt_out = NULL, *capt_err = NULL; size_t outlen = 0, errlen = 0; |
|
|
|
|
|
int status = run_do_encode_capture(input, strlen(input), 4, 1, |
|
|
&capt_out, &outlen, |
|
|
&capt_err, &errlen); |
|
|
TEST_ASSERT_NOT_EQUAL(-1, status); |
|
|
assert_child_ok(status); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_STRING_LEN("Zm9vYmFy", capt_out, 8); |
|
|
TEST_ASSERT_EQUAL_size_t(8, outlen); |
|
|
|
|
|
|
|
|
TEST_ASSERT_NOT_NULL(capt_err); |
|
|
TEST_ASSERT_EQUAL_size_t(2, errlen); |
|
|
TEST_ASSERT_EQUAL_UINT8('\n', (unsigned char)capt_err[0]); |
|
|
TEST_ASSERT_EQUAL_UINT8('\n', (unsigned char)capt_err[1]); |
|
|
|
|
|
free(capt_out); |
|
|
free(capt_err); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_do_encode_empty_input_no_wrap); |
|
|
RUN_TEST(test_do_encode_base64_no_wrap_foo); |
|
|
RUN_TEST(test_do_encode_wrap4_exact_boundary_newline_once); |
|
|
RUN_TEST(test_do_encode_wrap4_inserts_mid_and_final_newlines); |
|
|
RUN_TEST(test_do_encode_newlines_go_to_out_stream); |
|
|
return UNITY_END(); |
|
|
} |