static char *skip_test(const char *testname, void *unused)
{
- btree_insert(cmdline_exclude, optarg);
+ btree_insert(cmdline_exclude, testname);
return NULL;
}
exit(0);
}
-static char *strip(const void *ctx, const char *line)
+static void test_dgraph_vertices(struct list_head *tests, const char *style)
{
- line += strcspn(line, IDENT_CHARS "-");
- return talloc_strndup(ctx, line, strspn(line, IDENT_CHARS "-"));
+ const struct ccanlint *i;
+
+ list_for_each(tests, i, list) {
+ /*
+ * todo: escape labels in case ccanlint test keys have
+ * characters interpreted as GraphViz syntax.
+ */
+ printf("\t\"%p\" [label=\"%s\"%s]\n", i, i->key, style);
+ }
+}
+
+static void test_dgraph_edges(struct list_head *tests)
+{
+ const struct ccanlint *i;
+ const struct dependent *d;
+
+ list_for_each(tests, i, list)
+ list_for_each(&i->dependencies, d, node)
+ printf("\t\"%p\" -> \"%p\"\n", d->dependent, i);
+}
+
+static char *test_dependency_graph(void *arg)
+{
+ puts("digraph G {");
+
+ test_dgraph_vertices(&compulsory_tests, ", style=filled, fillcolor=yellow");
+ test_dgraph_vertices(&normal_tests, "");
+
+ test_dgraph_edges(&compulsory_tests);
+ test_dgraph_edges(&normal_tests);
+
+ puts("}");
+
+ exit(0);
+}
+
+/* Remove empty lines. */
+static char **collapse(char **lines, unsigned int *nump)
+{
+ unsigned int i, j;
+ for (i = j = 0; lines[i]; i++) {
+ if (lines[i][0])
+ lines[j++] = lines[i];
+ }
+ if (nump)
+ *nump = j;
+ return lines;
}
-static void add_info_fails(struct ccan_file *info)
+static void add_info_options(struct ccan_file *info, bool mark_fails)
{
struct doc_section *d;
unsigned int i;
+ struct ccanlint *test;
list_for_each(get_ccan_file_docs(info), d, list) {
- if (!streq(d->type, "fails"))
+ if (!streq(d->type, "ccanlint"))
continue;
- for (i = 0; i < d->num_lines; i++)
- btree_insert(info_exclude, strip(info, d->lines[i]));
- break;
+ for (i = 0; i < d->num_lines; i++) {
+ char **words = collapse(strsplit(d, d->lines[i], " \t",
+ NULL), NULL);
+ if (!words[0])
+ continue;
+
+ if (strncmp(words[0], "//", 2) == 0)
+ continue;
+
+ test = find_test(words[0]);
+ if (!test) {
+ warnx("%s: unknown ccanlint test '%s'",
+ info->fullname, words[0]);
+ continue;
+ }
+
+ if (!words[1]) {
+ warnx("%s: no argument to test '%s'",
+ info->fullname, words[0]);
+ continue;
+ }
+
+ /* Known failure? */
+ if (strcasecmp(words[1], "FAIL") == 0) {
+ if (mark_fails)
+ btree_insert(info_exclude, words[0]);
+ } else {
+ if (!test->takes_options)
+ warnx("%s: %s doesn't take options",
+ info->fullname, words[0]);
+ /* Copy line exactly into options. */
+ test->options = strstr(d->lines[i], words[0])
+ + strlen(words[0]);
+ }
+ }
}
}
"do not compile anything");
opt_register_noarg("-l|--list-tests", list_tests, NULL,
"list tests ccanlint performs (and exit)");
+ opt_register_noarg("--test-dep-graph", test_dependency_graph, NULL,
+ "print dependency graph of tests in Graphviz .dot format");
opt_register_arg("-k|--keep <testname>", keep_test, NULL, NULL,
"keep results of <testname> (can be used multiple times)");
opt_register_noarg("--summary|-s", opt_set_bool, &summary,
test = find_test(target);
if (!test)
- err(1, "Unknown test to run '%s'", target);
+ errx(1, "Unknown test to run '%s'", target);
skip_unrelated_tests(test);
}
}
}
- /* --target overrides _info excludes */
- if (!target)
- add_info_fails(m->info_file);
+ /* --target overrides known FAIL from _info */
+ add_info_options(m->info_file, !target);
while ((i = get_next_test(&normal_tests)) != NULL)
run_test(i, summary, &score, &total_score, m);