Added file assertions for redirection

This commit is contained in:
Snaipe 2015-09-11 00:21:31 +02:00
parent 3744d67b0c
commit 3dc9d47c0b
7 changed files with 144 additions and 11 deletions

View file

@ -61,6 +61,7 @@ enum criterion_assert_messages {
CRITERION_ASSERT_MSG_IS_NOT_NULL,
CRITERION_ASSERT_MSG_IS_EMPTY,
CRITERION_ASSERT_MSG_IS_NOT_EMPTY,
CRITERION_ASSERT_MSG_FILE_STR_MATCH,
};
CR_BEGIN_C_API
@ -80,7 +81,7 @@ CR_END_C_API
# endif
# define CR_TRANSLATE_DEF_MSG__(Arg) \
CR_EXPAND Arg
CR_IDENTITY Arg
# define CR_TRANSLATE_DEF_MSG_(...) \
CR_EXPAND(translate_assert_msg( \

View file

@ -33,6 +33,7 @@
# endif
# define CR_EXPAND(x) x
# define CR_IDENTITY(...) __VA_ARGS__
# define CR_STR(x) CR_EXPAND(CR_STR_(x))
# define CR_STR_(x) #x

View file

@ -25,6 +25,13 @@
# define CRITERION_REDIRECT_H_
# include "common.h"
# include "assert.h"
# ifdef __cplusplus
# include <cstdio>
# else
# include <stdio.h>
# endif
CR_BEGIN_C_API
@ -32,10 +39,38 @@ CR_API void cr_redirect_stdout(void);
CR_API void cr_redirect_stderr(void);
CR_API void cr_redirect_stdin(void);
CR_API FILE* cr_get_redirected_stdout(void);
CR_API FILE* cr_get_redirected_stderr(void);
CR_API FILE* cr_get_redirected_stdin(void);
CR_API CR_STDN FILE* cr_get_redirected_stdout(void);
CR_API CR_STDN FILE* cr_get_redirected_stderr(void);
CR_API CR_STDN FILE* cr_get_redirected_stdin(void);
CR_API int cr_file_match_str(CR_STDN FILE* f, const char *str);
CR_END_C_API
# define cr_assert_redir_op_(Fail, Fun, Op, File, Str, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
!(Fun((File), (Str)) Op 0), \
dummy, \
CRITERION_ASSERT_MSG_FILE_STR_MATCH, \
(CR_STR(File), Str), \
__VA_ARGS__ \
))
# define cr_assert_redir_op_va_(Fail, Fun, Op, ...) \
CR_EXPAND(cr_assert_redir_op_( \
Fail, \
Fun, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_file_contents_match_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, ==, __VA_ARGS__))
# define cr_expect_file_contents_match_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, ==, __VA_ARGS__))
# define cr_assert_file_contents_not_match_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, !=, __VA_ARGS__))
# define cr_expect_file_contents_not_match_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, !=, __VA_ARGS__))
#endif /* !CRITERION_REDIRECT_H_ */

View file

@ -15,6 +15,7 @@ set(SAMPLES
description.c
simple.c
theories.c
redirect.c
signal.cc
report.cc

View file

@ -17,6 +17,12 @@ char *translate_assert_msg(int msg_index, ...) {
[CRITERION_ASSERT_MSG_IS_NOT_NULL] = N_("%s is not null."),
[CRITERION_ASSERT_MSG_IS_EMPTY] = N_("%s is empty."),
[CRITERION_ASSERT_MSG_IS_NOT_EMPTY] = N_("%s is not empty."),
#ifdef ENABLE_NLS
[CRITERION_ASSERT_MSG_FILE_STR_MATCH] = N_("The file contents of %1$s does not match the string \"%2$s\"."),
#else
[CRITERION_ASSERT_MSG_FILE_STR_MATCH] = "The file contents of %s does not match the string \"%s\".",
#endif
};
va_list vl;

View file

@ -453,8 +453,72 @@ cr_std_fd get_std_fd(int fd_kind) {
return kinds[fd_kind];
}
void cr_redirect(int fd_kind, s_pipe_handle *pipe, int fd_index) {
if (stdpipe_stack(pipe) < 0)
FILE* get_std_file(int fd_kind) {
switch (fd_kind) {
case CR_STDIN: return stdin;
case CR_STDOUT: return stdout;
case CR_STDERR: return stderr;
}
return NULL;
}
int make_redirect_pipe(s_pipe_handle *handle, int noblock) {
#ifdef VANILLA_WIN32
static char pipe_name[256] = {0};
HANDLE fhs[2];
SECURITY_ATTRIBUTES attr = {
.nLength = sizeof (SECURITY_ATTRIBUTES),
.bInheritHandle = TRUE
};
if (!pipe_name[0]) {
snprintf(pipe_name, sizeof (pipe_name),
"\\\\.\\pipe\\criterion_%d", GetCurrentProcessId());
}
fhs[0] = CreateNamedPipe(pipe_name,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE
| (noblock ? PIPE_NOWAIT : PIPE_WAIT),
PIPE_UNLIMITED_INSTANCES
4096 * 4,
4096 * 4,
0,
attr);
if (fds[0] == INVALID_HANDLE_VALUE)
return 0;
fhs[1] = CreateFile(pipe_name,
GENERIC_READ | GENERIC_WRITE,
0,
attr,
OPEN_EXISTING,
0,
NULL);
if (fds[1] == INVALID_HANDLE_VALUE) {
CloseHandle(fds[0]);
return 0;
}
*handle = (s_pipe_handle) {{ fhs[0], fhs[1] }};
#else
int fds[2] = { -1, -1 };
if (pipe(fds) == -1)
return 0;
if (noblock)
for (int i = 0; i < 2; ++i)
fcntl(fds[i], F_SETFL, fcntl(fds[i], F_GETFL) | O_NONBLOCK);
*handle = (s_pipe_handle) {{ fds[0], fds[1] }};
#endif
return 1;
}
void cr_redirect(int fd_kind, s_pipe_handle *pipe, int fd_index, int noblock) {
fflush(get_std_file(fd_kind));
if (make_redirect_pipe(pipe, noblock) < 0)
cr_assert_fail("Could not redirect standard file descriptor.");
cr_std_fd fd = get_std_fd(fd_kind);
@ -463,21 +527,21 @@ void cr_redirect(int fd_kind, s_pipe_handle *pipe, int fd_index) {
SetStdHandle(fd, pipe->fhs[fd_index]);
#else
close(fd);
dup2(fd, pipe->fds[fd_index]);
dup2(pipe->fds[fd_index], fd);
close(pipe->fds[fd_index]);
#endif
}
void cr_redirect_stdout(void) {
cr_redirect(CR_STDOUT, &stdout_redir, PIPE_WRITE);
cr_redirect(CR_STDOUT, &stdout_redir, PIPE_WRITE, 1);
}
void cr_redirect_stderr(void) {
cr_redirect(CR_STDERR, &stderr_redir, PIPE_WRITE);
cr_redirect(CR_STDERR, &stderr_redir, PIPE_WRITE, 1);
}
void cr_redirect_stdin(void) {
cr_redirect(CR_STDIN, &stdin_redir, PIPE_READ);
cr_redirect(CR_STDIN, &stdin_redir, PIPE_READ, 0);
}
FILE* cr_get_redirected_stdout(void) {
@ -509,3 +573,27 @@ FILE* cr_get_redirected_stdin(void) {
}
return f;
}
int cr_file_match_str(FILE* f, const char *str) {
size_t len = strlen(str);
fputs(str, stderr);
char buf[512];
size_t read;
int matches = 0;
while ((read = fread(buf, 1, sizeof (buf), f)) > 0) {
matches = !strncmp(buf, str, read);
if (!matches || read > len) {
matches = 0;
break;
}
len -= read;
str += read;
}
// consume the rest of what's available
while (fread(buf, 1, sizeof (buf), f) > 0);
return matches;
}

View file

@ -27,6 +27,7 @@
#include "criterion/types.h"
#include "criterion/options.h"
#include "criterion/redirect.h"
#include "process.h"
#include "event.h"
#include "posix-compat.h"
@ -61,7 +62,7 @@ struct event *worker_read_event(struct process *proc) {
}
void run_worker(struct worker_context *ctx) {
fclose(stdin);
cr_redirect_stdin();
g_event_pipe = pipe_out(ctx->pipe, 1);
ctx->func(ctx->test, ctx->suite);