|
|
#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> |
|
|
#include <sys/types.h> |
|
|
#include <sys/stat.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern FILE *in_stream; |
|
|
extern char const *const *file_list; |
|
|
extern char const *input_filename; |
|
|
extern bool have_read_stdin; |
|
|
extern intmax_t end_offset; |
|
|
extern bool flag_dump_strings; |
|
|
|
|
|
|
|
|
extern bool open_next_file (void); |
|
|
extern bool check_and_close (int in_errno); |
|
|
extern bool skip (intmax_t n_skip); |
|
|
|
|
|
|
|
|
static char *create_temp_file_with_size(size_t size) { |
|
|
char tmpl[] = "/tmp/od_skip_testXXXXXX"; |
|
|
int fd = mkstemp(tmpl); |
|
|
if (fd < 0) { |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
size_t remaining = size; |
|
|
char buf[4096]; |
|
|
memset(buf, 'A', sizeof(buf)); |
|
|
|
|
|
while (remaining > 0) { |
|
|
size_t chunk = remaining < sizeof(buf) ? remaining : sizeof(buf); |
|
|
ssize_t w = write(fd, buf, chunk); |
|
|
if (w < 0) { |
|
|
int e = errno; |
|
|
close(fd); |
|
|
unlink(tmpl); |
|
|
errno = e; |
|
|
return NULL; |
|
|
} |
|
|
remaining -= (size_t)w; |
|
|
} |
|
|
|
|
|
if (fsync(fd) != 0) { |
|
|
|
|
|
} |
|
|
|
|
|
if (close(fd) != 0) { |
|
|
unlink(tmpl); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
char *path = strdup(tmpl); |
|
|
return path; |
|
|
} |
|
|
|
|
|
static long current_offset(FILE *f) { |
|
|
off_t off = ftello(f); |
|
|
if (off == (off_t)-1) return -1; |
|
|
return (long)off; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
in_stream = NULL; |
|
|
have_read_stdin = false; |
|
|
end_offset = -1; |
|
|
flag_dump_strings = false; |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
|
|
|
|
|
|
if (in_stream) { |
|
|
check_and_close(0); |
|
|
in_stream = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void test_skip_zero_no_stream(void) { |
|
|
in_stream = NULL; |
|
|
bool ok = skip(0); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NULL(in_stream); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_skip_within_single_file_seek(void) { |
|
|
char *p1 = create_temp_file_with_size(100000); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(p1, "failed to create temp file"); |
|
|
|
|
|
|
|
|
const char *flist[] = { p1, NULL }; |
|
|
file_list = flist; |
|
|
|
|
|
bool ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream)); |
|
|
|
|
|
ok = skip(12345); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(12345, current_offset(in_stream)); |
|
|
|
|
|
|
|
|
check_and_close(0); |
|
|
|
|
|
unlink(p1); |
|
|
free(p1); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void test_skip_across_two_files_boundary_seek_on_first(void) { |
|
|
char *p1 = create_temp_file_with_size(5000); |
|
|
char *p2 = create_temp_file_with_size(2000); |
|
|
TEST_ASSERT_NOT_NULL(p1); |
|
|
TEST_ASSERT_NOT_NULL(p2); |
|
|
|
|
|
const char *flist[] = { p1, p2, NULL }; |
|
|
file_list = flist; |
|
|
|
|
|
bool ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream)); |
|
|
|
|
|
|
|
|
ok = skip(5200); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
|
|
|
|
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
long off = current_offset(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(200, off); |
|
|
|
|
|
|
|
|
check_and_close(0); |
|
|
unlink(p1); unlink(p2); |
|
|
free(p1); free(p2); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void test_skip_read_based_small_file(void) { |
|
|
char *p1 = create_temp_file_with_size(10); |
|
|
TEST_ASSERT_NOT_NULL(p1); |
|
|
|
|
|
const char *flist[] = { p1, NULL }; |
|
|
file_list = flist; |
|
|
|
|
|
bool ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(0, current_offset(in_stream)); |
|
|
|
|
|
ok = skip(6); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_EQUAL_INT(6, current_offset(in_stream)); |
|
|
|
|
|
|
|
|
check_and_close(0); |
|
|
unlink(p1); |
|
|
free(p1); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void test_skip_exact_file_size_stays_on_first_at_eof(void) { |
|
|
char *p1 = create_temp_file_with_size(1000); |
|
|
char *p2 = create_temp_file_with_size(100); |
|
|
TEST_ASSERT_NOT_NULL(p1); |
|
|
TEST_ASSERT_NOT_NULL(p2); |
|
|
|
|
|
const char *flist[] = { p1, p2, NULL }; |
|
|
file_list = flist; |
|
|
|
|
|
bool ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
|
|
|
ok = skip(1000); |
|
|
TEST_ASSERT_TRUE(ok); |
|
|
|
|
|
|
|
|
TEST_ASSERT_NOT_NULL(in_stream); |
|
|
TEST_ASSERT_EQUAL_INT(1000, current_offset(in_stream)); |
|
|
|
|
|
|
|
|
check_and_close(0); |
|
|
unlink(p1); unlink(p2); |
|
|
free(p1); free(p2); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
|
|
|
RUN_TEST(test_skip_zero_no_stream); |
|
|
RUN_TEST(test_skip_within_single_file_seek); |
|
|
RUN_TEST(test_skip_across_two_files_boundary_seek_on_first); |
|
|
RUN_TEST(test_skip_read_based_small_file); |
|
|
RUN_TEST(test_skip_exact_file_size_stays_on_first_at_eof); |
|
|
|
|
|
return UNITY_END(); |
|
|
} |