| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <stdbool.h> |
|
|
| |
| void setUp(void) { |
| |
| } |
| void tearDown(void) { |
| |
| } |
|
|
| |
| static char *read_all_into_string(int fd) { |
| size_t cap = 1024; |
| size_t len = 0; |
| char *buf = (char *)malloc(cap); |
| if (!buf) return NULL; |
| for (;;) { |
| if (len + 512 > cap) { |
| size_t ncap = cap * 2; |
| char *nbuf = (char *)realloc(buf, ncap); |
| if (!nbuf) { free(buf); return NULL; } |
| cap = ncap; buf = nbuf; |
| } |
| ssize_t n = read(fd, buf + len, 512); |
| if (n < 0) { |
| if (errno == EINTR) continue; |
| break; |
| } |
| if (n == 0) break; |
| len += (size_t)n; |
| } |
| buf[len] = '\0'; |
| return buf; |
| } |
|
|
| |
| static char *capture_stderr_and_call(void (*cb)(void)) { |
| int pipefd[2]; |
| if (pipe(pipefd) != 0) { |
| return NULL; |
| } |
|
|
| int saved_stderr = dup(STDERR_FILENO); |
| if (saved_stderr < 0) { |
| close(pipefd[0]); close(pipefd[1]); |
| return NULL; |
| } |
|
|
| |
| if (dup2(pipefd[1], STDERR_FILENO) < 0) { |
| close(pipefd[0]); close(pipefd[1]); close(saved_stderr); |
| return NULL; |
| } |
| |
| close(pipefd[1]); |
|
|
| |
| cb(); |
|
|
| |
| fflush(stderr); |
|
|
| |
| dup2(saved_stderr, STDERR_FILENO); |
| close(saved_stderr); |
|
|
| |
| char *out = read_all_into_string(pipefd[0]); |
| close(pipefd[0]); |
| return out; |
| } |
|
|
| |
| static bool str_contains(const char *haystack, const char *needle) { |
| if (!haystack || !needle) return false; |
| return strstr(haystack, needle) != NULL; |
| } |
|
|
| |
| |
| extern int progress_len; |
| |
|
|
| |
| static int g_errnum; |
| static const char *g_fmt; |
| static const char *g_sarg; |
| static int g_iarg; |
| static void call_diagnose_s_i(void) { |
| diagnose(g_errnum, g_fmt, g_sarg, g_iarg); |
| } |
| static void call_diagnose_s(void) { |
| diagnose(g_errnum, g_fmt, g_sarg); |
| } |
| static void call_diagnose_literal(void) { |
| diagnose(g_errnum, "Literal message"); |
| } |
|
|
| void test_diagnose_inserts_newline_when_progress_pending(void) { |
| progress_len = 5; |
| g_errnum = 0; g_fmt = "Test %s"; g_sarg = "NL"; |
| char *out = capture_stderr_and_call(call_diagnose_s); |
| TEST_ASSERT_NOT_NULL(out); |
| |
| TEST_ASSERT_TRUE_MESSAGE(out[0] == '\n', "diagnose should prepend a newline when progress_len>0"); |
| |
| TEST_ASSERT_TRUE(str_contains(out, "Test NL")); |
| |
| TEST_ASSERT_EQUAL_INT(0, progress_len); |
| free(out); |
| } |
|
|
| void test_diagnose_no_leading_newline_without_progress(void) { |
| progress_len = 0; |
| g_errnum = 0; g_fmt = "Hello %s"; g_sarg = "World"; |
| char *out = capture_stderr_and_call(call_diagnose_s); |
| TEST_ASSERT_NOT_NULL(out); |
| |
| TEST_ASSERT_TRUE_MESSAGE(out[0] != '\n', "diagnose should not prepend newline when progress_len==0"); |
| TEST_ASSERT_TRUE(str_contains(out, "Hello World")); |
| TEST_ASSERT_EQUAL_INT(0, progress_len); |
| free(out); |
| } |
|
|
| void test_diagnose_includes_errno_message_when_errnum_nonzero(void) { |
| progress_len = 0; |
| g_errnum = EINVAL; g_fmt = "Bad option %s"; g_sarg = "--foo"; |
| const char *errtxt = strerror(g_errnum); |
| char *out = capture_stderr_and_call(call_diagnose_s); |
| TEST_ASSERT_NOT_NULL(out); |
| |
| TEST_ASSERT_TRUE(str_contains(out, "Bad option --foo")); |
| |
| TEST_ASSERT_TRUE_MESSAGE(str_contains(out, errtxt), "diagnose should include strerror text when errnum != 0"); |
| free(out); |
| } |
|
|
| void test_diagnose_varargs_formatting_with_int_and_string(void) { |
| progress_len = 0; |
| g_errnum = 0; g_fmt = "Value:%d;Name:%s"; g_sarg = "Z"; g_iarg = 123; |
| char *out = capture_stderr_and_call(call_diagnose_s_i); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_TRUE(str_contains(out, "Value:123;Name:Z")); |
| free(out); |
| } |
|
|
| void test_diagnose_resets_progress_len_even_on_simple_message(void) { |
| progress_len = 2; |
| g_errnum = 0; |
| char *out = capture_stderr_and_call(call_diagnose_literal); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_INT(0, progress_len); |
| TEST_ASSERT_TRUE(str_contains(out, "Literal message")); |
| free(out); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_diagnose_inserts_newline_when_progress_pending); |
| RUN_TEST(test_diagnose_no_leading_newline_without_progress); |
| RUN_TEST(test_diagnose_includes_errno_message_when_errnum_nonzero); |
| RUN_TEST(test_diagnose_varargs_formatting_with_int_and_string); |
| RUN_TEST(test_diagnose_resets_progress_len_even_on_simple_message); |
| return UNITY_END(); |
| } |