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