Added event system to push reporting back to the parent process

This commit is contained in:
Snaipe 2015-02-05 18:09:21 +01:00
parent 6babf0e295
commit 7db8b3f413
14 changed files with 244 additions and 48 deletions

View file

@ -1,7 +1,7 @@
CC = gcc
CFLAGS = -Wall -Wextra -std=gnu99 -Isrc/ -Iinclude/ -g
SRCS = runner.c report.c
SRCS = runner.c report.c event.c
OBJS = $(addprefix src/,$(subst .c,.o,$(SRCS)))
sample: samples/simple.o libcriterion.a

View file

@ -27,49 +27,24 @@
# include <stdlib.h>
# include <stdbool.h>
# include "criterion.h"
# include "event.h"
enum criterion_assert_kind {
NORMAL,
FATAL
};
struct criterion_assert_stat {
enum criterion_assert_kind kind;
const char *condition;
const char *message;
bool passed;
unsigned line;
struct criterion_assert_stat *next;
};
struct criterion_test_stats {
struct criterion_test *test;
struct criterion_assert_stat *asserts;
unsigned failed;
unsigned passed;
};
extern struct criterion_test_stats g_current_test_stats;
# define assertImpl(Kind, Condition, ...) \
do { \
int passed = !!(Condition); \
struct criterion_assert_stat *stat = \
malloc(sizeof (struct criterion_assert_stat)); \
*stat = (struct criterion_assert_stat) { \
struct criterion_assert_stat stat = { \
.kind = Kind, \
.condition = #Condition, \
.message = "" __VA_ARGS__, \
.passed = passed, \
.line = __LINE__, \
.next = g_current_test_stats.asserts, \
}; \
g_current_test_stats.asserts = stat; \
if (passed) \
++g_current_test_stats.passed; \
else \
++g_current_test_stats.failed; \
send_event(ASSERT, &stat, sizeof (stat)); \
if (!passed && Kind == FATAL) \
return; \
} while (0)

31
include/criterion/event.h Normal file
View file

@ -0,0 +1,31 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_EVENT_H_
# define CRITERION_EVENT_H_
extern const int EVENT_PIPE;
void send_event(int kind, void *data, size_t size);
#endif /* !CRITERION_EVENT_H_ */

View file

@ -30,6 +30,8 @@ typedef enum {
PRE_EVERYTHING,
PRE_INIT,
PRE_TEST,
ASSERT,
TEST_CRASH,
POST_TEST,
POST_FINI,
POST_EVERYTHING,

43
include/criterion/stats.h Normal file
View file

@ -0,0 +1,43 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_STATS_H_
# define CRITERION_STATS_H_
# include "criterion.h"
struct criterion_assert_stat {
int kind;
const char *condition;
const char *message;
bool passed;
unsigned line;
};
struct criterion_test_stats {
struct criterion_test *test;
int passed;
int failed;
};
#endif /* !CRITERION_STATS_H_ */

View file

@ -1,8 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include "criterion.h"
#include "report.h"
#include "assert.h"
#include <criterion/criterion.h>
#include <criterion/assert.h>
#include <criterion/hooks.h>
#include <criterion/stats.h>
Test(misc, failing) {
assert(1);
@ -13,6 +14,19 @@ Test(misc, simple) {
expect(1);
}
Test(aziezdcjn, simple) {
expect(1);
}
Test(aziezdcjn, abcd) {
expect(1);
}
Test(aziezdcjn, simplez) {
expect(1);
}
Test(aziezdcjn, simpl) {
expect(1);
}
ReportHook(PRE_INIT)(struct criterion_test *test) {
printf("testing %s in category %s\n", test->name, test->category);
}

64
src/event.c Normal file
View file

@ -0,0 +1,64 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "criterion/assert.h"
#undef assert
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <csptr/smart_ptr.h>
#include "criterion/criterion.h"
#include "criterion/stats.h"
#include "criterion/hooks.h"
#include "event.h"
const int EVENT_PIPE = 3;
void destroy_event(void *ptr, UNUSED void *meta) {
struct event *ev = ptr;
free(ev->data);
}
struct event *read_event(int fd) {
unsigned kind;
if (read(fd, &kind, sizeof (unsigned)) < (ssize_t) sizeof (unsigned))
return NULL;
if (kind != ASSERT)
return unique_ptr(struct event, ({ .kind = kind, .data = NULL }));
const size_t assert_size = sizeof (struct criterion_assert_stat);
unsigned char *buf = malloc(assert_size);
if (read(fd, buf, assert_size) < (ssize_t) assert_size)
return NULL;
return unique_ptr(struct event, ({ .kind = kind, .data = buf }), destroy_event);
}
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 (buf));
}

36
src/event.h Normal file
View file

@ -0,0 +1,36 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef EVENT_H_
# define EVENT_H_
# include "criterion/event.h"
struct event {
int kind;
void *data;
};
struct event *read_event(int fd);
#endif /* !EVENT_H_ */

View file

@ -22,7 +22,8 @@
* THE SOFTWARE.
*/
#include <stdio.h>
#include "criterion.h"
#include "criterion/criterion.h"
#include "criterion/stats.h"
#include "report.h"
#define IMPL_CALL_REPORT_HOOKS(Kind) \
@ -60,3 +61,5 @@ ReportHook(POST_FINI)() {}
ReportHook(PRE_EVERYTHING)() {}
ReportHook(POST_EVERYTHING)() {}

View file

@ -24,7 +24,7 @@
#ifndef REPORT_H_
# define REPORT_H_
# include "hooks.h"
# include "criterion/hooks.h"
# define report(Kind, Data) call_report_hooks_##Kind(Data)

View file

@ -22,13 +22,15 @@
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <csptr/smart_ptr.h>
#include "criterion/assert.h"
#include "criterion/stats.h"
#include "runner.h"
#include "report.h"
#include "assert.h"
#include "event.h"
static struct criterion_test * const g_section_start = &__start_criterion_tests;
static struct criterion_test * const g_section_end = &__stop_criterion_tests;
@ -92,31 +94,57 @@ static void map_tests(struct test_set *set, void (*fun)(struct criterion_test *)
__attribute__ ((always_inline))
static inline void nothing() {}
struct criterion_test_stats g_current_test_stats;
static void run_test_nofork(struct criterion_test *test) {
report(PRE_INIT, test);
static void run_test_child(struct criterion_test *test) {
send_event(PRE_INIT, NULL, 0);
(test->data->init ?: nothing)();
report(PRE_TEST, test);
g_current_test_stats = (struct criterion_test_stats) { .test = test };
send_event(PRE_TEST, NULL, 0);
(test->test ?: nothing)();
report(POST_TEST, &g_current_test_stats);
send_event(POST_TEST, NULL, 0);
(test->data->fini ?: nothing)();
report(POST_FINI, test);
send_event(POST_FINI, NULL, 0);
}
struct pipefds {
int in, out;
} __attribute__ ((packed));
static void setup_child(struct pipefds *fds) {
close(STDIN_FILENO);
close(fds->in);
dup2(fds->out, EVENT_PIPE);
close(fds->out);
}
static void run_test(struct criterion_test *test) {
struct pipefds fds;
if (pipe((int*) &fds) == -1)
abort();
pid_t pid;
if (!(pid = fork())) {
run_test_nofork(test);
setup_child(&fds);
run_test_child(test);
exit(0);
} else {
struct criterion_test_stats stats = { .test = test };
close(fds.out);
struct event *ev;
while ((ev = read_event(fds.in)) != NULL) {
switch (ev->kind) {
case PRE_INIT: report(PRE_INIT, test); break;
case PRE_TEST: report(PRE_TEST, test); break;
case ASSERT: report(PRE_TEST, ev->data); break;
case POST_TEST: report(POST_TEST, &stats); break;
case POST_FINI: report(POST_FINI, test); break;
}
sfree(ev);
}
waitpid(pid, NULL, 0);
}
}
// TODO: disable & change tests at runtime
void run_all(void) {
report(PRE_EVERYTHING, NULL);
smart struct test_set *set = read_all_tests();

View file

@ -24,7 +24,7 @@
#ifndef CRITERION_RUNNER_H_
# define CRITERION_RUNNER_H_
# include "criterion.h"
# include "criterion/criterion.h"
extern struct criterion_test __start_criterion_tests;
extern struct criterion_test __stop_criterion_tests;