diff options
Diffstat (limited to '')
-rw-r--r-- | tests/clar/clar_libgit2_trace.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/tests/clar/clar_libgit2_trace.c b/tests/clar/clar_libgit2_trace.c new file mode 100644 index 0000000..814a5fa --- /dev/null +++ b/tests/clar/clar_libgit2_trace.c @@ -0,0 +1,263 @@ +#include "clar_libgit2_trace.h" +#include "clar_libgit2.h" +#include "clar_libgit2_timer.h" +#include "trace.h" + +struct method { + const char *name; + void (*git_trace_cb)(git_trace_level_t level, const char *msg); + void (*close)(void); +}; + +static const char *message_prefix(git_trace_level_t level) +{ + switch (level) { + case GIT_TRACE_NONE: + return "[NONE]: "; + case GIT_TRACE_FATAL: + return "[FATAL]: "; + case GIT_TRACE_ERROR: + return "[ERROR]: "; + case GIT_TRACE_WARN: + return "[WARN]: "; + case GIT_TRACE_INFO: + return "[INFO]: "; + case GIT_TRACE_DEBUG: + return "[DEBUG]: "; + case GIT_TRACE_TRACE: + return "[TRACE]: "; + default: + return "[?????]: "; + } +} + +static void _git_trace_cb__printf(git_trace_level_t level, const char *msg) +{ + printf("%s%s\n", message_prefix(level), msg); +} + +#if defined(GIT_WIN32) +static void _git_trace_cb__debug(git_trace_level_t level, const char *msg) +{ + OutputDebugString(message_prefix(level)); + OutputDebugString(msg); + OutputDebugString("\n"); + + printf("%s%s\n", message_prefix(level), msg); +} +#else +#define _git_trace_cb__debug _git_trace_cb__printf +#endif + + +static void _trace_printf_close(void) +{ + fflush(stdout); +} + +#define _trace_debug_close _trace_printf_close + + +static struct method s_methods[] = { + { "printf", _git_trace_cb__printf, _trace_printf_close }, + { "debug", _git_trace_cb__debug, _trace_debug_close }, + /* TODO add file method */ + {0}, +}; + + +static int s_trace_loaded = 0; +static int s_trace_level = GIT_TRACE_NONE; +static struct method *s_trace_method = NULL; +static int s_trace_tests = 0; + +static int set_method(const char *name) +{ + int k; + + if (!name || !*name) + name = "printf"; + + for (k=0; (s_methods[k].name); k++) { + if (strcmp(name, s_methods[k].name) == 0) { + s_trace_method = &s_methods[k]; + return 0; + } + } + fprintf(stderr, "Unknown CLAR_TRACE_METHOD: '%s'\n", name); + return -1; +} + + +/** + * Lookup CLAR_TRACE_LEVEL and CLAR_TRACE_METHOD from + * the environment and set the above s_trace_* fields. + * + * If CLAR_TRACE_LEVEL is not set, we disable tracing. + * + * TODO If set, we assume GIT_TRACE_TRACE level, which + * logs everything. Later, we may want to parse the + * value of the environment variable and set a specific + * level. + * + * We assume the "printf" method. This can be changed + * with the CLAR_TRACE_METHOD environment variable. + * Currently, this is only needed on Windows for a "debug" + * version which also writes to the debug output window + * in Visual Studio. + * + * TODO add a "file" method that would open and write + * to a well-known file. This would help keep trace + * output and clar output separate. + * + */ +static void _load_trace_params(void) +{ + char *sz_level; + char *sz_method; + char *sz_tests; + + s_trace_loaded = 1; + + sz_level = cl_getenv("CLAR_TRACE_LEVEL"); + if (!sz_level || !*sz_level) { + s_trace_level = GIT_TRACE_NONE; + s_trace_method = NULL; + return; + } + + /* TODO Parse sz_level and set s_trace_level. */ + s_trace_level = GIT_TRACE_TRACE; + + sz_method = cl_getenv("CLAR_TRACE_METHOD"); + if (set_method(sz_method) < 0) + set_method(NULL); + + sz_tests = cl_getenv("CLAR_TRACE_TESTS"); + if (sz_tests != NULL) + s_trace_tests = 1; +} + +#define HR "================================================================" + +/** + * Timer to report the take spend in a test's run() method. + */ +static cl_perf_timer s_timer_run = CL_PERF_TIMER_INIT; + +/** + * Timer to report total time in a test (init, run, cleanup). + */ +static cl_perf_timer s_timer_test = CL_PERF_TIMER_INIT; + +static void _cl_trace_cb__event_handler( + cl_trace_event ev, + const char *suite_name, + const char *test_name, + void *payload) +{ + GIT_UNUSED(payload); + + if (!s_trace_tests) + return; + + switch (ev) { + case CL_TRACE__SUITE_BEGIN: + git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name); +#if 0 && defined(GIT_WIN32_LEAKCHECK) + git_win32__crtdbg_stacktrace__dump( + GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK, + suite_name); +#endif + break; + + case CL_TRACE__SUITE_END: +#if 0 && defined(GIT_WIN32_LEAKCHECK) + /* As an example of checkpointing, dump leaks within this suite. + * This may generate false positives for things like the global + * TLS error state and maybe the odb cache since they aren't + * freed until the global shutdown and outside the scope of this + * set of tests. + * + * This may under-report if the test itself uses a checkpoint. + * See tests/trace/windows/stacktrace.c + */ + git_win32__crtdbg_stacktrace__dump( + GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK, + suite_name); +#endif + git_trace(GIT_TRACE_TRACE, "\n\n%s: End Suite\n%s", suite_name, HR); + break; + + case CL_TRACE__TEST__BEGIN: + git_trace(GIT_TRACE_TRACE, "\n%s::%s: Begin Test", suite_name, test_name); + cl_perf_timer__init(&s_timer_test); + cl_perf_timer__start(&s_timer_test); + break; + + case CL_TRACE__TEST__END: + cl_perf_timer__stop(&s_timer_test); + git_trace(GIT_TRACE_TRACE, "%s::%s: End Test (%" PRIuZ " %" PRIuZ ")", suite_name, test_name, + cl_perf_timer__last(&s_timer_run), + cl_perf_timer__last(&s_timer_test)); + break; + + case CL_TRACE__TEST__RUN_BEGIN: + git_trace(GIT_TRACE_TRACE, "%s::%s: Begin Run", suite_name, test_name); + cl_perf_timer__init(&s_timer_run); + cl_perf_timer__start(&s_timer_run); + break; + + case CL_TRACE__TEST__RUN_END: + cl_perf_timer__stop(&s_timer_run); + git_trace(GIT_TRACE_TRACE, "%s::%s: End Run", suite_name, test_name); + break; + + case CL_TRACE__TEST__LONGJMP: + cl_perf_timer__stop(&s_timer_run); + git_trace(GIT_TRACE_TRACE, "%s::%s: Aborted", suite_name, test_name); + break; + + default: + break; + } +} + +/** + * Setup/Enable git_trace() based upon settings user's environment. + */ +void cl_global_trace_register(void) +{ + if (!s_trace_loaded) + _load_trace_params(); + + if (s_trace_level == GIT_TRACE_NONE) + return; + if (s_trace_method == NULL) + return; + if (s_trace_method->git_trace_cb == NULL) + return; + + git_trace_set(s_trace_level, s_trace_method->git_trace_cb); + cl_trace_register(_cl_trace_cb__event_handler, NULL); +} + +/** + * If we turned on git_trace() earlier, turn it off. + * + * This is intended to let us close/flush any buffered + * IO if necessary. + * + */ +void cl_global_trace_disable(void) +{ + cl_trace_register(NULL, NULL); + git_trace_set(GIT_TRACE_NONE, NULL); + if (s_trace_method && s_trace_method->close) + s_trace_method->close(); + + /* Leave s_trace_ vars set so they can restart tracing + * since we only want to hit the environment variables + * once. + */ +} |