coreutils / tests /cksum /tests_for_output_crc.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#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>
/* Function under test is available from the included program:
void output_crc (char const *file, int binary_file,
void const *digest, bool raw, bool tagged,
unsigned char delim, bool args, uintmax_t length);
*/
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* stdout capture helpers. Avoid Unity assertions after redirecting stdout. */
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 the file so it is removed when closed, but remains accessible via fd */
unlink(tmpl);
int r = dup2(capture_fd, fileno(stdout));
if (r == -1) {
int err = errno;
/* We haven't redirected stdout (dup2 failed), so it's safe to assert here. */
close(capture_fd);
capture_fd = -1;
TEST_FAIL_MESSAGE("dup2 to redirect stdout failed");
}
}
static char *stop_capture(size_t *out_size) {
/* Flush any buffered data before restoring stdout */
fflush(stdout);
int r = dup2(saved_stdout_fd, fileno(stdout));
int saved_err = errno;
close(saved_stdout_fd);
saved_stdout_fd = -1;
/* Now stdout should be restored; it's safe to use Unity asserts. */
TEST_ASSERT_MESSAGE(r != -1, "dup2 restoring stdout failed");
/* Determine the size and read the captured data */
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); /* +1 for convenience in text tests */
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);
/* Null-terminate for convenience (even for raw, this doesn't affect comparisons when using size) */
buf[alloc_sz] = '\0';
close(capture_fd);
capture_fd = -1;
if (out_size) *out_size = (size_t)alloc_sz;
return buf;
}
/* Helper to build expected text output mirroring output_crc's formatting */
static char *build_expected_text(unsigned int digest, uintmax_t length,
const char *file, unsigned char delim, bool args)
{
/* Compute needed size */
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; /* +1 for delim */
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;
}
/* Tests */
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'; /* should be ignored in raw mode */
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);
/* Expect exactly 4 bytes in network order */
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; /* 305419896 */
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);
/* Expect exactly 4 bytes, no additional text regardless of args/delim */
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();
}