|
|
#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(); |
|
|
} |