File size: 5,246 Bytes
78d2150 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
/* 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();
} |