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