| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <locale.h> |
| #include <errno.h> |
|
|
| |
| |
|
|
| |
| static FILE *cap_file = NULL; |
| static int saved_stderr_fd = -1; |
|
|
| static void start_capture_stderr(void) |
| { |
| fflush(stderr); |
| saved_stderr_fd = dup(STDERR_FILENO); |
| TEST_ASSERT_TRUE_MESSAGE(saved_stderr_fd >= 0, "dup(STDERR_FILENO) failed"); |
|
|
| cap_file = tmpfile(); |
| TEST_ASSERT_NOT_NULL_MESSAGE(cap_file, "tmpfile() failed"); |
|
|
| int cap_fd = fileno(cap_file); |
| TEST_ASSERT_TRUE_MESSAGE(cap_fd >= 0, "fileno(tmpfile) failed"); |
|
|
| int rc = dup2(cap_fd, STDERR_FILENO); |
| TEST_ASSERT_TRUE_MESSAGE(rc >= 0, "dup2 to redirect stderr failed"); |
| } |
|
|
| static char *finish_capture_stderr(void) |
| { |
| fflush(stderr); |
| TEST_ASSERT_NOT_NULL_MESSAGE(cap_file, "No capture active"); |
|
|
| long size; |
| if (fseek(cap_file, 0, SEEK_END) != 0) |
| TEST_FAIL_MESSAGE("fseek end failed"); |
| size = ftell(cap_file); |
| if (size < 0) |
| TEST_FAIL_MESSAGE("ftell failed"); |
| if (fseek(cap_file, 0, SEEK_SET) != 0) |
| TEST_FAIL_MESSAGE("fseek set failed"); |
|
|
| char *buf = (char *)malloc((size_t)size + 1); |
| TEST_ASSERT_NOT_NULL_MESSAGE(buf, "malloc failed"); |
| size_t n = fread(buf, 1, (size_t)size, cap_file); |
| buf[n] = '\0'; |
|
|
| |
| int rc = dup2(saved_stderr_fd, STDERR_FILENO); |
| TEST_ASSERT_TRUE_MESSAGE(rc >= 0, "dup2 restore stderr failed"); |
| close(saved_stderr_fd); |
| saved_stderr_fd = -1; |
|
|
| fclose(cap_file); |
| cap_file = NULL; |
|
|
| return buf; |
| } |
|
|
| |
| static int count_newlines(const char *s) |
| { |
| int c = 0; |
| for (; *s; ++s) if (*s == '\n') ++c; |
| return c; |
| } |
|
|
| |
| static void reset_print_stats_state(void) |
| { |
| |
| status_level = STATUS_DEFAULT; |
| progress_len = 0; |
| r_full = 0; |
| r_partial = 0; |
| w_full = 0; |
| w_partial = 0; |
| r_truncate = 0; |
| w_bytes = 0; |
| reported_w_bytes = -1; |
| } |
|
|
| void setUp(void) { |
| setlocale(LC_ALL, "C"); |
| reset_print_stats_state(); |
| } |
|
|
| void tearDown(void) { |
| |
| if (cap_file) { |
| char *discard = finish_capture_stderr(); |
| free(discard); |
| } |
| } |
|
|
| |
| void test_print_stats_status_none_no_output_no_progress_reset(void) |
| { |
| status_level = STATUS_NONE; |
| progress_len = 5; |
| r_full = 1; r_partial = 2; w_full = 3; w_partial = 4; r_truncate = 1; |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| TEST_ASSERT_EQUAL_INT(0, (int)strlen(out)); |
| TEST_ASSERT_EQUAL_INT(5, progress_len); |
|
|
| free(out); |
| } |
|
|
| |
| void test_print_stats_basic_records_output_no_truncate(void) |
| { |
| status_level = STATUS_NOXFER; |
| progress_len = 0; |
| r_full = 2; r_partial = 3; w_full = 4; w_partial = 5; r_truncate = 0; |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| const char *expected = "2+3 records in\n4+5 records out\n"; |
| TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
| free(out); |
| } |
|
|
| |
| void test_print_stats_truncate_singular(void) |
| { |
| status_level = STATUS_NOXFER; |
| r_truncate = 1; |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| const char *expected = "0+0 records in\n0+0 records out\n1 truncated record\n"; |
| TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
| free(out); |
| } |
|
|
| |
| void test_print_stats_truncate_plural(void) |
| { |
| status_level = STATUS_NOXFER; |
| r_truncate = 2; |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| const char *expected = "0+0 records in\n0+0 records out\n2 truncated records\n"; |
| TEST_ASSERT_EQUAL_STRING(expected, out); |
|
|
| free(out); |
| } |
|
|
| |
| void test_print_stats_progress_len_newline_and_reset(void) |
| { |
| status_level = STATUS_NOXFER; |
| progress_len = 10; |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| TEST_ASSERT_TRUE_MESSAGE(out[0] == '\n', "Expected leading newline when progress_len > 0"); |
| const char *rest = out + 1; |
| const char *expected_rest = "0+0 records in\n0+0 records out\n"; |
| TEST_ASSERT_EQUAL_STRING(expected_rest, rest); |
| TEST_ASSERT_EQUAL_INT(0, progress_len); |
|
|
| free(out); |
| } |
|
|
| |
| void test_print_stats_calls_print_xfer_stats_and_updates_reported(void) |
| { |
| status_level = STATUS_DEFAULT; |
| progress_len = 0; |
| r_truncate = 0; |
| w_bytes = 12345; |
| reported_w_bytes = -1; |
|
|
| |
| |
| start_time = gethrxtime(); |
|
|
| start_capture_stderr(); |
| print_stats(); |
| char *out = finish_capture_stderr(); |
|
|
| TEST_ASSERT_EQUAL_INT64((int64_t)w_bytes, (int64_t)reported_w_bytes); |
|
|
| int nl = count_newlines(out); |
| TEST_ASSERT_GREATER_OR_EQUAL_INT(3, nl); |
|
|
| free(out); |
| } |
|
|
| int main(void) |
| { |
| UNITY_BEGIN(); |
| RUN_TEST(test_print_stats_status_none_no_output_no_progress_reset); |
| RUN_TEST(test_print_stats_basic_records_output_no_truncate); |
| RUN_TEST(test_print_stats_truncate_singular); |
| RUN_TEST(test_print_stats_truncate_plural); |
| RUN_TEST(test_print_stats_progress_len_newline_and_reset); |
| RUN_TEST(test_print_stats_calls_print_xfer_stats_and_updates_reported); |
| return UNITY_END(); |
| } |