#include "harness.h" #include #include #include int tc_pass = 0, tc_fail = 0; void tc_search_family(const char *desc, const char *pat, int flags, const char *subj, size_t subjlen, int kind, int exp_matched, int n_spans, const long long *exp_spans) { PatternError err; memset(&err, 0, sizeof err); Pattern *p = re_compile(pat, strlen(pat), flags, &err); if (!p) { printf("FAIL [%s]: compile error: %s\n", desc, err.msg ? err.msg : "?"); tc_fail++; return; } Input *in = Input_from_buffer((const uint8_t *)subj, subjlen); Match m; memset(&m, 0, sizeof m); int r; if (kind == 0) r = Pattern_search(p, in, 0, -1, &m); else if (kind == 1) r = Pattern_match(p, in, 0, -1, &m); else r = Pattern_fullmatch(p, in, 0, -1, &m); if (r < 0) { printf("FAIL [%s]: internal error (depth exceeded or bad UTF-8)\n", desc); tc_fail++; } else if ((r == 1) != (exp_matched != 0)) { printf("FAIL [%s]: matched=%d expected=%d\n", desc, r, exp_matched); tc_fail++; } else if (r == 1) { int ok = 1; for (int g = 0; g < n_spans; g++) { long long es = exp_spans[2 * g], ee = exp_spans[2 * g + 1]; long long as = Match_start(&m, g), ae = Match_end(&m, g); if (as != es || ae != ee) { printf("FAIL [%s]: group %d span (%lld,%lld) expected (%lld,%lld)\n", desc, g, as, ae, es, ee); ok = 0; } } if (ok) tc_pass++; else tc_fail++; Match_free(&m); } else { tc_pass++; } Input_free(in); Pattern_free(p); } typedef struct { long long *spans; int n, cap; } SpanList; static void span_cb(void *ctx, const Match *m_const) { SpanList *sl = ctx; Match *m = (Match *)m_const; if (sl->n == sl->cap) { sl->cap = sl->cap ? sl->cap * 2 : 8; sl->spans = realloc(sl->spans, (size_t)sl->cap * 2 * sizeof(long long)); } sl->spans[2 * sl->n] = Match_start(m, 0); sl->spans[2 * sl->n + 1] = Match_end(m, 0); sl->n++; } void tc_finditer(const char *desc, const char *pat, int flags, const char *subj, size_t subjlen, int exp_n_matches, const long long *exp_spans) { PatternError err; memset(&err, 0, sizeof err); Pattern *p = re_compile(pat, strlen(pat), flags, &err); if (!p) { printf("FAIL [%s]: compile error: %s\n", desc, err.msg ? err.msg : "?"); tc_fail++; return; } Input *in = Input_from_buffer((const uint8_t *)subj, subjlen); SpanList sl; memset(&sl, 0, sizeof sl); int total = Pattern_finditer(p, in, 0, -1, span_cb, &sl); if (total < 0) { printf("FAIL [%s]: internal error\n", desc); tc_fail++; } else if (sl.n != exp_n_matches) { printf("FAIL [%s]: %d matches, expected %d\n", desc, sl.n, exp_n_matches); tc_fail++; } else { int ok = 1; for (int i = 0; i < sl.n; i++) if (sl.spans[2 * i] != exp_spans[2 * i] || sl.spans[2 * i + 1] != exp_spans[2 * i + 1]) { printf("FAIL [%s]: match %d span (%lld,%lld) expected (%lld,%lld)\n", desc, i, sl.spans[2 * i], sl.spans[2 * i + 1], exp_spans[2 * i], exp_spans[2 * i + 1]); ok = 0; } if (ok) tc_pass++; else tc_fail++; } free(sl.spans); Input_free(in); Pattern_free(p); } void tc_sub(const char *desc, const char *pat, int flags, const char *subj, size_t subjlen, const char *repl, int count, const char *exp_result, int exp_n) { PatternError err; memset(&err, 0, sizeof err); Pattern *p = re_compile(pat, strlen(pat), flags, &err); if (!p) { printf("FAIL [%s]: compile error: %s\n", desc, err.msg ? err.msg : "?"); tc_fail++; return; } Input *in = Input_from_buffer((const uint8_t *)subj, subjlen); char *out = NULL; size_t outlen = 0; int n = 0; int r = Pattern_subn(p, in, repl, NULL, NULL, count, &out, &outlen, &n); if (r < 0) { printf("FAIL [%s]: internal error\n", desc); tc_fail++; } else { size_t explen = strlen(exp_result); if (outlen != explen || memcmp(out, exp_result, explen) != 0 || n != exp_n) { printf("FAIL [%s]: sub result '%.*s' (n=%d) expected '%s' (n=%d)\n", desc, (int)outlen, out, n, exp_result, exp_n); tc_fail++; } else tc_pass++; } free(out); Input_free(in); Pattern_free(p); } typedef struct { int present; const char *ptr; size_t len; } SplitItem; typedef struct { SplitItem *items; int n, cap; } SplitList; static void split_cb(void *ctx, const Match *m_const) { SplitList *sl = ctx; Match *m = (Match *)m_const; if (sl->n == sl->cap) { sl->cap = sl->cap ? sl->cap * 2 : 8; sl->items = realloc(sl->items, (size_t)sl->cap * sizeof(SplitItem)); } const char *out; size_t outlen; int r = Match_group(m, NULL, 0, &out, &outlen); sl->items[sl->n].present = (r == 1); sl->items[sl->n].ptr = out; sl->items[sl->n].len = outlen; sl->n++; } void tc_split(const char *desc, const char *pat, int flags, const char *subj, size_t subjlen, int maxsplit, int n_items, const char *const *texts) { PatternError err; memset(&err, 0, sizeof err); Pattern *p = re_compile(pat, strlen(pat), flags, &err); if (!p) { printf("FAIL [%s]: compile error: %s\n", desc, err.msg ? err.msg : "?"); tc_fail++; return; } Input *in = Input_from_buffer((const uint8_t *)subj, subjlen); SplitList sl; memset(&sl, 0, sizeof sl); int r = Pattern_split(p, in, maxsplit, split_cb, &sl); if (r < 0) { printf("FAIL [%s]: internal error\n", desc); tc_fail++; } else if (sl.n != n_items) { printf("FAIL [%s]: %d items, expected %d\n", desc, sl.n, n_items); tc_fail++; } else { int ok = 1; for (int i = 0; i < sl.n; i++) { int exp_none = (texts[i] == NULL); if (exp_none && sl.items[i].present) { printf("FAIL [%s]: item %d expected None\n", desc, i); ok = 0; } else if (!exp_none) { size_t explen = strlen(texts[i]); if (!sl.items[i].present || sl.items[i].len != explen || memcmp(sl.items[i].ptr, texts[i], explen) != 0) { printf("FAIL [%s]: item %d = '%.*s' expected '%s'\n", desc, i, sl.items[i].present ? (int)sl.items[i].len : 4, sl.items[i].present ? sl.items[i].ptr : "NONE", texts[i]); ok = 0; } } } if (ok) tc_pass++; else tc_fail++; } free(sl.items); Input_free(in); Pattern_free(p); } void harness_report(void) { printf("\n%d passed, %d failed\n", tc_pass, tc_fail); }