|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <fcntl.h> |
|
|
#include <signal.h> |
|
|
#include <errno.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/stat.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *capture_stderr_begin(int *saved_fd, int pipefd[2]) |
|
|
{ |
|
|
if (pipe(pipefd) != 0) |
|
|
return NULL; |
|
|
|
|
|
fflush(stderr); |
|
|
*saved_fd = dup(STDERR_FILENO); |
|
|
if (*saved_fd < 0) |
|
|
return NULL; |
|
|
|
|
|
if (dup2(pipefd[1], STDERR_FILENO) < 0) |
|
|
return NULL; |
|
|
|
|
|
close(pipefd[1]); |
|
|
return (char *)1; |
|
|
} |
|
|
|
|
|
static char *capture_stderr_end(int saved_fd, int pipefd[2]) |
|
|
{ |
|
|
|
|
|
fflush(stderr); |
|
|
if (dup2(saved_fd, STDERR_FILENO) >= 0) { |
|
|
close(saved_fd); |
|
|
} |
|
|
|
|
|
|
|
|
char *buf = NULL; |
|
|
size_t cap = 0; |
|
|
size_t len = 0; |
|
|
for (;;) { |
|
|
char tmp[256]; |
|
|
ssize_t n = read(pipefd[0], tmp, sizeof(tmp)); |
|
|
if (n <= 0) break; |
|
|
if (len + (size_t)n + 1 > cap) { |
|
|
size_t ncap = cap ? cap * 2 : 512; |
|
|
while (ncap < len + (size_t)n + 1) ncap *= 2; |
|
|
char *nbuf = (char *)realloc(buf, ncap); |
|
|
if (!nbuf) { |
|
|
free(buf); |
|
|
buf = NULL; |
|
|
break; |
|
|
} |
|
|
buf = nbuf; |
|
|
cap = ncap; |
|
|
} |
|
|
memcpy(buf + len, tmp, (size_t)n); |
|
|
len += (size_t)n; |
|
|
buf[len] = '\0'; |
|
|
} |
|
|
close(pipefd[0]); |
|
|
if (!buf) { |
|
|
buf = (char *)malloc(1); |
|
|
if (buf) buf[0] = '\0'; |
|
|
} |
|
|
return buf; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
|
|
|
extern sig_atomic_t volatile interrupt_signal; |
|
|
extern sig_atomic_t volatile info_signal_count; |
|
|
extern int status_level; |
|
|
extern int progress_len; |
|
|
|
|
|
interrupt_signal = 0; |
|
|
info_signal_count = 0; |
|
|
status_level = 3; |
|
|
progress_len = 0; |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_process_signals_info_only_decrements_to_zero(void) |
|
|
{ |
|
|
extern void process_signals(void); |
|
|
extern sig_atomic_t volatile info_signal_count; |
|
|
extern sig_atomic_t volatile interrupt_signal; |
|
|
extern int status_level; |
|
|
|
|
|
info_signal_count = 5; |
|
|
interrupt_signal = 0; |
|
|
status_level = 1; |
|
|
|
|
|
process_signals(); |
|
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, (int)info_signal_count, "info_signal_count should be 0 after processing"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, (int)interrupt_signal, "interrupt_signal should remain 0"); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_process_signals_no_info_no_output(void) |
|
|
{ |
|
|
extern void process_signals(void); |
|
|
extern sig_atomic_t volatile info_signal_count; |
|
|
extern int status_level; |
|
|
|
|
|
info_signal_count = 0; |
|
|
status_level = 2; |
|
|
|
|
|
int saved; |
|
|
int pf[2]; |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(capture_stderr_begin(&saved, pf), "Failed to start capturing stderr"); |
|
|
|
|
|
process_signals(); |
|
|
|
|
|
char *out = capture_stderr_end(saved, pf); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_UINT_MESSAGE(0, (unsigned)strlen(out), "No output expected when no info signals"); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_process_signals_info_only_prints_expected_lines(void) |
|
|
{ |
|
|
extern void process_signals(void); |
|
|
extern sig_atomic_t volatile info_signal_count; |
|
|
extern int status_level; |
|
|
extern int progress_len; |
|
|
|
|
|
info_signal_count = 2; |
|
|
status_level = 2; |
|
|
progress_len = 0; |
|
|
|
|
|
int saved; |
|
|
int pf[2]; |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(capture_stderr_begin(&saved, pf), "Failed to start capturing stderr"); |
|
|
|
|
|
process_signals(); |
|
|
|
|
|
char *out = capture_stderr_end(saved, pf); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
|
|
|
|
|
|
size_t nl = 0; |
|
|
for (char *p = out; *p; ++p) if (*p == '\n') nl++; |
|
|
TEST_ASSERT_EQUAL_UINT_MESSAGE(4, nl, "Expected exactly two lines per info signal (total 4 newlines)"); |
|
|
|
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_process_signals_progress_line_newline_emitted_first(void) |
|
|
{ |
|
|
extern void process_signals(void); |
|
|
extern sig_atomic_t volatile info_signal_count; |
|
|
extern int status_level; |
|
|
extern int progress_len; |
|
|
|
|
|
info_signal_count = 1; |
|
|
status_level = 2; |
|
|
progress_len = 7; |
|
|
|
|
|
int saved; |
|
|
int pf[2]; |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(capture_stderr_begin(&saved, pf), "Failed to start capturing stderr"); |
|
|
|
|
|
process_signals(); |
|
|
|
|
|
char *out = capture_stderr_end(saved, pf); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_TRUE_MESSAGE(out[0] == '\n', "Expected leading newline when progress_len > 0"); |
|
|
|
|
|
free(out); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_process_signals_info_only_decrements_to_zero); |
|
|
RUN_TEST(test_process_signals_no_info_no_output); |
|
|
RUN_TEST(test_process_signals_info_only_prints_expected_lines); |
|
|
RUN_TEST(test_process_signals_progress_line_newline_emitted_first); |
|
|
return UNITY_END(); |
|
|
} |