coreutils / tests /od /tests_for_skip.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 <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
/* The test file is included into the od source, so we can access
the internal globals and functions directly. We declare externs only
for clarity; they are defined above in the included program. */
/* Globals from od.c (visible since this test is included into the TU) */
extern FILE *in_stream;
extern char const *const *file_list;
extern char const *input_filename;
extern bool have_read_stdin;
extern intmax_t end_offset;
extern bool flag_dump_strings;
/* Functions from od.c */
extern bool open_next_file (void);
extern bool check_and_close (int in_errno);
extern bool skip (intmax_t n_skip);
/* Helpers for tests */
static char *create_temp_file_with_size(size_t size) {
char tmpl[] = "/tmp/od_skip_testXXXXXX";
int fd = mkstemp(tmpl);
if (fd < 0) {
return NULL;
}
/* Write 'size' bytes of predictable data */
size_t remaining = size;
char buf[4096];
memset(buf, 'A', sizeof(buf));
while (remaining > 0) {
size_t chunk = remaining < sizeof(buf) ? remaining : sizeof(buf);
ssize_t w = write(fd, buf, chunk);
if (w < 0) {
int e = errno;
close(fd);
unlink(tmpl);
errno = e;
return NULL;
}
remaining -= (size_t)w;
}
if (fsync(fd) != 0) {
/* Not fatal for tests, continue */
}
if (close(fd) != 0) {
unlink(tmpl);
return NULL;
}
/* Return a heap-allocated copy of the path so caller can free */
char *path = strdup(tmpl);
return path;
}
static long current_offset(FILE *f) {
off_t off = ftello(f);
if (off == (off_t)-1) return -1;
return (long)off;
}
void setUp(void) {
/* Reset core globals to a safe baseline for each test. */
in_stream = NULL;
have_read_stdin = false;
end_offset = -1; /* No end limit */
flag_dump_strings = false;
}
void tearDown(void) {
/* If a stream is still open, close it safely. Note: in tests, we
prefer to close via check_and_close within each test before
local arrays (for file_list) go out of scope. */
if (in_stream) {
check_and_close(0);
in_stream = NULL;
}
}
/* Test: n_skip == 0 is a no-op and returns true, without requiring an open stream. */
static void test_skip_zero_no_stream(void) {
in_stream = NULL;
bool ok = skip(0);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NULL(in_stream);
}
/* Test: Skip within a single large file using seek optimization. */
static void test_skip_within_single_file_seek(void) {
char *p1 = create_temp_file_with_size(100000); /* large to trigger seek path */
TEST_ASSERT_NOT_NULL_MESSAGE(p1, "failed to create temp file");
/* Set up file list and open first file */
const char *flist[] = { p1, NULL };
file_list = flist;
bool ok = open_next_file();
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(in_stream);
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream));
ok = skip(12345);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(in_stream);
TEST_ASSERT_EQUAL_INT(12345, current_offset(in_stream));
/* Cleanup while file_list is still valid */
check_and_close(0);
unlink(p1);
free(p1);
}
/* Test: Skip across two files, requiring skipping past the entire first file
and partially into the second file. */
static void test_skip_across_two_files_boundary_seek_on_first(void) {
char *p1 = create_temp_file_with_size(5000);
char *p2 = create_temp_file_with_size(2000);
TEST_ASSERT_NOT_NULL(p1);
TEST_ASSERT_NOT_NULL(p2);
const char *flist[] = { p1, p2, NULL };
file_list = flist;
bool ok = open_next_file();
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(in_stream);
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream));
/* Skip more than file1, but less than total */
ok = skip(5200);
TEST_ASSERT_TRUE(ok);
/* Expect to be in the second file at offset 200. */
TEST_ASSERT_NOT_NULL(in_stream);
long off = current_offset(in_stream);
TEST_ASSERT_EQUAL_INT(200, off);
/* Cleanup */
check_and_close(0);
unlink(p1); unlink(p2);
free(p1); free(p2);
}
/* Test: Read-based skipping on a small regular file (size <= block size),
exercising the fread path. */
static void test_skip_read_based_small_file(void) {
char *p1 = create_temp_file_with_size(10);
TEST_ASSERT_NOT_NULL(p1);
const char *flist[] = { p1, NULL };
file_list = flist;
bool ok = open_next_file();
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(in_stream);
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream));
ok = skip(6);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_INT(6, current_offset(in_stream));
/* Cleanup */
check_and_close(0);
unlink(p1);
free(p1);
}
/* Test: Skipping exactly the size of the first file remains at EOF of first file.
The code seeks within the first file and does not immediately open the next. */
static void test_skip_exact_file_size_stays_on_first_at_eof(void) {
char *p1 = create_temp_file_with_size(1000);
char *p2 = create_temp_file_with_size(100);
TEST_ASSERT_NOT_NULL(p1);
TEST_ASSERT_NOT_NULL(p2);
const char *flist[] = { p1, p2, NULL };
file_list = flist;
bool ok = open_next_file();
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_NOT_NULL(in_stream);
ok = skip(1000);
TEST_ASSERT_TRUE(ok);
/* Expect still on first file at offset 1000 (EOF), not yet transitioned */
TEST_ASSERT_NOT_NULL(in_stream);
TEST_ASSERT_EQUAL_INT(1000, current_offset(in_stream));
/* Cleanup */
check_and_close(0);
unlink(p1); unlink(p2);
free(p1); free(p2);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_skip_zero_no_stream);
RUN_TEST(test_skip_within_single_file_seek);
RUN_TEST(test_skip_across_two_files_boundary_seek_on_first);
RUN_TEST(test_skip_read_based_small_file);
RUN_TEST(test_skip_exact_file_size_stays_on_first_at_eof);
return UNITY_END();
}