|
|
#include "../../unity/unity.h" |
|
|
#include <unistd.h> |
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
#include <errno.h> |
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char* capture_write_pending_output(char *outbuf, char **bpout, size_t *out_len) |
|
|
{ |
|
|
int saved_stdout = -1; |
|
|
int p[2] = {-1, -1}; |
|
|
char *result = NULL; |
|
|
size_t result_len = 0; |
|
|
|
|
|
saved_stdout = dup(STDOUT_FILENO); |
|
|
if (saved_stdout < 0) |
|
|
return NULL; |
|
|
|
|
|
if (pipe(p) != 0) { |
|
|
close(saved_stdout); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
if (dup2(p[1], STDOUT_FILENO) < 0) { |
|
|
close(saved_stdout); |
|
|
close(p[0]); |
|
|
close(p[1]); |
|
|
return NULL; |
|
|
} |
|
|
close(p[1]); |
|
|
|
|
|
|
|
|
write_pending(outbuf, bpout); |
|
|
|
|
|
|
|
|
if (dup2(saved_stdout, STDOUT_FILENO) < 0) { |
|
|
|
|
|
close(saved_stdout); |
|
|
close(p[0]); |
|
|
return NULL; |
|
|
} |
|
|
close(saved_stdout); |
|
|
|
|
|
|
|
|
{ |
|
|
char tmp[1024]; |
|
|
ssize_t n; |
|
|
size_t cap = 0; |
|
|
while ((n = read(p[0], tmp, sizeof tmp)) > 0) { |
|
|
if (result_len + (size_t)n > cap) { |
|
|
size_t new_cap = cap ? cap * 2 : 1024; |
|
|
while (new_cap < result_len + (size_t)n) |
|
|
new_cap *= 2; |
|
|
char *new_buf = (char*)realloc(result, new_cap); |
|
|
if (!new_buf) { |
|
|
free(result); |
|
|
close(p[0]); |
|
|
return NULL; |
|
|
} |
|
|
result = new_buf; |
|
|
cap = new_cap; |
|
|
} |
|
|
memcpy(result + result_len, tmp, (size_t)n); |
|
|
result_len += (size_t)n; |
|
|
} |
|
|
close(p[0]); |
|
|
if (n < 0) { |
|
|
free(result); |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!result) { |
|
|
result = (char*)malloc(1); |
|
|
if (!result) return NULL; |
|
|
} |
|
|
|
|
|
if (out_len) |
|
|
*out_len = result_len; |
|
|
return result; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void test_write_pending_no_pending_data(void) |
|
|
{ |
|
|
char outbuf[8] = {0}; |
|
|
char *bp = outbuf; |
|
|
|
|
|
size_t captured_len = 0; |
|
|
char *captured = capture_write_pending_output(outbuf, &bp, &captured_len); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(captured, "Failed to capture output"); |
|
|
TEST_ASSERT_EQUAL_size_t(0, captured_len); |
|
|
TEST_ASSERT_EQUAL_PTR(outbuf, bp); |
|
|
free(captured); |
|
|
} |
|
|
|
|
|
|
|
|
void test_write_pending_writes_and_resets_pointer(void) |
|
|
{ |
|
|
const char *msg = "Hello, world!"; |
|
|
size_t msg_len = strlen(msg); |
|
|
char outbuf[64]; |
|
|
memcpy(outbuf, msg, msg_len); |
|
|
char *bp = outbuf + msg_len; |
|
|
|
|
|
size_t captured_len = 0; |
|
|
char *captured = capture_write_pending_output(outbuf, &bp, &captured_len); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(captured, "Failed to capture output"); |
|
|
TEST_ASSERT_EQUAL_size_t(msg_len, captured_len); |
|
|
TEST_ASSERT_EQUAL_MEMORY(msg, captured, msg_len); |
|
|
TEST_ASSERT_EQUAL_PTR(outbuf, bp); |
|
|
free(captured); |
|
|
} |
|
|
|
|
|
|
|
|
void test_write_pending_multiple_independent_flushes(void) |
|
|
{ |
|
|
char outbuf[16]; |
|
|
|
|
|
|
|
|
memcpy(outbuf, "ABC", 3); |
|
|
char *bp1 = outbuf + 3; |
|
|
size_t len1 = 0; |
|
|
char *cap1 = capture_write_pending_output(outbuf, &bp1, &len1); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(cap1, "Failed to capture output (first)"); |
|
|
TEST_ASSERT_EQUAL_size_t(3, len1); |
|
|
TEST_ASSERT_EQUAL_MEMORY("ABC", cap1, 3); |
|
|
TEST_ASSERT_EQUAL_PTR(outbuf, bp1); |
|
|
|
|
|
|
|
|
memcpy(outbuf, "DEF", 3); |
|
|
char *bp2 = outbuf + 3; |
|
|
size_t len2 = 0; |
|
|
char *cap2 = capture_write_pending_output(outbuf, &bp2, &len2); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(cap2, "Failed to capture output (second)"); |
|
|
TEST_ASSERT_EQUAL_size_t(3, len2); |
|
|
TEST_ASSERT_EQUAL_MEMORY("DEF", cap2, 3); |
|
|
TEST_ASSERT_EQUAL_PTR(outbuf, bp2); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_size_t(3, len1); |
|
|
TEST_ASSERT_EQUAL_size_t(3, len2); |
|
|
|
|
|
free(cap1); |
|
|
free(cap2); |
|
|
} |
|
|
|
|
|
|
|
|
void test_write_pending_large_payload(void) |
|
|
{ |
|
|
const size_t N = 8192; |
|
|
char *outbuf = (char*)malloc(N); |
|
|
TEST_ASSERT_NOT_NULL(outbuf); |
|
|
|
|
|
for (size_t i = 0; i < N; i++) |
|
|
outbuf[i] = (char)('a' + (i % 26)); |
|
|
|
|
|
char *bp = outbuf + N; |
|
|
|
|
|
size_t captured_len = 0; |
|
|
char *captured = capture_write_pending_output(outbuf, &bp, &captured_len); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(captured, "Failed to capture output"); |
|
|
TEST_ASSERT_EQUAL_size_t(N, captured_len); |
|
|
TEST_ASSERT_EQUAL_MEMORY(outbuf, captured, N); |
|
|
TEST_ASSERT_EQUAL_PTR(outbuf, bp); |
|
|
|
|
|
free(captured); |
|
|
free(outbuf); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_write_pending_no_pending_data); |
|
|
RUN_TEST(test_write_pending_writes_and_resets_pointer); |
|
|
RUN_TEST(test_write_pending_multiple_independent_flushes); |
|
|
RUN_TEST(test_write_pending_large_payload); |
|
|
return UNITY_END(); |
|
|
} |