| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <errno.h> |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| extern void write_block (intmax_t current_offset, idx_t n_bytes, |
| char const *prev_block, char const *curr_block); |
| extern void format_address_none (intmax_t, char); |
| extern void print_double (idx_t fields, idx_t blank, void const *data, |
| const char *fmt, int width, idx_t pad); |
|
|
| |
| extern struct tspec *spec; |
| extern idx_t n_specs; |
| extern idx_t n_specs_allocated; |
| extern idx_t bytes_per_block; |
| extern bool abbreviate_duplicate_blocks; |
| extern int address_pad_len; |
| extern void (*format_address) (intmax_t, char); |
|
|
| |
| |
| |
| static void configure_spec_zero_fields(int count) |
| { |
| |
| if (spec) { |
| free(spec); |
| spec = NULL; |
| } |
| n_specs_allocated = 0; |
|
|
| spec = (struct tspec *)calloc((size_t)count, sizeof(*spec)); |
| TEST_ASSERT_NOT_NULL_MESSAGE(spec, "Failed to allocate spec array"); |
| n_specs = (idx_t)count; |
|
|
| for (int i = 0; i < count; i++) { |
| spec[i].fmt = FLOATING_POINT; |
| spec[i].size = FLOAT_DOUBLE; |
| spec[i].print_function = print_double; |
| spec[i].field_width = 0; |
| spec[i].pad_width = 0; |
| spec[i].hexl_mode_trailer = false; |
| spec[i].fmt_string[0] = '\0'; |
| } |
| } |
|
|
| |
| |
| typedef struct { |
| FILE *cap_file; |
| int saved_fd; |
| int cap_fd; |
| int err; |
| } Capture; |
|
|
| static void capture_begin(Capture *c) |
| { |
| memset(c, 0, sizeof(*c)); |
| fflush(stdout); |
| c->cap_file = tmpfile(); |
| if (!c->cap_file) { |
| c->err = errno ? errno : -1; |
| return; |
| } |
| c->cap_fd = fileno(c->cap_file); |
| if (c->cap_fd < 0) { |
| c->err = errno ? errno : -2; |
| return; |
| } |
| c->saved_fd = dup(fileno(stdout)); |
| if (c->saved_fd < 0) { |
| c->err = errno ? errno : -3; |
| return; |
| } |
| if (dup2(c->cap_fd, fileno(stdout)) < 0) { |
| c->err = errno ? errno : -4; |
| |
| (void)dup2(c->saved_fd, fileno(stdout)); |
| return; |
| } |
| } |
|
|
| static char *capture_end(Capture *c) |
| { |
| fflush(stdout); |
| |
| if (c->saved_fd >= 0) |
| (void)dup2(c->saved_fd, fileno(stdout)); |
| if (c->saved_fd >= 0) { |
| close(c->saved_fd); |
| c->saved_fd = -1; |
| } |
|
|
| if (!c->cap_file) { |
| return strdup(""); |
| } |
|
|
| |
| fseek(c->cap_file, 0, SEEK_END); |
| long len = ftell(c->cap_file); |
| if (len < 0) len = 0; |
| fseek(c->cap_file, 0, SEEK_SET); |
|
|
| char *buf = (char *)malloc((size_t)len + 1); |
| if (!buf) { |
| fclose(c->cap_file); |
| return strdup(""); |
| } |
| size_t n = fread(buf, 1, (size_t)len, c->cap_file); |
| buf[n] = '\0'; |
| fclose(c->cap_file); |
| c->cap_file = NULL; |
| return buf; |
| } |
|
|
| void setUp(void) { |
| |
| |
| format_address = format_address_none; |
| address_pad_len = 0; |
| abbreviate_duplicate_blocks = true; |
| bytes_per_block = 4; |
|
|
| |
| |
| configure_spec_zero_fields(1); |
| } |
|
|
| void tearDown(void) { |
| |
| if (spec) { |
| free(spec); |
| spec = NULL; |
| } |
| n_specs = 0; |
| n_specs_allocated = 0; |
|
|
| |
| } |
|
|
| |
| |
| void test_write_block_duplicate_elision_sequence(void) |
| { |
| |
| format_address = format_address_none; |
| address_pad_len = 0; |
| abbreviate_duplicate_blocks = true; |
| bytes_per_block = 4; |
| configure_spec_zero_fields(1); |
|
|
| char A[4] = {1,2,3,4}; |
| char B[4] = {9,8,7,6}; |
|
|
| Capture cap; capture_begin(&cap); |
| |
| write_block(0, 4, A, A); |
| write_block(4, 4, A, A); |
| write_block(8, 4, A, A); |
| write_block(12, 4, A, B); |
| char *out = capture_end(&cap); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, cap.err, "capture_begin failed"); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n*\n\n", out); |
| free(out); |
| } |
|
|
| |
| |
| void test_write_block_no_elision_when_disabled(void) |
| { |
| abbreviate_duplicate_blocks = false; |
| format_address = format_address_none; |
| address_pad_len = 0; |
| bytes_per_block = 4; |
| configure_spec_zero_fields(1); |
|
|
| char A[4] = {1,1,1,1}; |
|
|
| Capture cap; capture_begin(&cap); |
| write_block(0, 4, A, A); |
| write_block(4, 4, A, A); |
| char *out = capture_end(&cap); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, cap.err, "capture_begin failed"); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n\n", out); |
| free(out); |
| } |
|
|
| |
| |
| void test_write_block_no_elision_when_partial_block(void) |
| { |
| abbreviate_duplicate_blocks = true; |
| format_address = format_address_none; |
| address_pad_len = 0; |
| bytes_per_block = 4; |
| configure_spec_zero_fields(1); |
|
|
| char A[4] = {5,5,5,5}; |
|
|
| Capture cap; capture_begin(&cap); |
| write_block(0, 3, A, A); |
| write_block(3, 3, A, A); |
| char *out = capture_end(&cap); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, cap.err, "capture_begin failed"); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n\n", out); |
| free(out); |
| } |
|
|
| |
| |
| |
| void test_write_block_multiple_specs_two_lines(void) |
| { |
| abbreviate_duplicate_blocks = true; |
| format_address = format_address_none; |
| address_pad_len = 0; |
| bytes_per_block = 4; |
| configure_spec_zero_fields(2); |
|
|
| char A[4] = {1,2,3,4}; |
| char B[4] = {4,3,2,1}; |
|
|
| Capture cap; capture_begin(&cap); |
| write_block(0, 4, A, B); |
| char *out = capture_end(&cap); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, cap.err, "capture_begin failed"); |
| TEST_ASSERT_NOT_NULL(out); |
| TEST_ASSERT_EQUAL_STRING("\n\n", out); |
| free(out); |
| } |
|
|
| |
| |
| |
| void test_write_block_address_pad_for_subsequent_specs(void) |
| { |
| abbreviate_duplicate_blocks = true; |
| format_address = format_address_none; |
| address_pad_len = 3; |
| bytes_per_block = 4; |
| configure_spec_zero_fields(2); |
|
|
| char P[4] = {7,7,7,7}; |
| char Q[4] = {8,8,8,8}; |
|
|
| Capture cap; capture_begin(&cap); |
| write_block(0, 4, P, Q); |
| char *out = capture_end(&cap); |
|
|
| TEST_ASSERT_EQUAL_INT_MESSAGE(0, cap.err, "capture_begin failed"); |
| TEST_ASSERT_NOT_NULL(out); |
| |
| TEST_ASSERT_EQUAL_STRING("\n \n", out); |
| free(out); |
| } |
|
|
| int main(void) |
| { |
| UNITY_BEGIN(); |
| RUN_TEST(test_write_block_duplicate_elision_sequence); |
| RUN_TEST(test_write_block_no_elision_when_disabled); |
| RUN_TEST(test_write_block_no_elision_when_partial_block); |
| RUN_TEST(test_write_block_multiple_specs_two_lines); |
| RUN_TEST(test_write_block_address_pad_for_subsequent_specs); |
| return UNITY_END(); |
| } |