#include "../../unity/unity.h" #include #include #include #include #include #include /* Test-helper state */ static FILE *test_last_stream_seen = NULL; static int test_callback_invoked = 0; static size_t test_bytes_read = 0; /* Prototypes of target under test are available since this file is included into the same translation unit as cut_file. We can call cut_file directly. */ /* Helper: create a temporary file with the given content, return malloc'ed path. */ static char *make_temp_file_with_content(const char *content) { char tmp_template[] = "/tmp/cut_ut_XXXXXX"; int fd = mkstemp(tmp_template); TEST_ASSERT_MESSAGE(fd >= 0, "mkstemp failed"); size_t len = strlen(content); if (len > 0) { ssize_t w = write(fd, content, len); TEST_ASSERT_MESSAGE(w == (ssize_t)len, "write failed to write all content"); } int rc = close(fd); TEST_ASSERT_MESSAGE(rc == 0, "close(temp file) failed"); /* Return a heap-allocated copy of the path so caller can free it. */ char *path = (char *)malloc(strlen(tmp_template) + 1); TEST_ASSERT_NOT_NULL(path); strcpy(path, tmp_template); return path; } /* Helper: reopen stdin from given path. */ static void reopen_stdin_from_path(const char *path) { FILE *f = freopen(path, "r", stdin); TEST_ASSERT_MESSAGE(f != NULL, "freopen on stdin failed"); } /* cut_stream callback that reads all bytes from the given stream */ static void test_cut_stream_read_all(FILE *s) { test_callback_invoked++; test_last_stream_seen = s; test_bytes_read = 0; int ch; while ((ch = getc(s)) != EOF) { test_bytes_read++; } } /* cut_stream callback that does nothing */ static void test_cut_stream_noop(FILE *s) { (void)s; test_callback_invoked++; test_last_stream_seen = s; } /* Unity fixtures */ void setUp(void) { test_last_stream_seen = NULL; test_callback_invoked = 0; test_bytes_read = 0; errno = 0; /* Reset the program's internal flag before each test. */ /* have_read_stdin is defined in the production code above, static at file scope. Since this test is included in the same translation unit, we can access it. */ extern bool have_read_stdin; /* forward declaration to appease some compilers */ have_read_stdin = false; /* Ensure stdin has no error/eof flags set */ clearerr(stdin); } void tearDown(void) { /* Nothing special */ } /* Test: Using "-" uses stdin, sets have_read_stdin, invokes callback, and clears EOF */ static void test_cut_file_stdin_reads_and_clears_eof(void) { /* Prepare stdin with some data */ char *p = make_temp_file_with_content("ABC"); reopen_stdin_from_path(p); extern bool have_read_stdin; bool ok = cut_file("-", test_cut_stream_read_all); TEST_ASSERT_TRUE(ok); TEST_ASSERT_TRUE(have_read_stdin); TEST_ASSERT_EQUAL_INT(1, test_callback_invoked); TEST_ASSERT_EQUAL_PTR(stdin, test_last_stream_seen); TEST_ASSERT_EQUAL_UINT32(3u, (unsigned) test_bytes_read); /* Because cut_file clears errors and EOF on stdin, feof(stdin) must be false */ TEST_ASSERT_FALSE(feof(stdin)); free(p); } /* Test: Regular file path is opened, callback sees that FILE*, and success is returned */ static void test_cut_file_regular_file_success(void) { char *p = make_temp_file_with_content("xyz123"); extern bool have_read_stdin; bool ok = cut_file(p, test_cut_stream_read_all); TEST_ASSERT_TRUE(ok); TEST_ASSERT_FALSE(have_read_stdin); TEST_ASSERT_EQUAL_INT(1, test_callback_invoked); TEST_ASSERT_NOT_NULL(test_last_stream_seen); /* For a regular file, cut_file opens its own stream, which must not be stdin */ TEST_ASSERT_NOT_EQUAL_PTR(stdin, test_last_stream_seen); TEST_ASSERT_EQUAL_UINT32(6u, (unsigned) test_bytes_read); /* Clean up the temporary file */ int rc = unlink(p); (void)rc; /* Ignore unlink failure on platforms that restrict deleting open files */ free(p); } /* Test: Nonexistent file returns false and does not invoke the callback */ static void test_cut_file_nonexistent_returns_false(void) { const char *nonexistent = "/tmp/cut_ut_no_such_file____XXXX"; extern bool have_read_stdin; bool ok = cut_file(nonexistent, test_cut_stream_noop); TEST_ASSERT_FALSE(ok); TEST_ASSERT_EQUAL_INT(0, test_callback_invoked); TEST_ASSERT_FALSE(have_read_stdin); } /* Test: Using "-" without reading still sets have_read_stdin and returns true */ static void test_cut_file_stdin_no_read_sets_flag(void) { /* Prepare stdin with empty file */ char *p = make_temp_file_with_content(""); reopen_stdin_from_path(p); extern bool have_read_stdin; bool ok = cut_file("-", test_cut_stream_noop); TEST_ASSERT_TRUE(ok); TEST_ASSERT_TRUE(have_read_stdin); TEST_ASSERT_EQUAL_INT(1, test_callback_invoked); TEST_ASSERT_EQUAL_PTR(stdin, test_last_stream_seen); /* No read was performed, but also no EOF should be set after clearerr */ TEST_ASSERT_FALSE(feof(stdin)); free(p); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_cut_file_stdin_reads_and_clears_eof); RUN_TEST(test_cut_file_regular_file_success); RUN_TEST(test_cut_file_nonexistent_returns_false); RUN_TEST(test_cut_file_stdin_no_read_sets_flag); return UNITY_END(); }