| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <errno.h> |
|
|
| |
| void setUp(void) { |
| |
| in_stream = NULL; |
| have_read_stdin = false; |
| |
| } |
|
|
| void tearDown(void) { |
| |
| if (in_stream) { |
| check_and_close(0); |
| } |
| } |
|
|
| |
| static char* create_temp_file_with_content(const char* content) { |
| const char* tmpdir = getenv("TMPDIR"); |
| if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; |
|
|
| size_t need = strlen(tmpdir) + 1 + strlen("od_utXXXXXX") + 1; |
| char* tmpl = (char*)malloc(need); |
| TEST_ASSERT_NOT_NULL(tmpl); |
| snprintf(tmpl, need, "%s/%s", tmpdir, "od_utXXXXXX"); |
|
|
| int fd = mkstemp(tmpl); |
| TEST_ASSERT_MESSAGE(fd >= 0, "mkstemp failed creating temporary file"); |
|
|
| ssize_t len = (ssize_t)strlen(content); |
| if (len > 0) { |
| ssize_t w = write(fd, content, (size_t)len); |
| TEST_ASSERT_EQUAL_INT64((int64_t)len, (int64_t)w); |
| } |
| close(fd); |
| return tmpl; |
| } |
|
|
| |
| static void init_stream_and_file_list(const char* path_cur, const char* const* rest) { |
| |
| FILE* f = fopen(path_cur, (O_BINARY ? "rb" : "r")); |
| TEST_ASSERT_NOT_NULL_MESSAGE(f, "Failed to open initial file"); |
| in_stream = f; |
| input_filename = path_cur; |
|
|
| |
| |
| |
| size_t k = 0; |
| if (rest) { |
| while (rest[k] != NULL) k++; |
| } |
| const char** arr = (const char**)malloc((k + 2) * sizeof(const char*)); |
| TEST_ASSERT_NOT_NULL(arr); |
| arr[0] = path_cur; |
| for (size_t i = 0; i < k; i++) arr[i + 1] = rest[i]; |
| arr[k + 1] = NULL; |
|
|
| file_list = arr + 1; |
|
|
| |
| } |
|
|
| |
| static void free_file_list_array(void) { |
| |
| if (file_list) { |
| const char** base = file_list - 1; |
| free((void*)base); |
| file_list = NULL; |
| } |
| } |
|
|
| |
| static void test_read_block_single_file_exact(void) { |
| bytes_per_block = 16; |
|
|
| char* p1 = create_temp_file_with_content("ABCDEFGH"); |
|
|
| const char* rest[] = { NULL }; |
| init_stream_and_file_list(p1, rest); |
|
|
| char buf[16]; |
| memset(buf, 0, sizeof(buf)); |
| idx_t got = 0; |
|
|
| bool ok = read_block(4, buf, &got); |
| TEST_ASSERT_TRUE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)4, (uint64_t)got); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(buf, "ABCD", 4)); |
|
|
| |
| check_and_close(0); |
| free_file_list_array(); |
| unlink(p1); |
| free(p1); |
| } |
|
|
| |
| static void test_read_block_cross_file_boundary(void) { |
| bytes_per_block = 16; |
|
|
| char* p1 = create_temp_file_with_content("ABC"); |
| char* p2 = create_temp_file_with_content("DEFG"); |
|
|
| const char* rest[] = { p2, NULL }; |
| init_stream_and_file_list(p1, rest); |
|
|
| char buf[16]; |
| memset(buf, 0, sizeof(buf)); |
| idx_t got = 0; |
|
|
| |
| bool ok = read_block(5, buf, &got); |
| TEST_ASSERT_TRUE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)5, (uint64_t)got); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(buf, "ABCDE", 5)); |
|
|
| |
| char buf2[8]; |
| memset(buf2, 0, sizeof(buf2)); |
| idx_t got2 = 0; |
| ok = read_block(2, buf2, &got2); |
| TEST_ASSERT_TRUE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)2, (uint64_t)got2); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(buf2, "FG", 2)); |
|
|
| |
| check_and_close(0); |
| free_file_list_array(); |
| unlink(p1); |
| unlink(p2); |
| free(p1); |
| free(p2); |
| } |
|
|
| |
| static void test_read_block_partial_then_eof_then_zero_on_next_call(void) { |
| bytes_per_block = 16; |
|
|
| char* p1 = create_temp_file_with_content("HI"); |
|
|
| const char* rest[] = { NULL }; |
| init_stream_and_file_list(p1, rest); |
|
|
| char buf[16]; |
| memset(buf, 0, sizeof(buf)); |
| idx_t got = 0; |
|
|
| |
| bool ok = read_block(5, buf, &got); |
| TEST_ASSERT_TRUE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)2, (uint64_t)got); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(buf, "HI", 2)); |
|
|
| |
| char buf2[8]; |
| memset(buf2, 0xAA, sizeof(buf2)); |
| idx_t got2 = 0; |
| ok = read_block(3, buf2, &got2); |
| TEST_ASSERT_TRUE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)0, (uint64_t)got2); |
| |
|
|
| |
| |
| check_and_close(0); |
| free_file_list_array(); |
| unlink(p1); |
| free(p1); |
| } |
|
|
| |
| |
| static void test_read_block_next_file_open_failure(void) { |
| bytes_per_block = 16; |
|
|
| char* p1 = create_temp_file_with_content("A"); |
|
|
| |
| const char* bad_path = "/no_such_od_test_file_path_hopefully_123456789"; |
|
|
| const char* rest[] = { bad_path, NULL }; |
| init_stream_and_file_list(p1, rest); |
|
|
| char buf[8]; |
| memset(buf, 0, sizeof(buf)); |
| idx_t got = 0; |
|
|
| |
| bool ok = read_block(2, buf, &got); |
| TEST_ASSERT_FALSE(ok); |
| TEST_ASSERT_EQUAL_UINT64((uint64_t)1, (uint64_t)got); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(buf, "A", 1)); |
|
|
| |
| check_and_close(0); |
| free_file_list_array(); |
| unlink(p1); |
| free(p1); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_read_block_single_file_exact); |
| RUN_TEST(test_read_block_cross_file_boundary); |
| RUN_TEST(test_read_block_partial_then_eof_then_zero_on_next_call); |
| RUN_TEST(test_read_block_next_file_open_failure); |
| return UNITY_END(); |
| } |