| | #include "../../unity/unity.h" |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <unistd.h> |
| |
|
| | |
| | void setUp(void) { |
| | |
| | } |
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | #ifdef EVAL_TRACE |
| |
|
| | |
| | |
| | |
| | static char *capture_trace_output(const char *fxn, char **test_args) { |
| | |
| | char ***args_ptr = &args; |
| | char **saved_args = *args_ptr; |
| | *args_ptr = test_args; |
| |
|
| | |
| | FILE *tmp = tmpfile(); |
| | if (!tmp) { |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | fflush(stdout); |
| | int stdout_fd = fileno(stdout); |
| | int saved_fd = dup(stdout_fd); |
| | if (saved_fd == -1) { |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | if (dup2(fileno(tmp), stdout_fd) == -1) { |
| | close(saved_fd); |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | |
| | trace((char *)fxn); |
| |
|
| | |
| | fflush(stdout); |
| |
|
| | |
| | long end = ftell(tmp); |
| | if (end < 0) { |
| | |
| | dup2(saved_fd, stdout_fd); |
| | close(saved_fd); |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | if (fseek(tmp, 0, SEEK_SET) != 0) { |
| | dup2(saved_fd, stdout_fd); |
| | close(saved_fd); |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | char *buf = (char *)malloc((size_t)end + 1); |
| | if (!buf) { |
| | dup2(saved_fd, stdout_fd); |
| | close(saved_fd); |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| | return NULL; |
| | } |
| |
|
| | size_t nread = fread(buf, 1, (size_t)end, tmp); |
| | buf[nread] = '\0'; |
| |
|
| | |
| | fflush(stdout); |
| | dup2(saved_fd, stdout_fd); |
| | close(saved_fd); |
| | fclose(tmp); |
| | *args_ptr = saved_args; |
| |
|
| | return buf; |
| | } |
| |
|
| | static void assert_trace_equals(const char *fxn, char **test_args, const char *expected) { |
| | char *out = capture_trace_output(fxn, test_args); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture trace output"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | void test_trace_empty_args(void) { |
| | char *a0[] = { NULL }; |
| | assert_trace_equals("eval", a0, "eval:\n"); |
| | } |
| |
|
| | void test_trace_single_arg(void) { |
| | char *a1[] = { "foo", NULL }; |
| | assert_trace_equals("walk", a1, "walk: foo\n"); |
| | } |
| |
|
| | void test_trace_multiple_args(void) { |
| | char *a2[] = { "arg1", "arg2", "arg3", NULL }; |
| | assert_trace_equals("parse", a2, "parse: arg1 arg2 arg3\n"); |
| | } |
| |
|
| | void test_trace_empty_string_arg(void) { |
| | char *a3[] = { "", "X", NULL }; |
| | |
| | assert_trace_equals("step", a3, "step: X\n"); |
| | } |
| |
|
| | void test_trace_utf8_args(void) { |
| | |
| | char *a4[] = { "\xCE\xB1bc", "\xE2\x9D\xA7", NULL }; |
| | assert_trace_equals("mb", a4, "mb: \xCE\xB1bc \xE2\x9D\xA7\n"); |
| | } |
| |
|
| | #else |
| |
|
| | void test_trace_unavailable(void) { |
| | TEST_IGNORE_MESSAGE("EVAL_TRACE not defined; trace() not compiled, skipping tests."); |
| | } |
| |
|
| | #endif |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | #ifdef EVAL_TRACE |
| | RUN_TEST(test_trace_empty_args); |
| | RUN_TEST(test_trace_single_arg); |
| | RUN_TEST(test_trace_multiple_args); |
| | RUN_TEST(test_trace_empty_string_arg); |
| | RUN_TEST(test_trace_utf8_args); |
| | #else |
| | RUN_TEST(test_trace_unavailable); |
| | #endif |
| | return UNITY_END(); |
| | } |