Commit 016a19d2 authored by Rusty Russell's avatar Rusty Russell

ccanlint: list dependencies by key

Joey Adams also pointed out that we should use strings for the dependency
lists.  Moving them into the structure also somewhat simplifies it.
parent f9423c17
......@@ -20,7 +20,6 @@
#include "ccanlint.h"
#include "../tools.h"
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -192,30 +191,9 @@ static bool run_test(struct ccanlint *i,
return score->pass;
}
static void register_test(struct list_head *h, struct ccanlint *test, ...)
static void register_test(struct list_head *h, struct ccanlint *test)
{
va_list ap;
struct ccanlint *depends;
struct dependent *dchild;
list_add(h, &test->list);
va_start(ap, test);
/* Careful: we might have been initialized by a dependent. */
if (test->dependencies.n.next == NULL)
list_head_init(&test->dependencies);
//dependent(s) args (if any), last one is NULL
while ((depends = va_arg(ap, struct ccanlint *)) != NULL) {
dchild = malloc(sizeof(*dchild));
dchild->dependent = test;
/* The thing we depend on might not be initialized yet! */
if (depends->dependencies.n.next == NULL)
list_head_init(&depends->dependencies);
list_add_tail(&depends->dependencies, &dchild->node);
test->num_depends++;
}
va_end(ap);
}
/**
......@@ -235,78 +213,103 @@ static inline struct ccanlint *get_next_test(struct list_head *test)
errx(1, "Can't make process; test dependency cycle");
}
static struct ccanlint *find_test(const char *key)
{
struct ccanlint *i;
list_for_each(&compulsory_tests, i, list)
if (streq(i->key, key))
return i;
list_for_each(&normal_tests, i, list)
if (streq(i->key, key))
return i;
return NULL;
}
#undef REGISTER_TEST
#define REGISTER_TEST(name, ...) extern struct ccanlint name
#include "generated-normal-tests"
#include "generated-compulsory-tests"
static void init_tests(void)
{
const struct ccanlint *i;
struct ccanlint *c;
struct btree *keys, *names;
struct list_head *list;
#undef REGISTER_TEST
#define REGISTER_TEST(name, ...) register_test(&normal_tests, &name, __VA_ARGS__, NULL)
#define REGISTER_TEST(name) register_test(&normal_tests, &name)
#include "generated-normal-tests"
#undef REGISTER_TEST
#define REGISTER_TEST(name, ...) register_test(&compulsory_tests, &name, __VA_ARGS__, NULL)
#define REGISTER_TEST(name) register_test(&compulsory_tests, &name)
#include "generated-compulsory-tests"
/* Initialize dependency lists. */
foreach_ptr(list, &compulsory_tests, &normal_tests) {
list_for_each(list, c, list) {
list_head_init(&c->dependencies);
}
}
/* Resolve dependencies. */
foreach_ptr(list, &compulsory_tests, &normal_tests) {
list_for_each(list, c, list) {
char **deps = strsplit(NULL, c->needs, " ", NULL);
unsigned int i;
for (i = 0; deps[i]; i++) {
struct ccanlint *dep;
struct dependent *dchild;
dep = find_test(deps[i]);
if (!dep)
errx(1, "BUG: unknown dep '%s' for %s",
deps[i], c->key);
dchild = talloc(NULL, struct dependent);
dchild->dependent = c;
list_add_tail(&dep->dependencies,
&dchild->node);
c->num_depends++;
}
talloc_free(deps);
}
}
/* Self-consistency check: make sure no two tests
have the same key or name. */
keys = btree_new(btree_strcmp);
names = btree_new(btree_strcmp);
list_for_each(&compulsory_tests, i, list) {
if (!btree_insert(keys, i->key))
errx(1, "BUG: Duplicate test key '%s'", i->key);
if (!btree_insert(keys, i->name))
errx(1, "BUG: Duplicate test name '%s'", i->name);
}
list_for_each(&normal_tests, i, list) {
if (!btree_insert(keys, i->key))
errx(1, "BUG: Duplicate test key '%s'", i->key);
if (!btree_insert(keys, i->name))
errx(1, "BUG: Duplicate test name '%s'", i->name);
foreach_ptr(list, &compulsory_tests, &normal_tests) {
list_for_each(list, c, list) {
if (!btree_insert(keys, c->key))
errx(1, "BUG: Duplicate test key '%s'",
c->key);
if (!btree_insert(names, c->name))
errx(1, "BUG: Duplicate test name '%s'",
c->name);
}
}
btree_delete(keys);
btree_delete(names);
if (!verbose)
return;
printf("\nCompulsory Tests\n");
list_for_each(&compulsory_tests, i, list) {
printf("%s depends on %u others\n", i->name, i->num_depends);
if (!list_empty(&i->dependencies)) {
const struct dependent *d;
printf("These depend on us:\n");
list_for_each(&i->dependencies, d, node)
printf("\t%s\n", d->dependent->name);
}
}
foreach_ptr(list, &compulsory_tests, &normal_tests) {
printf("\%s Tests\n",
list == &compulsory_tests ? "Compulsory" : "Normal");
printf("\nNormal Tests\n");
list_for_each(&normal_tests, i, list) {
printf("%s depends on %u others\n", i->name, i->num_depends);
if (!list_empty(&i->dependencies)) {
if (!list_empty(&c->dependencies)) {
const struct dependent *d;
printf("These depend on us:\n");
list_for_each(&i->dependencies, d, node)
list_for_each(&c->dependencies, d, node)
printf("\t%s\n", d->dependent->name);
}
}
}
static struct ccanlint *find_test(const char *key)
{
struct ccanlint *i;
list_for_each(&compulsory_tests, i, list)
if (streq(i->key, key))
return i;
list_for_each(&normal_tests, i, list)
if (streq(i->key, key))
return i;
return NULL;
}
static char *keep_test(const char *testname, void *unused)
{
struct ccanlint *i = find_test(testname);
......
......@@ -4,11 +4,6 @@
#include <stdbool.h>
#include "../doc_extract.h"
#define REGISTER_TEST(name, ...) extern struct ccanlint name
#include "generated-compulsory-tests"
#include "generated-normal-tests"
#undef REGISTER_TEST
#define REGISTER_TEST(name, ...)
/* 0 == Describe failed tests.
......@@ -92,6 +87,9 @@ struct ccanlint {
/* If not set, we'll give an error if they try to set options. */
bool takes_options;
/* comma-separated list of dependency keys. */
const char *needs;
/* Internal use fields: */
/* Who depends on us? */
struct list_head dependencies;
......
......@@ -78,6 +78,7 @@ struct ccanlint build = {
.name = "Module can be built from object files",
.check = do_build,
.can_run = can_build,
.needs = "objects_build"
};
REGISTER_TEST(build, &build_objs, NULL);
REGISTER_TEST(build);
......@@ -62,6 +62,7 @@ struct ccanlint build_objs = {
.name = "Module object files can be built",
.check = check_objs_build,
.can_run = can_build,
.needs = "depends_exist"
};
REGISTER_TEST(build_objs, &depends_exist, NULL);
REGISTER_TEST(build_objs);
......@@ -88,6 +88,7 @@ struct ccanlint check_build = {
.name = "Module can be linked against trivial program",
.check = check_use_build,
.can_run = can_build,
.needs = "module_builds depends_build"
};
REGISTER_TEST(check_build, &build, &depends_built, NULL);
REGISTER_TEST(check_build);
......@@ -105,6 +105,7 @@ struct ccanlint depends_built = {
.name = "Module's CCAN dependencies can be found or built",
.check = check_depends_built,
.can_run = can_build,
.needs = "depends_exist"
};
REGISTER_TEST(depends_built, &depends_exist, NULL);
REGISTER_TEST(depends_built);
......@@ -72,6 +72,7 @@ struct ccanlint depends_exist = {
.key = "depends_exist",
.name = "Module's CCAN dependencies can be found",
.check = check_depends_exist,
.needs = "info_exists"
};
REGISTER_TEST(depends_exist, &has_info, NULL);
REGISTER_TEST(depends_exist);
......@@ -72,6 +72,7 @@ struct ccanlint includes_build = {
.name = "Modules main header compiles",
.check = check_includes_build,
.can_run = can_build,
.needs = "depends_exist main_header_exists"
};
REGISTER_TEST(includes_build, &depends_exist, &has_main_header, NULL);
REGISTER_TEST(includes_build);
......@@ -79,6 +79,7 @@ struct ccanlint has_info = {
.name = "Module has _info file",
.check = check_has_info,
.handle = create_info_template,
.needs = ""
};
REGISTER_TEST(has_info, NULL);
REGISTER_TEST(has_info);
......@@ -37,6 +37,7 @@ struct ccanlint has_main_header = {
.key = "main_header_exists",
.name = "Module has main header file",
.check = check_has_main_header,
.needs = ""
};
REGISTER_TEST(has_main_header, NULL);
REGISTER_TEST(has_main_header);
......@@ -147,6 +147,7 @@ struct ccanlint compile_coverage_tests = {
.name = "Module tests compile with " COVERAGE_CFLAGS,
.check = do_compile_coverage_tests,
.can_run = can_run_coverage,
.needs = "tests_compile"
};
REGISTER_TEST(compile_coverage_tests, &compile_tests, NULL);
REGISTER_TEST(compile_coverage_tests);
......@@ -69,6 +69,7 @@ struct ccanlint compile_test_helpers = {
.name = "Module test helper objects compile",
.check = do_compile_test_helpers,
.can_run = can_run,
.needs = "depends_build tests_exist"
};
REGISTER_TEST(compile_test_helpers, &depends_built, &has_tests, NULL);
REGISTER_TEST(compile_test_helpers);
......@@ -135,6 +135,7 @@ struct ccanlint compile_tests = {
.name = "Module tests compile",
.check = do_compile_tests,
.can_run = can_build,
.needs = "tests_helpers_compile objects_build"
};
REGISTER_TEST(compile_tests, &compile_test_helpers, &build_objs, NULL);
REGISTER_TEST(compile_tests);
......@@ -90,6 +90,7 @@ struct ccanlint depends_accurate = {
.key = "depends_accurate",
.name = "Module's CCAN dependencies are the only CCAN files #included",
.check = check_depends_accurate,
.needs = "depends_exist"
};
REGISTER_TEST(depends_accurate, &depends_exist, NULL);
REGISTER_TEST(depends_accurate);
......@@ -619,6 +619,7 @@ struct ccanlint examples_compile = {
.name = "Module examples compile",
.check = build_examples,
.can_run = can_run,
.needs = "examples_exist module_builds"
};
REGISTER_TEST(examples_compile, &has_examples, &build, NULL);
REGISTER_TEST(examples_compile);
......@@ -276,6 +276,7 @@ struct ccanlint examples_run = {
.name = "Module examples with expected output give that output",
.check = run_examples,
.can_run = can_run,
.needs = "examples_compile"
};
REGISTER_TEST(examples_run, &examples_compile, NULL);
REGISTER_TEST(examples_run);
......@@ -113,6 +113,7 @@ struct ccanlint has_examples = {
.key = "examples_exist",
.name = "_info and main header file have Example: sections",
.check = extract_examples,
.needs = "info_exists"
};
REGISTER_TEST(has_examples, &has_info, NULL);
REGISTER_TEST(has_examples);
......@@ -15,6 +15,8 @@
#include <ccan/noerr/noerr.h>
#include <ccan/grab_file/grab_file.h>
extern struct ccanlint has_info_documentation;
static void create_info_template_doc(struct manifest *m, struct score *score)
{
int fd = open("_info.new", O_WRONLY|O_CREAT|O_EXCL, 0666);
......@@ -94,6 +96,7 @@ struct ccanlint has_info_documentation = {
.key = "info_documentation_exists",
.name = "Module has documentation in _info",
.check = check_has_info_documentation,
.needs = "info_exists"
};
REGISTER_TEST(has_info_documentation, &has_info, NULL);
REGISTER_TEST(has_info_documentation);
......@@ -10,6 +10,8 @@
#include <err.h>
#include <ccan/talloc/talloc.h>
extern struct ccanlint has_tests;
static void handle_no_tests(struct manifest *m, struct score *score)
{
FILE *run;
......@@ -128,6 +130,7 @@ struct ccanlint has_tests = {
.key = "tests_exist",
.name = "Module has test directory with tests in it",
.check = check_has_tests,
.needs = ""
};
REGISTER_TEST(has_tests, NULL);
REGISTER_TEST(has_tests);
......@@ -198,6 +198,7 @@ struct ccanlint idempotent = {
.name = "Module headers are #ifndef/#define wrapped",
.check = check_idempotent,
.handle = handle_idem,
.needs = ""
};
REGISTER_TEST(idempotent, NULL);
REGISTER_TEST(idempotent);
......@@ -11,6 +11,8 @@
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
struct ccanlint has_license;
static struct doc_section *find_license(const struct manifest *m)
{
struct doc_section *d;
......@@ -151,6 +153,7 @@ struct ccanlint has_license = {
.key = "license_exists",
.name = "Module has License: entry in _info, and LICENSE symlink/file",
.check = check_has_license,
.needs = "info_exists"
};
REGISTER_TEST(has_license, &has_info, NULL);
REGISTER_TEST(has_license);
......@@ -166,6 +166,7 @@ struct ccanlint run_coverage_tests = {
.key = "tests_coverage",
.name = "Module's tests cover all the code",
.check = do_run_coverage_tests,
.needs = "tests_compile_coverage tests_pass"
};
REGISTER_TEST(run_coverage_tests, &compile_coverage_tests, &run_tests, NULL);
REGISTER_TEST(run_coverage_tests);
......@@ -71,6 +71,7 @@ struct ccanlint run_tests = {
.check = do_run_tests,
.handle = run_under_debugger,
.can_run = can_run,
.needs = "tests_compile"
};
REGISTER_TEST(run_tests, &compile_tests, NULL);
REGISTER_TEST(run_tests);
......@@ -17,6 +17,8 @@
#include <string.h>
#include <ctype.h>
struct ccanlint run_tests_vg;
/* Note: we already test safe_mode in run_tests.c */
static const char *can_run_vg(struct manifest *m)
{
......@@ -183,15 +185,17 @@ struct ccanlint run_tests_vg = {
.can_run = can_run_vg,
.check = do_run_tests_vg,
.handle = run_under_debugger_vg,
.takes_options = true
.takes_options = true,
.needs = "tests_pass"
};
REGISTER_TEST(run_tests_vg, &run_tests, NULL);
REGISTER_TEST(run_tests_vg);
struct ccanlint run_tests_vg_leak = {
.key = "tests_pass_valgrind_noleaks",
.name = "Module's run and api tests leak memory",
.check = do_leakcheck_vg,
.needs = "tests_pass_valgrind"
};
REGISTER_TEST(run_tests_vg_leak, &run_tests_vg, NULL);
REGISTER_TEST(run_tests_vg_leak);
......@@ -53,7 +53,8 @@ struct ccanlint trailing_whitespace = {
.key = "no_trailing_whitespace",
.name = "Module's source code has no trailing whitespace",
.check = check_trailing_whitespace,
.needs = ""
};
REGISTER_TEST(trailing_whitespace, NULL);
REGISTER_TEST(trailing_whitespace);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment