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