21# ifndef _POSIX_C_SOURCE
22# define _POSIX_C_SOURCE 200809L
43#define SEPARATOR "---"
63 size_t line_start = 0;
64 size_t sep_start = SIZE_MAX;
65 size_t sep_end = SIZE_MAX;
67 for (
size_t i = 0; i <=
len; i++) {
68 if (i ==
len || content[i] ==
'\n') {
69 size_t line_len = i - line_start;
70 if (line_len == strlen(
SEPARATOR) && memcmp(content + line_start,
SEPARATOR, line_len) == 0) {
71 sep_start = line_start;
72 sep_end = (i <
len) ? i + 1 : i;
79 if (sep_start == SIZE_MAX) {
80 (void)fprintf(stderr,
"%s: missing '---' separator line\n",
path);
84 size_t src_len = sep_start;
85 if (src_len > 0 && content[src_len - 1] ==
'\n') {
89 size_t exp_start = sep_end;
90 size_t exp_len =
len - sep_end;
91 if (exp_len > 0 && content[exp_start + exp_len - 1] ==
'\n') {
95 out->
source = malloc(src_len + 1);
99 (void)fprintf(stderr,
"%s: out of memory\n",
path);
105 memcpy(out->
source, content, src_len);
106 out->
source[src_len] =
'\0';
108 memcpy(out->
expected, content + exp_start, exp_len);
128 int fd = open(
arg->path, O_RDONLY);
131 srn_error_t *err =
ERR(ctx, tag,
"Failed to open the test file.");
137 if (fstat(
fd, &st) < 0) {
140 srn_error_t *err =
ERR(ctx, tag,
"Failed to stat the test file.");
145 size_t len = (size_t)st.st_size;
146 char *content = malloc(
len + 1);
147 if (content ==
nullptr) {
149 (void)fprintf(stderr,
"%s: out of memory reading the test file\n",
arg->path);
153 size_t total_read = 0;
154 while (total_read <
len) {
157 r = srn_fiber_read(fd, content + total_read, len - total_read, -1);
172 total_read += r.
count;
176 content[total_read] =
'\0';
187 .reading_context =
nullptr,
189 .buffer = (
const unsigned char *)test.
source,
190 .len = strlen(test.
source),
202 if (reader_result !=
nullptr) {
211 arg->passed = ((actual !=
nullptr && strcmp(actual, test.
expected) == 0) != 0);
214 printf(
"PASS %s\n",
arg->path);
216 printf(
"FAIL %s\n",
arg->path);
217 printf(
"==> expected:\n%s\n\n", test.
expected);
218 printf(
"==> actual:\n%s\n\n", actual !=
nullptr ? actual :
"(reader error, see above)");
221 if (actual !=
nullptr) {
222 FREE(ctx, (
void *)actual);
231int main(
int argc,
char **argv) {
233 (void)fprintf(stderr,
"usage: %s <test-file>...\n", argv[0]);
239 size_t ntests = (size_t)(argc - 1);
243 for (
size_t i = 0; i < ntests; i++) {
244 args[i].path = argv[i + 1];
251 for (
size_t i = 0; i < ntests; i++) {
252 if (!
args[i].passed) {
260 printf(
"\n%d/%d passed\n", (
int)ntests - failures, (
int)ntests);
262 return failures == 0 ? 0 : 1;
srn_context_t * srn_context_make(srn_engine_t *engine)
Make an empty context, by allocating a new memory block.
int srn_context_release(srn_context_t *ctx)
#define ALLOCN_OR_PANIC(ctx, T, N)
char * srn_error_to_string(const srn_context_t *ctx, const srn_error_t *err)
Format err as a newly allocated string of the form [TAG]: msg, allocated in ctx.
Error handling for the runtime.
#define HAS_ERROR(x)
True when x – a value carrying an ERROR_HEADER – has an error attached.
srn_error_tag_t
The kind of a failure.
srn_error_tag_t srn_errno_to_tag(int errno_value, srn_error_tag_t default_tag)
Map a POSIX errno to error tag.
#define ERR(ctx, err, msg)
srn_fiber_t * srn_fiber_spawn(srn_context_t *ctx, srn_fiber_entry_t entry, void *arg)
Make and schedule a fiber with every default, the engine's scheduler, the configured stack size,...
AI Generated (🤦) Fiber subsystem overview.
void * srn_fiber_result_t
What a fiber's entry produces, type-erased.
The fiber facing IO API: blocking looking calls a fiber uses to do IO.
#define SRN_WITH_RETRY(err,...)
Run block and retry it (yielding between attempts through srn_fiber_io_retry) while err holds the tra...
static srn_fiber_result_t run_test_fiber(srn_context_t *ctx, void *arg_)
Run one test file end to end, on its own fiber, so a large batch of files runs as that many concurren...
static bool split_test_case(const char *path, const char *content, size_t len, test_case_t *out)
Split content (len bytes) at the line that is exactly "---" into a freshly allocated source and expec...
const char * srn_sexp_to_debug_string(srn_context_t *ctx, srn_sexp_tree_t *tree)
Convert the given sexp to a string for debugging purposes.
srn_fiber_result_t read_from_buffer(srn_context_t *ctx, void *arg)
A simple sexp reader to be used with textual IR.
#define SERENE_RUNTIME_SHUTDOWN(engine)
Tear down what SERENE_RUNTIME_INIT brought up, in reverse order, the engine (reactor,...
#define SERENE_RUNTIME_INIT_WITH_SCHED(engine, sched, config)
SERENE_RUNTIME_INIT plus a sched variable bound to the engine's scheduler, which every run and fiber ...
srn_fiber_result_t srn_fiber_wait_for(srn_fiber_t *target)
Block the calling fiber until target finishes, then return its result.
void srn_sched_run(srn_scheduler_t *sched, size_t nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
A runtime error, a tag classifying the failure and a human-readable message.
The result of a byte transfer op (read/write/sendto/recvmsg/sendmsg).