X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;ds=sidebyside;f=tools%2Fccanlint%2Ftests%2Fexamples_run.c;h=8ea6a9bf515806fa58e22bbe480c96e8b4065460;hb=9a8344b2cd849a5506ca5e93bfc30665fb35acab;hp=522feb0a0bf320422c80f4bc5c5fb73335b159b0;hpb=5378c864f9c37f39d906f599285da25a7db0c9fe;p=ccan diff --git a/tools/ccanlint/tests/examples_run.c b/tools/ccanlint/tests/examples_run.c index 522feb0a..8ea6a9bf 100644 --- a/tools/ccanlint/tests/examples_run.c +++ b/tools/ccanlint/tests/examples_run.c @@ -1,8 +1,9 @@ #include #include -#include #include #include +#include +#include #include #include #include @@ -14,19 +15,19 @@ static const char *can_run(struct manifest *m) { + struct list_head *list; + if (safe_mode) return "Safe mode enabled"; - return NULL; + foreach_ptr(list, &m->examples, &m->mangled_examples) + if (!list_empty(list)) + return NULL; + return "No examples"; } -struct score { - unsigned int score; - char *errors; -}; - /* Very dumb scanner, allocates %s-strings. */ static bool scan_forv(const void *ctx, - const char *input, const char *fmt, const va_list *args) + const char *input, const char *fmt, va_list *args) { va_list ap; bool ret; @@ -36,10 +37,10 @@ static bool scan_forv(const void *ctx, va_copy(ap, *args); - if (isspace(fmt[0])) { + if (cisspace(fmt[0])) { /* One format space can swallow many input spaces */ ret = false; - while (isspace(input[0])) { + while (cisspace(input[0])) { if (scan_forv(ctx, ++input, fmt+1, &ap)) { ret = true; break; @@ -59,7 +60,7 @@ static bool scan_forv(const void *ctx, for (len = 1; input[len-1]; len++) { ret = scan_forv(ctx, input + len, fmt+2, &ap); if (ret) { - *p = talloc_strndup(ctx, input, len); + *p = tal_strndup(ctx, input, len); ret = true; break; } @@ -81,224 +82,172 @@ static bool scan_for(const void *ctx, const char *input, const char *fmt, ...) } static char *find_expect(struct ccan_file *file, - char **lines, char **input, bool *exact, + char **lines, char **input, + bool *contains, bool *whitespace, bool *error, unsigned *line) { char *expect; - const char *fmt; + *error = false; for (; lines[*line]; (*line)++) { char *p = lines[*line] + strspn(lines[*line], " \t"); if (!strstarts(p, "//")) continue; p += strspn(p, "/ "); - foreach_ptr(fmt, - "given '%s', outputs '%s'", - "given '%s' outputs '%s'", - "given \"%s\", outputs \"%s\"", - "given \"%s\" outputs \"%s\"") { - if (scan_for(file, p, fmt, input, &expect)) { - *exact = true; - return expect; - } - } - - foreach_ptr(fmt, - "given '%s', output contains '%s'", - "given '%s' output contains '%s'", - "given \"%s\", output contains \"%s\"", - "given \"%s\" output contains \"%s\"") { - if (scan_for(file, p, fmt, input, &expect)) { - *exact = false; - return expect; - } - } - foreach_ptr(fmt, "outputs '%s'", "outputs \"%s\"") { - if (scan_for(file, p, fmt, &expect)) { - *input = ""; - *exact = true; - return expect; + /* With or without input? */ + if (strncasecmp(p, "given", strlen("given")) == 0) { + /* Must be of form */ + if (!scan_for(file, p, "given \"%s\" %s", input, &p)) { + *error = true; + return p; } + } else { + *input = NULL; } - foreach_ptr(fmt, - "given '%s', output contains '%s'", - "given '%s' output contains '%s'", - "given \"%s\", output contains \"%s\"", - "given \"%s\" output contains \"%s\"") { - if (scan_for(file, p, fmt, input, &expect)) { - *exact = false; - return expect; - } + if (scan_for(file, p, "outputs \"%s\"", &expect)) { + *whitespace = true; + *contains = false; + return expect; } - /* Unquoted versions... we can get this wrong! */ - foreach_ptr(fmt, - "given %s, outputs '%s'", - "given '%s', outputs %s", - "given %s, outputs \"%s\"", - "given \"%s\", outputs %s", - "given %s, outputs %s", - "given %s outputs '%s'", - "given '%s' outputs %s", - "given %s outputs \"%s\"", - "given \"%s\" outputs %s", - "given %s outputs %s") { - if (scan_for(file, p, fmt, input, &expect)) { - *exact = true; - return expect; - } + if (scan_for(file, p, "output contains \"%s\"", &expect)) { + *whitespace = true; + *contains = true; + return expect; } - foreach_ptr(fmt, - "given %s, output contains '%s'", - "given '%s', output contains %s", - "given %s, output contains \"%s\"", - "given \"%s\", output contains %s", - "given %s, output contains %s", - "given %s output contains '%s'", - "given '%s' output contains %s", - "given %s output contains \"%s\"", - "given \"%s\" output contains %s", - "given %s output contains %s") { - if (scan_for(file, p, fmt, input, &expect)) { - *exact = false; - return expect; - } + /* Whitespace-ignoring versions. */ + if (scan_for(file, p, "outputs %s", &expect)) { + *whitespace = false; + *contains = false; + return expect; } - foreach_ptr(fmt, - "outputs '%s'", - "outputs \"%s\"", - "outputs %s") { - if (scan_for(file, p, fmt, &expect)) { - *input = ""; - *exact = true; - return expect; - } + if (scan_for(file, p, "output contains %s", &expect)) { + *whitespace = false; + *contains = true; + return expect; } - foreach_ptr(fmt, - "output contains '%s'", - "output contains \"%s\"", - "output contains %s") { - if (scan_for(file, p, fmt, &expect)) { - *input = ""; - *exact = false; - return expect; - } + /* Other malformed line? */ + if (*input || !strncasecmp(p, "output", strlen("output"))) { + *error = true; + return p; } - } + } return NULL; } -static char *trim(char *string) -{ - while (strends(string, "\n")) - string[strlen(string)-1] = '\0'; - return string; -} - static char *unexpected(struct ccan_file *i, const char *input, - const char *expect, bool exact) + const char *expect, bool contains, bool whitespace) { char *output, *cmd; + const char *p; bool ok; unsigned int default_time = default_timeout_ms; - cmd = talloc_asprintf(i, "echo '%s' | %s %s", - input, i->compiled, input); + if (input) + cmd = tal_fmt(i, "echo '%s' | %s %s", + input, i->compiled[COMPILE_NORMAL], input); + else + cmd = tal_fmt(i, "%s", i->compiled[COMPILE_NORMAL]); output = run_with_timeout(i, cmd, &ok, &default_time); if (!ok) - return talloc_asprintf(i, "Exited with non-zero status\n"); + return tal_fmt(i, "Exited with non-zero status\n"); - if (exact) { - if (streq(output, expect) || streq(trim(output), expect)) + /* Substitute \n */ + while ((p = strstr(expect, "\\n")) != NULL) { + expect = tal_fmt(cmd, "%.*s\n%s", (int)(p - expect), expect, + p+2); + } + + if (!whitespace) { + /* Normalize to spaces. */ + expect = tal_strjoin(cmd, + tal_strsplit(cmd, expect, " \n\t", + STR_NO_EMPTY), + " ", STR_NO_TRAIL); + output = tal_strjoin(cmd, + tal_strsplit(cmd, output, " \n\t", + STR_NO_EMPTY), + " ", STR_NO_TRAIL); + } + + if (contains) { + if (strstr(output, expect)) return NULL; } else { - if (strstr(output, expect)) + if (streq(output, expect)) return NULL; } + return output; } -static void *run_examples(struct manifest *m, bool keep, - unsigned int *timeleft) +static void run_examples(struct manifest *m, + unsigned int *timeleft, struct score *score) { struct ccan_file *i; struct list_head *list; - struct score *score = talloc(m, struct score); - score->score = 0; - score->errors = talloc_strdup(score, ""); + score->total = 0; + score->pass = true; - examples_run.total_score = 0; foreach_ptr(list, &m->examples, &m->mangled_examples) { list_for_each(list, i, list) { char **lines, *expect, *input, *output; unsigned int linenum = 0; - bool exact; - - if (i->compiled == NULL) - continue; + bool contains, whitespace, error; lines = get_ccan_file_lines(i); - for (expect = find_expect(i, lines, &input, &exact, + for (expect = find_expect(i, lines, &input, + &contains, &whitespace, &error, &linenum); expect; linenum++, expect = find_expect(i, lines, &input, - &exact, &linenum)) { - examples_run.total_score++; - output = unexpected(i, input, expect, exact); - if (!output) + &contains, &whitespace, + &error, &linenum)) { + if (error) { + score_file_error(score, i, linenum+1, + "Unparsable test line '%s'", + lines[linenum]); + score->pass = false; + break; + } + + if (i->compiled[COMPILE_NORMAL] == NULL) + continue; + + score->total++; + output = unexpected(i, input, expect, + contains, whitespace); + if (!output) { score->score++; - else { - score->errors = talloc_asprintf_append( - score->errors, - "%s: output '%s' didn't" - " %s '%s'\n", - i->name, output, - exact ? "match" : "contain", - expect); + continue; } + score_file_error(score, i, linenum+1, + "output '%s' didn't %s '%s'\n", + output, + contains ? "contain" : "match", + expect); + score->pass = false; } } } - - if (strcmp(score->errors, "") == 0) { - talloc_free(score); - return NULL; - } - return score; -} - -static unsigned int score_examples(struct manifest *m, void *check_result) -{ - struct score *score = check_result; - return score->score; -} - -static const char *describe(struct manifest *m, void *check_result) -{ - struct score *score = check_result; - if (verbose) - return talloc_asprintf(m, "Wrong output running examples:\n" - "%s", score->errors); - return NULL; } +/* FIXME: Test with reduced features, valgrind! */ struct ccanlint examples_run = { - .key = "examples-run", + .key = "examples_run", .name = "Module examples with expected output give that output", - .score = score_examples, - .total_score = 3, /* This gets changed to # testable, if we run. */ .check = run_examples, - .describe = describe, .can_run = can_run, + .needs = "examples_compile" }; -REGISTER_TEST(examples_run, &examples_compile, NULL); +REGISTER_TEST(examples_run);