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