[Issue #13] Merge branch 'features/windows-compat' into bleeding
This commit is contained in:
commit
0184f8f674
15 changed files with 352 additions and 55 deletions
|
@ -52,6 +52,7 @@ libcriterion_la_SOURCES = \
|
|||
src/timer.c \
|
||||
src/timer.h \
|
||||
src/ordered-set.c \
|
||||
src/posix-compat.c \
|
||||
src/main.c
|
||||
|
||||
TARGET = $(PACKAGE)-$(VERSION)
|
||||
|
|
|
@ -14,6 +14,7 @@ init:
|
|||
-P mingw-gcc-core \
|
||||
-P mingw-pthreads \
|
||||
-P mingw-w32api \
|
||||
-P mingw64-i686-gcc-core \
|
||||
-P libtool \
|
||||
-P make \
|
||||
-P python \
|
||||
|
@ -52,13 +53,13 @@ configuration: Release
|
|||
|
||||
install:
|
||||
- "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'"
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; ./configure"'
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; ./configure CC=i686-w64-mingw32-gcc"'
|
||||
|
||||
build_script:
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make"'
|
||||
|
||||
test_script:
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make check"'
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER/samples; exec 0</dev/null; make check"'
|
||||
|
||||
after_test:
|
||||
- '%CYG_BASH% -lc "cat $(find $APPVEYOR_BUILD_FOLDER/samples -iname \"*.log\") /dev/null'
|
||||
|
|
|
@ -20,6 +20,8 @@ AC_PROG_LN_S
|
|||
AC_PROG_MAKE_SET
|
||||
AC_SUBST([LIBTOOL_DEPS])
|
||||
|
||||
AC_FUNC_FNMATCH
|
||||
|
||||
AC_ARG_ENABLE([gcov],
|
||||
[AS_HELP_STRING([--enable-gcov],
|
||||
[Compile the project with converage enabled])],
|
||||
|
|
2
dependencies/csptr
vendored
2
dependencies/csptr
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 15b825ffb8ffe7309bf524659eb900d6bb1d7c04
|
||||
Subproject commit 1c96aaec456287dc63eeb31443f409b5476afa0e
|
|
@ -25,8 +25,9 @@
|
|||
# define CRITERION_EVENT_H_
|
||||
|
||||
# include <stddef.h>
|
||||
# include <stdio.h>
|
||||
|
||||
extern int EVENT_PIPE;
|
||||
extern FILE *g_event_pipe;
|
||||
|
||||
void send_event(int kind, void *data, size_t size);
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
|
||||
struct criterion_test_extra_data {
|
||||
int sentinel_;
|
||||
const char *const identifier_;
|
||||
const char *const file_;
|
||||
const unsigned line_;
|
||||
const char *identifier_;
|
||||
const char *file_;
|
||||
unsigned line_;
|
||||
void (*init)(void);
|
||||
void (*fini)(void);
|
||||
int signal;
|
||||
|
@ -44,12 +44,14 @@ struct criterion_test {
|
|||
const char *name;
|
||||
const char *category;
|
||||
void (*test)(void);
|
||||
struct criterion_test_extra_data *const data;
|
||||
struct criterion_test_extra_data *data;
|
||||
};
|
||||
|
||||
struct criterion_suite {
|
||||
const char *name;
|
||||
struct criterion_test_extra_data *const data;
|
||||
struct criterion_test_extra_data *data;
|
||||
};
|
||||
|
||||
typedef void (*f_worker_func)(struct criterion_test *, struct criterion_suite *);
|
||||
|
||||
#endif /* !CRITERION_TYPES_H_ */
|
||||
|
|
16
src/event.c
16
src/event.c
|
@ -22,36 +22,37 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <csptr/smart_ptr.h>
|
||||
#include "criterion/stats.h"
|
||||
#include "criterion/common.h"
|
||||
#include "criterion/hooks.h"
|
||||
#include "event.h"
|
||||
|
||||
int EVENT_PIPE = -1;
|
||||
FILE *g_event_pipe = NULL;
|
||||
|
||||
void destroy_event(void *ptr, UNUSED void *meta) {
|
||||
struct event *ev = ptr;
|
||||
free(ev->data);
|
||||
}
|
||||
|
||||
struct event *read_event(int fd) {
|
||||
struct event *read_event(FILE *f) {
|
||||
unsigned kind;
|
||||
if (read(fd, &kind, sizeof (unsigned)) < (ssize_t) sizeof (unsigned))
|
||||
if (fread(&kind, sizeof (unsigned), 1, f) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (kind) {
|
||||
case ASSERT: {
|
||||
const size_t assert_size = sizeof (struct criterion_assert_stats);
|
||||
unsigned char *buf = malloc(assert_size);
|
||||
if (read(fd, buf, assert_size) < (ssize_t) assert_size)
|
||||
if (fread(buf, assert_size, 1, f) == 0)
|
||||
return NULL;
|
||||
|
||||
return unique_ptr(struct event, { .kind = kind, .data = buf }, destroy_event);
|
||||
}
|
||||
case POST_TEST: {
|
||||
double *elapsed_time = malloc(sizeof (double));
|
||||
if (read(fd, elapsed_time, sizeof (double)) < (ssize_t) sizeof (double))
|
||||
if (fread(elapsed_time, sizeof (double), 1, f) == 0)
|
||||
return NULL;
|
||||
|
||||
return unique_ptr(struct event, { .kind = kind, .data = elapsed_time }, destroy_event);
|
||||
|
@ -65,5 +66,6 @@ void send_event(int kind, void *data, size_t size) {
|
|||
unsigned char buf[sizeof (int) + size];
|
||||
memcpy(buf, &kind, sizeof (int));
|
||||
memcpy(buf + sizeof (int), data, size);
|
||||
write(EVENT_PIPE, buf, sizeof (int) + size);
|
||||
if (fwrite(buf, sizeof (int) + size, 1, g_event_pipe) == 0)
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,6 @@ struct event {
|
|||
void *data;
|
||||
};
|
||||
|
||||
struct event *read_event(int fd);
|
||||
struct event *read_event(FILE *f);
|
||||
|
||||
#endif /* !EVENT_H_ */
|
||||
|
|
17
src/main.c
17
src/main.c
|
@ -33,6 +33,14 @@
|
|||
|
||||
# define VERSION_MSG "Tests compiled with Criterion v" VERSION "\n"
|
||||
|
||||
#ifdef HAVE_FNMATCH
|
||||
# define PATTERN_USAGE \
|
||||
" --pattern [PATTERN]: run tests matching the " \
|
||||
"given pattern\n"
|
||||
#else
|
||||
# define PATTERN_USAGE
|
||||
#endif
|
||||
|
||||
# define USAGE \
|
||||
VERSION_MSG "\n" \
|
||||
"usage: %s OPTIONS\n" \
|
||||
|
@ -44,8 +52,7 @@
|
|||
" -f or --fail-fast: exit after the first failure\n" \
|
||||
" --ascii: don't use fancy unicode symbols " \
|
||||
"or colors in the output\n" \
|
||||
" --pattern [PATTERN]: run tests matching the " \
|
||||
"given pattern\n" \
|
||||
PATTERN_USAGE \
|
||||
" --tap: enables TAP formatting\n" \
|
||||
" --always-succeed: always exit with 0\n" \
|
||||
" --no-early-exit: do not exit the test worker " \
|
||||
|
@ -112,7 +119,9 @@ int main(int argc, char *argv[]) {
|
|||
{"list", no_argument, 0, 'l'},
|
||||
{"ascii", no_argument, 0, 'k'},
|
||||
{"fail-fast", no_argument, 0, 'f'},
|
||||
#ifdef HAVE_FNMATCH
|
||||
{"pattern", required_argument, 0, 'p'},
|
||||
#endif
|
||||
{"always-succeed", no_argument, 0, 'y'},
|
||||
{"no-early-exit", no_argument, 0, 'z'},
|
||||
{0, 0, 0, 0 }
|
||||
|
@ -124,7 +133,9 @@ int main(int argc, char *argv[]) {
|
|||
.fail_fast = !strcmp("1", getenv("CRITERION_FAIL_FAST") ?: "0"),
|
||||
.use_ascii = !strcmp("1", getenv("CRITERION_USE_ASCII") ?: "0"),
|
||||
.logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"),
|
||||
#ifdef HAVE_FNMATCH
|
||||
.pattern = getenv("CRITERION_TEST_PATTERN"),
|
||||
#endif
|
||||
.output_provider = NORMAL_LOGGING,
|
||||
};
|
||||
|
||||
|
@ -140,7 +151,9 @@ int main(int argc, char *argv[]) {
|
|||
case 'z': criterion_options.no_early_exit = true; break;
|
||||
case 'k': criterion_options.use_ascii = true; break;
|
||||
case 'f': criterion_options.fail_fast = true; break;
|
||||
#ifdef HAVE_FNMATCH
|
||||
case 'p': criterion_options.pattern = optarg; break;
|
||||
#endif
|
||||
case 't': use_tap = true; break;
|
||||
case 'l': do_list_tests = true; break;
|
||||
case 'v': do_print_version = true; break;
|
||||
|
|
196
src/posix-compat.c
Normal file
196
src/posix-compat.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
#include "posix-compat.h"
|
||||
#include "process.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define VC_EXTRALEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <winnt.h>
|
||||
# include <stdint.h>
|
||||
|
||||
# define CREATE_SUSPENDED_(Filename, CmdLine, StartupInfo, Info) \
|
||||
CreateProcessW(Filename, \
|
||||
CmdLine, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
TRUE, \
|
||||
CREATE_SUSPENDED, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
&(StartupInfo), \
|
||||
&(Info))
|
||||
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/wait.h>
|
||||
# include <sys/signal.h>
|
||||
# include <sys/fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <csptr/smart_ptr.h>
|
||||
|
||||
struct proc_handle {
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
#else
|
||||
pid_t pid;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct pipe_handle {
|
||||
#ifdef _WIN32
|
||||
HANDLE fhs[2];
|
||||
#else
|
||||
int fds[2];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct worker_context g_worker_context = {.test = NULL};
|
||||
|
||||
#ifdef _WIN32
|
||||
static struct criterion_test child_test;
|
||||
static struct criterion_test_extra_data child_test_data;
|
||||
static struct criterion_suite child_suite;
|
||||
static struct criterion_test_extra_data child_suite_data;
|
||||
static struct pipe_handle child_pipe;
|
||||
#endif
|
||||
|
||||
int resume_child(void) {
|
||||
if (g_worker_context.test) {
|
||||
run_worker(&g_worker_context);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_proc_handle *fork_process() {
|
||||
#ifdef _WIN32
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOW si = { .cb = sizeof (STARTUPINFOW) };
|
||||
|
||||
ZeroMemory(&info, sizeof (info));
|
||||
|
||||
// Create the suspended child process
|
||||
wchar_t filename[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, filename, MAX_PATH);
|
||||
|
||||
if (!CREATE_SUSPENDED_(filename, GetCommandLineW(), si, info))
|
||||
return (void *) -1;
|
||||
|
||||
// Copy context over
|
||||
f_worker_func child_func = g_worker_context.func;
|
||||
|
||||
child_test = *g_worker_context.test;
|
||||
child_test_data = *g_worker_context.test->data;
|
||||
child_suite = *g_worker_context.suite;
|
||||
child_pipe = *g_worker_context.pipe;
|
||||
|
||||
g_worker_context = (struct worker_context) { &child_test, &child_suite, child_func, &child_pipe };
|
||||
child_test.data = &child_test_data;
|
||||
|
||||
if (g_worker_context.suite->data) {
|
||||
child_suite_data = *g_worker_context.suite->data;
|
||||
child_suite.data = &child_suite_data;
|
||||
WriteProcessMemory(info.hProcess, &child_suite_data, &child_suite_data, sizeof (child_suite_data), NULL);
|
||||
}
|
||||
|
||||
WriteProcessMemory(info.hProcess, &child_test, &child_test, sizeof (child_test), NULL);
|
||||
WriteProcessMemory(info.hProcess, &child_test_data, &child_test_data, sizeof (child_test_data), NULL);
|
||||
WriteProcessMemory(info.hProcess, &child_suite, &child_suite, sizeof (child_suite), NULL);
|
||||
WriteProcessMemory(info.hProcess, &child_pipe, &child_pipe, sizeof (child_pipe), NULL);
|
||||
WriteProcessMemory(info.hProcess, &g_worker_context, &g_worker_context, sizeof (struct worker_context), NULL);
|
||||
|
||||
ResumeThread(info.hThread);
|
||||
CloseHandle(info.hThread);
|
||||
|
||||
return unique_ptr(s_proc_handle, { info.hProcess });
|
||||
#else
|
||||
pid_t pid = fork();
|
||||
if (pid == -1)
|
||||
return (void *) -1;
|
||||
if (pid == 0)
|
||||
return NULL;
|
||||
return unique_ptr(s_proc_handle, { pid });
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait_process(s_proc_handle *handle, int *status) {
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(handle->handle, INFINITE);
|
||||
DWORD exit_code;
|
||||
GetExitCodeProcess(handle->handle, &exit_code);
|
||||
CloseHandle(handle->handle);
|
||||
*status = exit_code << 8;
|
||||
#else
|
||||
waitpid(handle->pid, status, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
FILE *pipe_in(s_pipe_handle *p) {
|
||||
#ifdef _WIN32
|
||||
CloseHandle(p->fhs[1]);
|
||||
int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
FILE *in = _fdopen(fd, "r");
|
||||
#else
|
||||
close(p->fds[1]);
|
||||
FILE *in = fdopen(p->fds[0], "r");
|
||||
#endif
|
||||
if (!in)
|
||||
return NULL;
|
||||
|
||||
setvbuf(in, NULL, _IONBF, 0);
|
||||
return in;
|
||||
}
|
||||
|
||||
FILE *pipe_out(s_pipe_handle *p) {
|
||||
#ifdef _WIN32
|
||||
CloseHandle(p->fhs[0]);
|
||||
int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
FILE *out = _fdopen(fd, "w");
|
||||
#else
|
||||
close(p->fds[0]);
|
||||
FILE *out = fdopen(p->fds[1], "w");
|
||||
#endif
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
setvbuf(out, NULL, _IONBF, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
s_pipe_handle *stdpipe() {
|
||||
#ifdef _WIN32
|
||||
HANDLE fhs[2];
|
||||
SECURITY_ATTRIBUTES attr = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE };
|
||||
if (!CreatePipe(fhs, fhs + 1, &attr, 0))
|
||||
return NULL;
|
||||
return unique_ptr(s_pipe_handle, {{ fhs[0], fhs[1] }});
|
||||
#else
|
||||
int fds[2] = { -1, -1 };
|
||||
if (pipe(fds) == -1)
|
||||
return NULL;
|
||||
return unique_ptr(s_pipe_handle, {{ fds[0], fds[1] }});
|
||||
#endif
|
||||
}
|
||||
|
||||
s_proc_handle *get_current_process() {
|
||||
#ifdef _WIN32
|
||||
return unique_ptr(s_proc_handle, { GetCurrentProcess() });
|
||||
#else
|
||||
return unique_ptr(s_proc_handle, { getpid() });
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_current_process(s_proc_handle *proc) {
|
||||
#ifdef _WIN32
|
||||
return GetProcessId(proc->handle) == GetProcessId(GetCurrentProcess());
|
||||
#else
|
||||
return proc->pid == getpid();
|
||||
#endif
|
||||
}
|
52
src/posix-compat.h
Normal file
52
src/posix-compat.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef POSIX_COMPAT_H_
|
||||
# define POSIX_COMPAT_H_
|
||||
|
||||
# if !defined(_POSIX_SOURCE)
|
||||
# define _POSIX_SOURCE 1
|
||||
# define TMP_POSIX
|
||||
# endif
|
||||
# include <stdio.h>
|
||||
# ifdef TMP_POSIX
|
||||
# undef _POSIX_SOURCE
|
||||
# undef TMP_POSIX
|
||||
# endif
|
||||
|
||||
# ifdef _WIN32
|
||||
# define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8)
|
||||
# define WTERMSIG(Status) ((Status) & 0x7F)
|
||||
# define WIFEXITED(Status) (WTERMSIG(Status) == 0)
|
||||
# define WIFSIGNALED(Status) (((signed char) (WTERMSIG(Status) + 1) >> 1) > 0)
|
||||
# else
|
||||
# include <sys/wait.h>
|
||||
# endif
|
||||
|
||||
#include <criterion/types.h>
|
||||
|
||||
struct proc_handle;
|
||||
typedef struct proc_handle s_proc_handle;
|
||||
|
||||
struct pipe_handle;
|
||||
typedef struct pipe_handle s_pipe_handle;
|
||||
|
||||
struct worker_context {
|
||||
struct criterion_test *test;
|
||||
struct criterion_suite *suite;
|
||||
f_worker_func func;
|
||||
struct pipe_handle *pipe;
|
||||
};
|
||||
|
||||
extern struct worker_context g_worker_context;
|
||||
|
||||
int resume_child(void);
|
||||
|
||||
s_pipe_handle *stdpipe();
|
||||
FILE *pipe_in(s_pipe_handle *p);
|
||||
FILE *pipe_out(s_pipe_handle *p);
|
||||
|
||||
s_proc_handle *fork_process();
|
||||
void wait_process(s_proc_handle *handle, int *status);
|
||||
|
||||
s_proc_handle *get_current_process();
|
||||
bool is_current_process(s_proc_handle *proc);
|
||||
|
||||
#endif /* !POSIX_COMPAT_H_ */
|
|
@ -22,71 +22,84 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdbool.h>
|
||||
#include <csptr/smart_ptr.h>
|
||||
|
||||
#include "criterion/types.h"
|
||||
#include "criterion/options.h"
|
||||
#include "process.h"
|
||||
#include "event.h"
|
||||
#include "posix-compat.h"
|
||||
|
||||
struct process {
|
||||
pid_t pid;
|
||||
int in;
|
||||
s_proc_handle *proc;
|
||||
FILE *in;
|
||||
};
|
||||
|
||||
static pid_t g_runner_pid;
|
||||
static s_proc_handle *g_current_proc;
|
||||
|
||||
void set_runner_pid(void) {
|
||||
g_runner_pid = getpid();
|
||||
void set_runner_process(void) {
|
||||
g_current_proc = get_current_process();
|
||||
}
|
||||
|
||||
void unset_runner_process(void) {
|
||||
sfree(g_current_proc);
|
||||
}
|
||||
|
||||
bool is_runner(void) {
|
||||
return g_runner_pid == getpid();
|
||||
return is_current_process(g_current_proc);
|
||||
}
|
||||
|
||||
static void close_process(void *ptr, UNUSED void *meta) {
|
||||
close(((struct process *) ptr)->in);
|
||||
struct process *proc = ptr;
|
||||
fclose(proc->in);
|
||||
sfree(proc->proc);
|
||||
}
|
||||
|
||||
struct event *worker_read_event(struct process *proc) {
|
||||
return read_event(proc->in);
|
||||
}
|
||||
|
||||
void run_worker(struct worker_context *ctx) {
|
||||
fclose(stdin);
|
||||
g_event_pipe = pipe_out(ctx->pipe);
|
||||
|
||||
ctx->func(ctx->test, ctx->suite);
|
||||
fclose(g_event_pipe);
|
||||
|
||||
fflush(NULL); // flush all opened streams
|
||||
if (criterion_options.no_early_exit)
|
||||
return;
|
||||
_Exit(0);
|
||||
}
|
||||
|
||||
struct process *spawn_test_worker(struct criterion_test *test,
|
||||
struct criterion_suite *suite,
|
||||
void (*func)(struct criterion_test *, struct criterion_suite *)) {
|
||||
int fds[2];
|
||||
if (pipe(fds) == -1)
|
||||
f_worker_func func) {
|
||||
smart s_pipe_handle *pipe = stdpipe();
|
||||
if (pipe == NULL)
|
||||
abort();
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
g_worker_context = (struct worker_context) {
|
||||
.test = test,
|
||||
.suite = suite,
|
||||
.func = func,
|
||||
.pipe = pipe
|
||||
};
|
||||
s_proc_handle *proc = fork_process();
|
||||
if (proc == (void *) -1) {
|
||||
return NULL;
|
||||
} else if (proc == NULL) {
|
||||
run_worker(&g_worker_context);
|
||||
return NULL;
|
||||
} else if (!pid) {
|
||||
close(STDIN_FILENO);
|
||||
close(fds[0]);
|
||||
EVENT_PIPE = fds[1];
|
||||
|
||||
func(test, suite);
|
||||
close(fds[1]);
|
||||
|
||||
fflush(NULL); // flush all opened streams
|
||||
if (criterion_options.no_early_exit)
|
||||
return NULL;
|
||||
else
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
close(fds[1]);
|
||||
return unique_ptr(struct process, { .pid = pid, .in = fds[0] }, close_process);
|
||||
return unique_ptr(struct process, { .proc = proc, .in = pipe_in(pipe) }, close_process);
|
||||
}
|
||||
|
||||
struct process_status wait_proc(struct process *proc) {
|
||||
int status;
|
||||
waitpid(proc->pid, &status, 0);
|
||||
wait_process(proc->proc, &status);
|
||||
|
||||
if (WIFEXITED(status))
|
||||
return (struct process_status) { .kind = EXIT_STATUS, .status = WEXITSTATUS(status) };
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
# define PROCESS_H_
|
||||
|
||||
# include <stdbool.h>
|
||||
# include "posix-compat.h"
|
||||
|
||||
struct process;
|
||||
|
||||
|
@ -39,7 +40,9 @@ struct process_status {
|
|||
int status;
|
||||
};
|
||||
|
||||
void set_runner_pid(void);
|
||||
void run_worker(struct worker_context *ctx);
|
||||
void set_runner_process(void);
|
||||
void unset_runner_process(void);
|
||||
bool is_runner(void);
|
||||
struct process_status wait_proc(struct process *proc);
|
||||
struct process *spawn_test_worker(struct criterion_test *test,
|
||||
|
|
|
@ -24,13 +24,17 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fnmatch.h>
|
||||
#include "criterion/types.h"
|
||||
#include "criterion/stats.h"
|
||||
#include "criterion/logging.h"
|
||||
#include "criterion/options.h"
|
||||
#include "criterion/ordered-set.h"
|
||||
#include "report.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
|
||||
#define IMPL_CALL_REPORT_HOOKS(Kind) \
|
||||
IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \
|
||||
|
@ -53,6 +57,7 @@ __attribute__((always_inline))
|
|||
static inline void nothing() {}
|
||||
|
||||
IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) {
|
||||
#ifdef HAVE_FNMATCH
|
||||
if (criterion_options.pattern) {
|
||||
FOREACH_SET(struct criterion_suite_set *s, set->suites) {
|
||||
if ((s->suite.data && s->suite.data->disabled) || !s->tests)
|
||||
|
@ -64,6 +69,7 @@ IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
log(pre_all, set);
|
||||
}
|
||||
|
||||
|
|
11
src/runner.c
11
src/runner.c
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <csptr/smart_ptr.h>
|
||||
#include "criterion/criterion.h"
|
||||
#include "criterion/options.h"
|
||||
|
@ -34,6 +33,7 @@
|
|||
#include "event.h"
|
||||
#include "process.h"
|
||||
#include "timer.h"
|
||||
#include "posix-compat.h"
|
||||
|
||||
IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests);
|
||||
IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites);
|
||||
|
@ -200,10 +200,12 @@ static void run_test(struct criterion_global_stats *stats,
|
|||
}
|
||||
|
||||
static int criterion_run_all_tests_impl(void) {
|
||||
if (resume_child()) // (windows only) resume from the fork
|
||||
return -1;
|
||||
|
||||
smart struct criterion_test_set *set = criterion_init();
|
||||
|
||||
report(PRE_ALL, set);
|
||||
set_runner_pid();
|
||||
|
||||
smart struct criterion_global_stats *stats = stats_init();
|
||||
map_tests(set, stats, run_test);
|
||||
|
@ -216,9 +218,12 @@ static int criterion_run_all_tests_impl(void) {
|
|||
}
|
||||
|
||||
int criterion_run_all_tests(void) {
|
||||
set_runner_process();
|
||||
int res = criterion_run_all_tests_impl();
|
||||
unset_runner_process();
|
||||
|
||||
if (res == -1) // if this is the test worker terminating
|
||||
_exit(0);
|
||||
_Exit(0);
|
||||
|
||||
return criterion_options.always_succeed || res;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue