| #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(); |
| } |