| #include "../../unity/unity.h" |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/wait.h> |
| #include <time.h> |
|
|
| |
|
|
| static void fill_pattern(char *buf, size_t len, size_t start_index) |
| { |
| for (size_t i = 0; i < len; i++) |
| buf[i] = (char)('A' + ((start_index + i) % 26)); |
| } |
|
|
| void setUp(void) { |
| |
| } |
|
|
| void tearDown(void) { |
| |
| } |
|
|
| static int mk_tempfile(char *template_buf, size_t template_buf_sz) |
| { |
| |
| const char *tmpl = "/tmp/dd_iread_fullblock_testXXXXXX"; |
| if (strlen(tmpl) + 1 > template_buf_sz) return -1; |
| strcpy(template_buf, tmpl); |
| int fd = mkstemp(template_buf); |
| return fd; |
| } |
|
|
| void test_iread_fullblock_full_read_from_file(void) |
| { |
| char path[128]; |
| int fd = mk_tempfile(path, sizeof(path)); |
| TEST_ASSERT_MESSAGE(fd >= 0, "mkstemp failed"); |
|
|
| |
| const size_t total = 4096; |
| char *src = (char*)malloc(total); |
| TEST_ASSERT_NOT_NULL(src); |
| fill_pattern(src, total, 0); |
|
|
| ssize_t wr = write(fd, src, total); |
| TEST_ASSERT_EQUAL_INT64(total, wr); |
|
|
| |
| lseek(fd, 0, SEEK_SET); |
| char *dst = (char*)malloc(total); |
| TEST_ASSERT_NOT_NULL(dst); |
|
|
| ssize_t rr = iread_fullblock(fd, dst, (idx_t)total); |
|
|
| TEST_ASSERT_EQUAL_INT64((ssize_t)total, rr); |
| TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, total); |
|
|
| free(src); |
| free(dst); |
| close(fd); |
| unlink(path); |
| } |
|
|
| void test_iread_fullblock_aggregates_from_pipe(void) |
| { |
| int pipefd[2]; |
| TEST_ASSERT_EQUAL_INT(0, pipe(pipefd)); |
|
|
| const size_t total = 3000; |
| const size_t chunk1 = 700; |
| const size_t chunk2 = total - chunk1; |
|
|
| fflush(stdout); |
| fflush(stderr); |
| pid_t pid = fork(); |
| TEST_ASSERT_MESSAGE(pid >= 0, "fork failed"); |
|
|
| if (pid == 0) { |
| |
| close(pipefd[0]); |
|
|
| char *buf1 = (char*)malloc(chunk1); |
| char *buf2 = (char*)malloc(chunk2); |
| if (!buf1 || !buf2) _exit(1); |
| fill_pattern(buf1, chunk1, 0); |
| fill_pattern(buf2, chunk2, chunk1); |
|
|
| |
| ssize_t w1 = write(pipefd[1], buf1, chunk1); |
| (void)w1; |
| struct timespec ts = {0, 150 * 1000 * 1000}; |
| nanosleep(&ts, NULL); |
| ssize_t w2 = write(pipefd[1], buf2, chunk2); |
| (void)w2; |
|
|
| free(buf1); |
| free(buf2); |
| close(pipefd[1]); |
| _exit(0); |
| } |
|
|
| |
| close(pipefd[1]); |
|
|
| char *dst = (char*)malloc(total); |
| TEST_ASSERT_NOT_NULL(dst); |
|
|
| ssize_t rr = iread_fullblock(pipefd[0], dst, (idx_t)total); |
| TEST_ASSERT_EQUAL_INT64((ssize_t)total, rr); |
|
|
| |
| char *expect = (char*)malloc(total); |
| TEST_ASSERT_NOT_NULL(expect); |
| fill_pattern(expect, total, 0); |
| TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, dst, total); |
|
|
| free(expect); |
| free(dst); |
| close(pipefd[0]); |
|
|
| int status = 0; |
| waitpid(pid, &status, 0); |
| TEST_ASSERT_TRUE(WIFEXITED(status)); |
| TEST_ASSERT_EQUAL_INT(0, WEXITSTATUS(status)); |
| } |
|
|
| void test_iread_fullblock_eof_before_full(void) |
| { |
| char path[128]; |
| int fd = mk_tempfile(path, sizeof(path)); |
| TEST_ASSERT_MESSAGE(fd >= 0, "mkstemp failed"); |
|
|
| const size_t have = 100; |
| const size_t want = 200; |
|
|
| char *src = (char*)malloc(have); |
| TEST_ASSERT_NOT_NULL(src); |
| fill_pattern(src, have, 0); |
|
|
| TEST_ASSERT_EQUAL_INT64((ssize_t)have, write(fd, src, have)); |
| lseek(fd, 0, SEEK_SET); |
|
|
| char *dst = (char*)malloc(want); |
| TEST_ASSERT_NOT_NULL(dst); |
| memset(dst, 0xCD, want); |
|
|
| ssize_t rr = iread_fullblock(fd, dst, (idx_t)want); |
| TEST_ASSERT_EQUAL_INT64((ssize_t)have, rr); |
| TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, have); |
|
|
| free(src); |
| free(dst); |
| close(fd); |
| unlink(path); |
| } |
|
|
| void test_iread_fullblock_zero_size(void) |
| { |
| |
| int fd = open("/dev/null", O_RDONLY); |
| TEST_ASSERT_MESSAGE(fd >= 0, "open /dev/null failed"); |
|
|
| char dummy; |
| ssize_t rr = iread_fullblock(fd, &dummy, (idx_t)0); |
| TEST_ASSERT_EQUAL_INT64(0, rr); |
|
|
| close(fd); |
| } |
|
|
| void test_iread_fullblock_error_bad_fd(void) |
| { |
| char buf[16]; |
| errno = 0; |
| ssize_t rr = iread_fullblock(-1, buf, (idx_t)sizeof(buf)); |
| TEST_ASSERT_EQUAL_INT64(-1, rr); |
| TEST_ASSERT_EQUAL_INT(EBADF, errno); |
| } |
|
|
| int main(void) |
| { |
| UNITY_BEGIN(); |
| RUN_TEST(test_iread_fullblock_full_read_from_file); |
| RUN_TEST(test_iread_fullblock_aggregates_from_pipe); |
| RUN_TEST(test_iread_fullblock_eof_before_full); |
| RUN_TEST(test_iread_fullblock_zero_size); |
| RUN_TEST(test_iread_fullblock_error_bad_fd); |
| return UNITY_END(); |
| } |