| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <endian.h> |
| #include <errno.h> |
|
|
| |
| |
| |
| |
| |
|
|
| void setUp(void) { |
| |
| } |
|
|
| void tearDown(void) { |
| |
| } |
|
|
| |
| static int saved_stdout_fd = -1; |
| static int capture_fd = -1; |
|
|
| static void start_capture(void) { |
| fflush(stdout); |
|
|
| saved_stdout_fd = dup(fileno(stdout)); |
| TEST_ASSERT_MESSAGE(saved_stdout_fd != -1, "dup(saved stdout) failed"); |
|
|
| char tmpl[] = "/tmp/cksum_out_XXXXXX"; |
| capture_fd = mkstemp(tmpl); |
| TEST_ASSERT_MESSAGE(capture_fd != -1, "mkstemp failed for stdout capture"); |
| |
| unlink(tmpl); |
|
|
| int r = dup2(capture_fd, fileno(stdout)); |
| if (r == -1) { |
| int err = errno; |
| |
| close(capture_fd); |
| capture_fd = -1; |
| TEST_FAIL_MESSAGE("dup2 to redirect stdout failed"); |
| } |
| } |
|
|
| static char *stop_capture(size_t *out_size) { |
| |
| fflush(stdout); |
|
|
| int r = dup2(saved_stdout_fd, fileno(stdout)); |
| int saved_err = errno; |
| close(saved_stdout_fd); |
| saved_stdout_fd = -1; |
|
|
| |
| TEST_ASSERT_MESSAGE(r != -1, "dup2 restoring stdout failed"); |
|
|
| |
| off_t sz = lseek(capture_fd, 0, SEEK_END); |
| TEST_ASSERT_MESSAGE(sz != (off_t)-1, "lseek SEEK_END failed on capture fd"); |
|
|
| int lr = lseek(capture_fd, 0, SEEK_SET); |
| TEST_ASSERT_MESSAGE(lr != -1, "lseek SEEK_SET failed on capture fd"); |
|
|
| size_t alloc_sz = (size_t) (sz > 0 ? sz : 0); |
| char *buf = (char *)malloc(alloc_sz + 1); |
| TEST_ASSERT_NOT_NULL(buf); |
|
|
| ssize_t n = (alloc_sz > 0) ? read(capture_fd, buf, alloc_sz) : 0; |
| if (alloc_sz > 0) |
| TEST_ASSERT_EQUAL_size_t(alloc_sz, (size_t)n); |
|
|
| |
| buf[alloc_sz] = '\0'; |
|
|
| close(capture_fd); |
| capture_fd = -1; |
|
|
| if (out_size) *out_size = (size_t)alloc_sz; |
| return buf; |
| } |
|
|
| |
| static char *build_expected_text(unsigned int digest, uintmax_t length, |
| const char *file, unsigned char delim, bool args) |
| { |
| |
| char tmp[64]; |
| int n1 = snprintf(tmp, sizeof tmp, "%u %ju", digest, length); |
| TEST_ASSERT_TRUE(n1 >= 0); |
|
|
| size_t file_len = (args && file) ? strlen(file) : 0; |
| size_t total = (size_t)n1 + (args ? 1 + file_len : 0) + 1; |
|
|
| char *out = (char *)malloc(total + 1); |
| TEST_ASSERT_NOT_NULL(out); |
|
|
| size_t off = 0; |
| int nw = snprintf(out + off, total + 1 - off, "%u %ju", digest, length); |
| TEST_ASSERT_TRUE(nw >= 0); |
| off += (size_t)nw; |
|
|
| if (args) { |
| out[off++] = ' '; |
| if (file_len) { |
| memcpy(out + off, file, file_len); |
| off += file_len; |
| } |
| } |
|
|
| out[off++] = (char)delim; |
| out[off] = '\0'; |
|
|
| return out; |
| } |
|
|
| |
|
|
| static void test_output_crc_raw_mode_big_endian_bytes_internal(void) { |
| uint32_t digest = 0x12345678u; |
| bool raw = true; |
| bool args = false; |
| unsigned char delim = '\n'; |
| uintmax_t length = 0; |
|
|
| start_capture(); |
| output_crc("ignored", 0, &digest, raw, false, delim, args, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| |
| TEST_ASSERT_EQUAL_size_t(4, out_sz); |
| uint32_t expected_be = htobe32(digest); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[0], (unsigned char)out[0]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[1], (unsigned char)out[1]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[2], (unsigned char)out[2]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[3], (unsigned char)out[3]); |
|
|
| free(out); |
| } |
|
|
| void test_output_crc_raw_mode_big_endian_bytes(void) { |
| test_output_crc_raw_mode_big_endian_bytes_internal(); |
| } |
|
|
| void test_output_crc_text_no_args_newline(void) { |
| unsigned int digest = 42u; |
| uintmax_t length = 0; |
| unsigned char delim = '\n'; |
| bool args = false; |
|
|
| char *expected = build_expected_text(digest, length, NULL, delim, args); |
|
|
| start_capture(); |
| output_crc(NULL, 0, &digest, false, false, delim, args, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| TEST_ASSERT_EQUAL_STRING_LEN(expected, out, strlen(expected)); |
| TEST_ASSERT_EQUAL_size_t(strlen(expected), out_sz); |
|
|
| free(expected); |
| free(out); |
| } |
|
|
| void test_output_crc_text_with_args_and_space_delim(void) { |
| unsigned int digest = 0x12345678u; |
| uintmax_t length = 99; |
| const char *file = "myfile.txt"; |
| unsigned char delim = ' '; |
| bool args = true; |
|
|
| char *expected = build_expected_text(digest, length, file, delim, args); |
|
|
| start_capture(); |
| output_crc(file, 0, &digest, false, false, delim, args, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| TEST_ASSERT_EQUAL_STRING_LEN(expected, out, strlen(expected)); |
| TEST_ASSERT_EQUAL_size_t(strlen(expected), out_sz); |
|
|
| free(expected); |
| free(out); |
| } |
|
|
| void test_output_crc_large_length_uses_uintmax(void) { |
| unsigned int digest = 7u; |
| uintmax_t length = UINTMAX_MAX; |
| unsigned char delim = '\n'; |
| bool args = false; |
|
|
| char *expected = build_expected_text(digest, length, NULL, delim, args); |
|
|
| start_capture(); |
| output_crc(NULL, 0, &digest, false, false, delim, args, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| TEST_ASSERT_EQUAL_STRING_LEN(expected, out, strlen(expected)); |
| TEST_ASSERT_EQUAL_size_t(strlen(expected), out_sz); |
|
|
| free(expected); |
| free(out); |
| } |
|
|
| void test_output_crc_null_file_when_args_false(void) { |
| unsigned int digest = 0u; |
| uintmax_t length = 12345; |
| unsigned char delim = '.'; |
| bool args = false; |
|
|
| char *expected = build_expected_text(digest, length, NULL, delim, args); |
|
|
| start_capture(); |
| output_crc(NULL, 0, &digest, false, false, delim, args, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| TEST_ASSERT_EQUAL_STRING_LEN(expected, out, strlen(expected)); |
| TEST_ASSERT_EQUAL_size_t(strlen(expected), out_sz); |
|
|
| free(expected); |
| free(out); |
| } |
|
|
| void test_output_crc_raw_ignores_args_and_delim(void) { |
| uint32_t digest = 0x89ABCDEFu; |
| uintmax_t length = 123456; |
| const char *file = "ignored.txt"; |
|
|
| start_capture(); |
| output_crc(file, 0, &digest, true, false, '\n', true, length); |
| size_t out_sz = 0; |
| char *out = stop_capture(&out_sz); |
|
|
| |
| TEST_ASSERT_EQUAL_size_t(4, out_sz); |
| uint32_t expected_be = htobe32(digest); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[0], (unsigned char)out[0]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[1], (unsigned char)out[1]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[2], (unsigned char)out[2]); |
| TEST_ASSERT_EQUAL_UINT8(((unsigned char *)&expected_be)[3], (unsigned char)out[3]); |
|
|
| free(out); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
|
|
| RUN_TEST(test_output_crc_raw_mode_big_endian_bytes); |
| RUN_TEST(test_output_crc_text_no_args_newline); |
| RUN_TEST(test_output_crc_text_with_args_and_space_delim); |
| RUN_TEST(test_output_crc_large_length_uses_uintmax); |
| RUN_TEST(test_output_crc_null_file_when_args_false); |
| RUN_TEST(test_output_crc_raw_ignores_args_and_delim); |
|
|
| return UNITY_END(); |
| } |