Run one test file end to end, on its own fiber, so a large batch of files runs as that many concurrent fibers rather than one after another: read the file (srn_fiber_read suspends this fiber rather than blocking its worker), split it into source/expected, hand the source to the reader on a nested fiber, then compare and report.
Errors along the way (I/O, a malformed fixture, a reader failure) are reported to stderr and leave arg->passed false; nothing here escapes to the fiber's result, there is no driver left to inspect it.
124 {
127
128 int fd = open(
arg->path, O_RDONLY);
131 srn_error_t *err =
ERR(ctx, tag,
"Failed to open the test file.");
133 return nullptr;
134 }
135
136 struct stat st;
137 if (fstat(
fd, &st) < 0) {
140 srn_error_t *err =
ERR(ctx, tag,
"Failed to stat the test file.");
142 return nullptr;
143 }
144
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);
150 return nullptr;
151 }
152
153 size_t total_read = 0;
154 while (total_read <
len) {
157 r = srn_fiber_read(fd, content + total_read, len - total_read, -1);
158 });
159
162 free(content);
164 return nullptr;
165 }
166
168
169 break;
170 }
171
172 total_read += r.
count;
173 }
174
176 content[total_read] = '\0';
177
180 free(content);
181 return nullptr;
182 }
183 free(content);
184
186 .ctx = ctx,
187 .reading_context = nullptr,
188 .buffer_id = 0,
189 .buffer = (
const unsigned char *)test.
source,
190 .len = strlen(test.
source),
191 .pos = 0,
192 };
193
195 .parser = &parser,
196 .tree = nullptr,
197 };
198
201
202 if (reader_result != nullptr) {
207 return nullptr;
208 }
209
211 arg->passed = ((actual !=
nullptr && strcmp(actual, test.
expected) == 0) != 0);
212
214 printf(
"PASS %s\n",
arg->path);
215 } else {
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)");
219 }
220
221 if (actual != nullptr) {
222 FREE(ctx, (
void *)actual);
223 }
224
227
228 return nullptr;
229}
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.
#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)
void * srn_fiber_result_t
What a fiber's entry produces, type-erased.
#define SRN_WITH_RETRY(err,...)
Run block and retry it (yielding between attempts through srn_fiber_io_retry) while err holds the tra...
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)
srn_fiber_result_t srn_fiber_wait_for(srn_fiber_t *target)
Block the calling fiber until target finishes, then return its result.
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).