|
|
#include "../../unity/unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <stdbool.h> |
|
|
#include <errno.h> |
|
|
#include <unistd.h> |
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool dump_strings(void); |
|
|
static bool open_next_file(void); |
|
|
|
|
|
|
|
|
extern int address_base; |
|
|
extern int address_pad_len; |
|
|
extern bool flag_dump_strings; |
|
|
extern intmax_t n_bytes_to_skip; |
|
|
extern intmax_t end_offset; |
|
|
extern idx_t string_min; |
|
|
extern FILE *in_stream; |
|
|
extern char const *const *file_list; |
|
|
extern void (*format_address)(intmax_t, char); |
|
|
static void format_address_std (intmax_t, char); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *testutil_make_temp_file(const unsigned char *data, size_t len) |
|
|
{ |
|
|
char tmpl[] = "od_test_XXXXXX"; |
|
|
int fd = mkstemp(tmpl); |
|
|
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp failed"); |
|
|
|
|
|
ssize_t written = 0; |
|
|
while ((size_t)written < len) { |
|
|
ssize_t w = write(fd, data + written, len - written); |
|
|
TEST_ASSERT_TRUE_MESSAGE(w >= 0, "write failed"); |
|
|
written += w; |
|
|
} |
|
|
int rc = close(fd); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, rc, "close temp file failed"); |
|
|
|
|
|
|
|
|
char *ret = (char *)malloc(strlen(tmpl) + 1); |
|
|
TEST_ASSERT_NOT_NULL(ret); |
|
|
strcpy(ret, tmpl); |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
static const char **testutil_build_file_list(char **paths, size_t n) |
|
|
{ |
|
|
const char **list = (const char **)malloc((n + 1) * sizeof(*list)); |
|
|
TEST_ASSERT_NOT_NULL(list); |
|
|
for (size_t i = 0; i < n; i++) list[i] = paths[i]; |
|
|
list[n] = NULL; |
|
|
return list; |
|
|
} |
|
|
|
|
|
|
|
|
static char *testutil_capture_dump_strings(bool *ok_out) |
|
|
{ |
|
|
|
|
|
int saved_fd = dup(fileno(stdout)); |
|
|
TEST_ASSERT_TRUE_MESSAGE(saved_fd >= 0, "dup(stdout) failed"); |
|
|
|
|
|
FILE *cap = tmpfile(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(cap, "tmpfile failed"); |
|
|
|
|
|
int cap_fd = fileno(cap); |
|
|
TEST_ASSERT_TRUE_MESSAGE(cap_fd >= 0, "fileno(tmpfile) failed"); |
|
|
|
|
|
fflush(stdout); |
|
|
int rc = dup2(cap_fd, fileno(stdout)); |
|
|
TEST_ASSERT_TRUE_MESSAGE(rc >= 0, "dup2 to stdout failed"); |
|
|
|
|
|
|
|
|
bool ok = dump_strings(); |
|
|
|
|
|
fflush(stdout); |
|
|
|
|
|
rc = dup2(saved_fd, fileno(stdout)); |
|
|
TEST_ASSERT_TRUE_MESSAGE(rc >= 0, "restore stdout failed"); |
|
|
close(saved_fd); |
|
|
|
|
|
|
|
|
long sz; |
|
|
int fseek_rc = fseek(cap, 0, SEEK_END); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fseek_rc, "fseek end failed"); |
|
|
sz = ftell(cap); |
|
|
TEST_ASSERT_TRUE_MESSAGE(sz >= 0, "ftell failed"); |
|
|
fseek_rc = fseek(cap, 0, SEEK_SET); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fseek_rc, "fseek set failed"); |
|
|
|
|
|
char *buf = (char *)malloc((size_t)sz + 1); |
|
|
TEST_ASSERT_NOT_NULL(buf); |
|
|
size_t rd = fread(buf, 1, (size_t)sz, cap); |
|
|
TEST_ASSERT_EQUAL_UINT_MESSAGE((size_t)sz, rd, "fread captured output failed"); |
|
|
buf[sz] = '\0'; |
|
|
|
|
|
fclose(cap); |
|
|
|
|
|
if (ok_out) *ok_out = ok; |
|
|
return buf; |
|
|
} |
|
|
|
|
|
|
|
|
void setUp(void) |
|
|
{ |
|
|
|
|
|
in_stream = NULL; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = -1; |
|
|
string_min = 0; |
|
|
flag_dump_strings = true; |
|
|
address_base = 8; |
|
|
address_pad_len = 7; |
|
|
format_address = format_address_std; |
|
|
} |
|
|
|
|
|
void tearDown(void) |
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void test_dump_strings_basic_nul_terminated(void) |
|
|
{ |
|
|
const unsigned char data[] = { 'a','b','c','\0' }; |
|
|
char *path = testutil_make_temp_file(data, sizeof data); |
|
|
|
|
|
char *paths_arr[] = { path }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 1); |
|
|
file_list = list; |
|
|
|
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = -1; |
|
|
|
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("0000000 abc\n", out); |
|
|
|
|
|
|
|
|
free(out); |
|
|
unlink(path); |
|
|
free(path); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
|
|
|
void test_dump_strings_minlen_not_met(void) |
|
|
{ |
|
|
const unsigned char data[] = { 'a','b','\0' }; |
|
|
char *path = testutil_make_temp_file(data, sizeof data); |
|
|
|
|
|
char *paths_arr[] = { path }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 1); |
|
|
file_list = list; |
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = -1; |
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("", out); |
|
|
|
|
|
free(out); |
|
|
unlink(path); |
|
|
free(path); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
|
|
|
void test_dump_strings_end_offset_termination(void) |
|
|
{ |
|
|
const unsigned char data[] = { 'a','b','c','d','e','f' }; |
|
|
char *path = testutil_make_temp_file(data, sizeof data); |
|
|
|
|
|
char *paths_arr[] = { path }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 1); |
|
|
file_list = list; |
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = 6; |
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("0000000 abcdef\n", out); |
|
|
|
|
|
free(out); |
|
|
unlink(path); |
|
|
free(path); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
|
|
|
void test_dump_strings_start_offset_address(void) |
|
|
{ |
|
|
const unsigned char data[] = { 'a','b','c','\0' }; |
|
|
char *path = testutil_make_temp_file(data, sizeof data); |
|
|
|
|
|
char *paths_arr[] = { path }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 1); |
|
|
file_list = list; |
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 2; |
|
|
end_offset = -1; |
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("0000002 abc\n", out); |
|
|
|
|
|
free(out); |
|
|
unlink(path); |
|
|
free(path); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
|
|
|
void test_dump_strings_across_files(void) |
|
|
{ |
|
|
const unsigned char data1[] = { 'h','e','l','l','o' }; |
|
|
const unsigned char data2[] = { '\0' }; |
|
|
char *path1 = testutil_make_temp_file(data1, sizeof data1); |
|
|
char *path2 = testutil_make_temp_file(data2, sizeof data2); |
|
|
|
|
|
char *paths_arr[] = { path1, path2 }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 2); |
|
|
file_list = list; |
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = -1; |
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("0000000 hello\n", out); |
|
|
|
|
|
free(out); |
|
|
unlink(path1); |
|
|
unlink(path2); |
|
|
free(path1); |
|
|
free(path2); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
|
|
|
void test_dump_strings_multiple_strings(void) |
|
|
{ |
|
|
const unsigned char data[] = { 'a','b','c','\0', 'x','y','z','\0' }; |
|
|
char *path = testutil_make_temp_file(data, sizeof data); |
|
|
|
|
|
char *paths_arr[] = { path }; |
|
|
const char **list = testutil_build_file_list(paths_arr, 1); |
|
|
file_list = list; |
|
|
|
|
|
string_min = 3; |
|
|
n_bytes_to_skip = 0; |
|
|
end_offset = -1; |
|
|
|
|
|
bool open_ok = open_next_file(); |
|
|
TEST_ASSERT_TRUE(open_ok); |
|
|
|
|
|
bool ok = false; |
|
|
char *out = testutil_capture_dump_strings(&ok); |
|
|
|
|
|
TEST_ASSERT_TRUE(ok); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("0000000 abc\n0000004 xyz\n", out); |
|
|
|
|
|
free(out); |
|
|
unlink(path); |
|
|
free(path); |
|
|
free((void*)list); |
|
|
} |
|
|
|
|
|
int main(void) |
|
|
{ |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_dump_strings_basic_nul_terminated); |
|
|
RUN_TEST(test_dump_strings_minlen_not_met); |
|
|
RUN_TEST(test_dump_strings_end_offset_termination); |
|
|
RUN_TEST(test_dump_strings_start_offset_address); |
|
|
RUN_TEST(test_dump_strings_across_files); |
|
|
RUN_TEST(test_dump_strings_multiple_strings); |
|
|
return UNITY_END(); |
|
|
} |