#include "../../unity/unity.h" #include #include #include #include #include #include #include #include /* Unity required hooks */ void setUp(void) { /* No setup needed */ } void tearDown(void) { /* No teardown needed */ } /* Helper: write exactly len bytes to fd */ static void write_exact(int fd, const void *buf, size_t len) { const char *p = (const char *)buf; size_t remaining = len; while (remaining > 0) { ssize_t w = write(fd, p, remaining); TEST_ASSERT_MESSAGE(w >= 0, "write() failed during test setup"); if (w == 0) { TEST_FAIL_MESSAGE("write() returned 0 unexpectedly"); } p += w; remaining -= (size_t)w; } } /* Test: shrinking a regular file succeeds and sets the correct size */ static void test_iftruncate_shrink_file(void) { FILE *fp = tmpfile(); TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); int fd = fileno(fp); TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); /* Create content: 1000 bytes */ char buf[1000]; memset(buf, 'A', sizeof buf); write_exact(fd, buf, sizeof buf); /* Shrink to 100 bytes */ errno = 0; int rc = iftruncate(fd, (off_t)100); TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "iftruncate should succeed when shrinking"); struct stat st; int s = fstat(fd, &st); TEST_ASSERT_EQUAL_INT_MESSAGE(0, s, "fstat failed after shrinking"); TEST_ASSERT_EQUAL_INT64_MESSAGE((long long)100, (long long)st.st_size, "File size after shrink is incorrect"); /* Cleanup */ fclose(fp); } /* Test: extending a regular file succeeds, sets size, and zeros new bytes */ static void test_iftruncate_extend_file_zero_filled(void) { FILE *fp = tmpfile(); TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); int fd = fileno(fp); TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); /* Ensure file initially empty */ struct stat st0; TEST_ASSERT_EQUAL_INT(0, fstat(fd, &st0)); /* Extend to 4096 bytes */ errno = 0; int rc = iftruncate(fd, (off_t)4096); TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "iftruncate should succeed when extending"); struct stat st; int s = fstat(fd, &st); TEST_ASSERT_EQUAL_INT_MESSAGE(0, s, "fstat failed after extending"); TEST_ASSERT_EQUAL_INT64_MESSAGE((long long)4096, (long long)st.st_size, "File size after extend is incorrect"); /* Read the last byte; should be zero */ off_t r = lseek(fd, (off_t)4095, SEEK_SET); TEST_ASSERT_TRUE_MESSAGE(r == (off_t)4095, "lseek to last byte failed"); unsigned char c = 0xFF; ssize_t rr = read(fd, &c, 1); TEST_ASSERT_EQUAL_INT_MESSAGE(1, rr, "read of last byte failed"); TEST_ASSERT_EQUAL_UINT8_MESSAGE(0, c, "Extended area is not zero-filled"); /* Cleanup */ fclose(fp); } /* Test: invalid file descriptor propagates EBADF and returns -1 */ static void test_iftruncate_invalid_fd(void) { errno = 0; int rc = iftruncate(-1, (off_t)123); TEST_ASSERT_EQUAL_INT_MESSAGE(-1, rc, "iftruncate should fail for invalid fd"); TEST_ASSERT_EQUAL_INT_MESSAGE(EBADF, errno, "errno should be EBADF for invalid fd"); } /* Test: negative length returns EINVAL */ static void test_iftruncate_negative_length(void) { FILE *fp = tmpfile(); TEST_ASSERT_NOT_NULL_MESSAGE(fp, "tmpfile() failed"); int fd = fileno(fp); TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "fileno() failed"); errno = 0; int rc = iftruncate(fd, (off_t)-1); TEST_ASSERT_EQUAL_INT_MESSAGE(-1, rc, "iftruncate should fail for negative length"); TEST_ASSERT_EQUAL_INT_MESSAGE(EINVAL, errno, "errno should be EINVAL for negative length"); fclose(fp); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_iftruncate_shrink_file); RUN_TEST(test_iftruncate_extend_file_zero_filled); RUN_TEST(test_iftruncate_invalid_fd); RUN_TEST(test_iftruncate_negative_length); return UNITY_END(); }