coreutils / tests /od /tests_for_read_char.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 <unistd.h>
#include <fcntl.h>
#include <errno.h>
/* The test file is included into the od translation unit, so it has
access to the internal functions and globals declared above, such as:
- static bool read_char (int *c);
- static bool open_next_file (void);
- static bool check_and_close (int in_errno);
- static FILE *in_stream;
- static char const *const *file_list; */
/* Helper: create a temporary file with the specified content. Returns a
malloc-allocated string containing the path which the caller must free. */
static char *make_tempfile_with_content(const char *content)
{
char tmpl[] = "/tmp/od_read_char_test_XXXXXX";
int fd = mkstemp(tmpl);
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp failed");
if (content && content[0] != '\0') {
size_t len = strlen(content);
ssize_t wr = write(fd, content, len);
TEST_ASSERT_EQUAL_INT_MESSAGE((int)len, (int)wr, "write failed");
}
close(fd);
char *path = (char *)malloc(strlen(tmpl) + 1);
TEST_ASSERT_NOT_NULL(path);
strcpy(path, tmpl);
return path;
}
/* Helper: close stream if open and reset pointer. */
static void close_stream_if_open(void)
{
if (in_stream != NULL) {
/* Pass 0 so check_and_close checks ferror itself */
(void)check_and_close(0);
}
}
void setUp(void) {
/* Ensure a clean slate before each test */
close_stream_if_open();
/* Reset file_list to a benign state (no files). We use a static
local array here to avoid lifetime issues. */
static const char *empty_list[] = { NULL };
file_list = empty_list;
}
void tearDown(void) {
/* Close any stream that may still be open */
close_stream_if_open();
}
/* Test: basic single byte read from a file. */
void test_read_char_single_byte(void)
{
char *p = make_tempfile_with_content("Z");
const char *flist[] = { p, NULL };
file_list = flist;
/* Open first (and only) file via program helper to set globals consistently */
TEST_ASSERT_TRUE(open_next_file());
int ch = 0;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('Z', ch);
/* Cleanup */
close_stream_if_open();
unlink(p);
free(p);
}
/* Test: sequential reads across multiple bytes without hitting EOF in read_char. */
void test_read_char_three_bytes(void)
{
char *p = make_tempfile_with_content("ABC");
const char *flist[] = { p, NULL };
file_list = flist;
TEST_ASSERT_TRUE(open_next_file());
int ch = 0;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('A', ch);
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('B', ch);
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('C', ch);
/* Do not call a 4th time to avoid transitioning to EOF here. */
close_stream_if_open();
unlink(p);
free(p);
}
/* Test: handle EOF on an empty file with no next file. Should return true and set *c = EOF. */
void test_read_char_eof_no_next_file(void)
{
char *p = make_tempfile_with_content("");
const char *flist[] = { p, NULL };
file_list = flist;
TEST_ASSERT_TRUE(open_next_file());
int ch = 123; /* init to non-EOF */
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT(EOF, ch);
/* Subsequent call with in_stream now NULL should also yield EOF and true. */
ch = 456;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT(EOF, ch);
close_stream_if_open();
unlink(p);
free(p);
}
/* Test: transition across two files: first has 'A', second has 'B'. */
void test_read_char_transition_to_next_file(void)
{
char *p1 = make_tempfile_with_content("A");
char *p2 = make_tempfile_with_content("B");
const char *flist[] = { p1, p2, NULL };
file_list = flist;
TEST_ASSERT_TRUE(open_next_file());
int ch = 0;
/* Read from first file */
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('A', ch);
/* Next call should hit EOF on first, advance to second, and read 'B' */
ch = 0;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT('B', ch);
/* Third call: both files exhausted -> EOF */
ch = 0;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT(EOF, ch);
close_stream_if_open();
unlink(p1);
unlink(p2);
free(p1);
free(p2);
}
/* Test: when in_stream is initially NULL (no file opened), read_char should return true and EOF. */
void test_read_char_with_null_stream(void)
{
/* Ensure no open stream and no files */
close_stream_if_open();
static const char *empty_list[] = { NULL };
file_list = empty_list;
int ch = 0;
TEST_ASSERT_TRUE(read_char(&ch));
TEST_ASSERT_EQUAL_INT(EOF, ch);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_read_char_single_byte);
RUN_TEST(test_read_char_three_bytes);
RUN_TEST(test_read_char_eof_no_next_file);
RUN_TEST(test_read_char_transition_to_next_file);
RUN_TEST(test_read_char_with_null_stream);
return UNITY_END();
}