]> git.ozlabs.org Git - ccan/blobdiff - tools/ccanlint/ccanlint.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / tools / ccanlint / ccanlint.c
index 7747a4976e7cd1ea748191ff5246480806cb027b..237e412817d8f99ff44d9e68afeed050365d89b6 100644 (file)
 #include <ccan/tal/path/path.h>
 #include <ccan/strmap/strmap.h>
 
-struct ccanlint_map {
-       STRMAP_MEMBERS(struct ccanlint *);
-};
+typedef STRMAP(struct ccanlint *) ccanlint_map_t;
 
 int verbose = 0;
-static struct ccanlint_map tests;
+static ccanlint_map_t tests;
 bool safe_mode = false;
 bool keep_results = false;
+bool non_ccan_deps = false;
+bool build_failed = false;
 static bool targeting = false;
 static unsigned int timeout;
 
@@ -84,12 +84,12 @@ static bool skip_test(struct dgraph_node *node, const char *why)
        return true;
 }
 
-static const char *dep_failed(struct manifest *m)
+static const char *dep_failed(struct manifest *m UNNEEDED)
 {
        return "dependency couldn't run";
 }
 
-static bool cannot_run(struct dgraph_node *node, void *all)
+static bool cannot_run(struct dgraph_node *node, void *all UNNEEDED)
 {
        struct ccanlint *c = container_of(node, struct ccanlint, node);
        c->can_run = dep_failed;
@@ -98,7 +98,7 @@ static bool cannot_run(struct dgraph_node *node, void *all)
 }
 
 struct run_info {
-       bool quiet;
+       bool noninteractive;
        unsigned int score, total;
        struct manifest *m;
        const char *prefix;
@@ -165,7 +165,7 @@ static bool run_test(struct dgraph_node *n, struct run_info *run)
        }
 
        assert(score->score <= score->total);
-       if ((!score->pass && !run->quiet)
+       if (!score->pass
            || (score->score < score->total && verbose)
            || verbose > 1) {
                printf("%s%s (%s): %s",
@@ -176,13 +176,13 @@ static bool run_test(struct dgraph_node *n, struct run_info *run)
                printf("\n");
        }
 
-       if ((!run->quiet && !score->pass) || verbose) {
+       if (!score->pass || verbose) {
                if (score->error) {
                        printf("%s%s", score->error,
                               strends(score->error, "\n") ? "" : "\n");
                }
        }
-       if (!run->quiet && score->score < score->total && i->handle)
+       if (!run->noninteractive && score->score < score->total && i->handle)
                i->handle(run->m, score);
 
        if (!score->pass) {
@@ -215,7 +215,7 @@ static void register_test(struct ccanlint *test)
        dgraph_init_node(&test->node);
 }
 
-static bool get_test(const char *member, struct ccanlint *i,
+static bool get_test(const char *member UNNEEDED, struct ccanlint *i,
                     struct ccanlint **ret)
 {
        if (tlist_empty(&i->node.edge[DGRAPH_TO])) {
@@ -252,7 +252,8 @@ bool is_excluded(const char *name)
        return find_test(name)->skip != NULL;
 }
 
-static bool init_deps(const char *member, struct ccanlint *c, void *unused)
+static bool init_deps(const char *member UNNEEDED,
+                     struct ccanlint *c, void *unused UNNEEDED)
 {
        char **deps = tal_strsplit(NULL, c->needs, " ", STR_EMPTY_OK);
        unsigned int i;
@@ -270,8 +271,8 @@ static bool init_deps(const char *member, struct ccanlint *c, void *unused)
        return true;
 }
 
-static bool check_names(const char *member, struct ccanlint *c,
-                       struct ccanlint_map *names)
+static bool check_names(const char *member UNNEEDED, struct ccanlint *c,
+                       ccanlint_map_t *names)
 {
        if (!strmap_add(names, c->name, c))
                err(1, "Duplicate name %s", c->name);
@@ -280,7 +281,7 @@ static bool check_names(const char *member, struct ccanlint *c,
 
 static void init_tests(void)
 {
-       struct ccanlint_map names;
+       ccanlint_map_t names;
        struct ccanlint **table;
        size_t i, num;
 
@@ -299,7 +300,7 @@ static void init_tests(void)
        strmap_clear(&names);
 }
 
-static bool reset_test(struct dgraph_node *node, void *unused)
+static bool reset_test(struct dgraph_node *node, void *unused UNNEEDED)
 {
        struct ccanlint *c = container_of(node, struct ccanlint, node);
        c->skip = NULL;
@@ -312,7 +313,8 @@ static void reset_tests(struct dgraph_node *all)
        dgraph_traverse_to(all, reset_test, NULL);
 }
 
-static bool print_deps(const char *member, struct ccanlint *c, void *unused)
+static bool print_deps(const char *member UNNEEDED,
+                      struct ccanlint *c, void *unused UNNEEDED)
 {
        if (!tlist_empty(&c->node.edge[DGRAPH_FROM])) {
                struct dgraph_edge *e;
@@ -341,7 +343,7 @@ static void show_tmpdir(const char *dir)
        printf("You can find ccanlint working files in '%s'\n", dir);
 }
 
-static char *keep_tests(void *unused)
+static char *keep_tests(void *unused UNNEEDED)
 {
        keep_results = true;
 
@@ -359,7 +361,7 @@ static bool remove_test(struct dgraph_node *node, const char *why)
        return true;
 }
 
-static char *exclude_test(const char *testname, void *unused)
+static char *exclude_test(const char *testname, void *unused UNNEEDED)
 {
        struct ccanlint *i = find_test(testname);
        if (!i)
@@ -378,7 +380,7 @@ static void skip_test_and_deps(struct ccanlint *c, const char *why)
        skip_test(&c->node, why);
 }
 
-static char *list_tests(void *arg)
+static char *list_tests(void *arg UNNEEDED)
 {
        struct ccanlint *i;
 
@@ -392,7 +394,8 @@ static char *list_tests(void *arg)
        exit(0);
 }
 
-static bool draw_test(const char *member, struct ccanlint *c, const char *style)
+static bool draw_test(const char *member UNNEEDED,
+                     struct ccanlint *c, const char *style)
 {
        /*
         * todo: escape labels in case ccanlint test keys have
@@ -407,7 +410,8 @@ static void test_dgraph_vertices(const char *style)
        strmap_iterate(&tests, draw_test, style);
 }
 
-static bool draw_edges(const char *member, struct ccanlint *c, void *unused)
+static bool draw_edges(const char *member UNNEEDED,
+                      struct ccanlint *c, void *unused UNNEEDED)
 {
        struct dgraph_edge *e;
 
@@ -425,7 +429,7 @@ static void test_dgraph_edges(void)
        strmap_iterate(&tests, draw_edges, NULL);
 }
 
-static char *test_dependency_graph(void *arg)
+static char *test_dependency_graph(void *arg UNNEEDED)
 {
        puts("digraph G {");
 
@@ -452,50 +456,43 @@ static void add_options(struct ccanlint *test, char **options,
        memcpy(&test->options[num], options, (num_options + 1)*sizeof(char *));
 }
 
-void add_info_options(struct ccan_file *info)
+void add_info_options(struct manifest *m)
 {
-       struct doc_section *d;
        unsigned int i;
-       struct ccanlint *test;
+       char **info_options = get_ccanlint(m, m->dir, get_or_compile_info);
+
+       for (i = 0; info_options[i]; i++) {
+               char **words = tal_strsplit(m, info_options[i], " \t",
+                                           STR_NO_EMPTY);
+               struct ccanlint *test;
+
+               if (!words[0])
+                       continue;
+
+               test = find_test(words[0]);
+               if (!test) {
+                       warnx("%s: unknown ccanlint test '%s'",
+                             m->info_file->fullname, words[0]);
+                       continue;
+               }
 
-       list_for_each(get_ccan_file_docs(info), d, list) {
-               if (!streq(d->type, "ccanlint"))
+               if (!words[1]) {
+                       warnx("%s: no argument to test '%s'",
+                             m->info_file->fullname, words[0]);
                        continue;
+               }
 
-               for (i = 0; i < d->num_lines; i++) {
-                       char **words = tal_strsplit(d, d->lines[i], " \t",
-                                                   STR_NO_EMPTY);
-                       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 (!targeting)
-                                       skip_test_and_deps(test,
-                                                          "excluded in _info"
-                                                          " file");
-                       } else {
-                               if (!test->takes_options)
-                                       warnx("%s: %s doesn't take options",
-                                             info->fullname, words[0]);
-                               add_options(test, words+1, tal_count(words)-1);
-                       }
+               /* Known failure? */
+               if (strcasecmp(words[1], "FAIL") == 0) {
+                       if (!targeting)
+                               skip_test_and_deps(test,
+                                                  "excluded in _info"
+                                                  " file");
+               } else {
+                       if (!test->takes_options)
+                               warnx("%s: %s doesn't take options",
+                                     m->info_file->fullname, words[0]);
+                       add_options(test, words+1, tal_count(words)-1);
                }
        }
 }
@@ -556,24 +553,37 @@ static char *opt_set_target(const char *arg, struct dgraph_node *all)
 
 static bool run_tests(struct dgraph_node *all,
                      bool summary,
+                     bool deps_fail_ignore,
                      struct manifest *m,
                      const char *prefix)
 {
        struct run_info run;
+       const char *comment = "";
 
-       run.quiet = summary;
+       run.noninteractive = summary;
        run.m = m;
        run.prefix = prefix;
        run.score = run.total = 0;
        run.pass = true;
 
+       non_ccan_deps = build_failed = false;
+
        dgraph_traverse_to(all, run_test, &run);
 
-       printf("%sTotal score: %u/%u\n", prefix, run.score, run.total);
+       /* We can completely fail if we're missing external stuff: ignore */
+       if (deps_fail_ignore && non_ccan_deps && build_failed) {
+               comment = " (missing non-ccan dependencies?)";
+               run.pass = true;
+       } else if (!run.pass) {
+               comment = " FAIL!";
+       }
+       printf("%sTotal score: %u/%u%s\n",
+              prefix, run.score, run.total, comment);
+
        return run.pass;
 }
 
-static bool add_to_all(const char *member, struct ccanlint *c,
+static bool add_to_all(const char *member UNNEEDED, struct ccanlint *c,
                       struct dgraph_node *all)
 {
        /* If we're excluded on cmdline, don't add. */
@@ -583,7 +593,8 @@ static bool add_to_all(const char *member, struct ccanlint *c,
 }
 
 static bool test_module(struct dgraph_node *all,
-                       const char *dir, const char *prefix, bool summary)
+                       const char *dir, const char *prefix, bool summary,
+                       bool deps_fail_ignore)
 {
        struct manifest *m = get_manifest(autofree(), dir);
        char *testlink = path_join(NULL, temp_dir(), "test");
@@ -594,17 +605,18 @@ static bool test_module(struct dgraph_node *all,
        if (symlink(path_join(m, dir, "test"), testlink) != 0)
                err(1, "Creating test symlink in %s", temp_dir());
 
-       return run_tests(all, summary, m, prefix);
+       return run_tests(all, summary, deps_fail_ignore, m, prefix);
 }
 
 int main(int argc, char *argv[])
 {
-       bool summary = false, pass = true;
-       unsigned int i;
+       bool summary = false, pass = true, deps_fail_ignore = false;
+       int i;
        const char *prefix = "";
        char *cwd = path_cwd(NULL), *dir;
        struct ccanlint top;  /* cannot_run may try to set ->can_run */
        const char *override_compiler = NULL, *override_cflags = NULL;
+       const char *override_gcov = NULL;
        
        /* Empty graph node to which we attach everything else. */
        dgraph_init_node(&top.node);
@@ -620,7 +632,7 @@ int main(int argc, char *argv[])
        opt_register_noarg("-k|--keep", keep_tests, NULL,
                         "do not delete ccanlint working files");
        opt_register_noarg("--summary|-s", opt_set_bool, &summary,
-                          "simply give one line summary");
+                          "give results only, no interactive correction");
        opt_register_arg("-x|--exclude <testname>", exclude_test, NULL, NULL,
                         "exclude <testname> (can be used multiple times)");
        opt_register_arg("--timeout <milleseconds>", opt_set_uintval,
@@ -633,6 +645,11 @@ int main(int argc, char *argv[])
                         NULL, &override_compiler, "set the compiler");
        opt_register_arg("--cflags <flags>", opt_set_const_charp,
                         NULL, &override_cflags, "set the compiler flags");
+       opt_register_arg("--gcov <coverage tool>", opt_set_const_charp,
+                        NULL, &override_gcov, "set the coverage tool");
+       opt_register_noarg("--deps-fail-ignore", opt_set_bool,
+                          &deps_fail_ignore,
+                          "don't fail if external dependencies are missing");
        opt_register_noarg("-?|-h|--help", opt_usage_and_exit,
                           "\nA program for checking and guiding development"
                           " of CCAN modules.",
@@ -662,7 +679,7 @@ int main(int argc, char *argv[])
        if (argc == 1)
                dir = cwd;
        else
-               dir = path_join(NULL, cwd, argv[1]);
+               dir = path_simplify(NULL, take(path_join(NULL, cwd, argv[1])));
 
        ccan_dir = find_ccan_dir(dir);
        if (!ccan_dir)
@@ -674,9 +691,12 @@ int main(int argc, char *argv[])
                cflags = override_cflags;
        if (override_compiler)
                compiler = override_compiler;
+       if (override_gcov)
+               gcov = override_gcov;
 
        if (argc == 1)
-               pass = test_module(&top.node, cwd, "", summary);
+               pass = test_module(&top.node, cwd, "",
+                                  summary, deps_fail_ignore);
        else {
                for (i = 1; i < argc; i++) {
                        dir = path_canon(NULL,
@@ -689,7 +709,8 @@ int main(int argc, char *argv[])
                        prefix = path_rel(NULL, take(prefix), dir);
                        prefix = tal_strcat(NULL, take(prefix), ": ");
 
-                       pass &= test_module(&top.node, dir, prefix, summary);
+                       pass &= test_module(&top.node, dir, prefix, summary,
+                                           deps_fail_ignore);
                        reset_tests(&top.node);
                }
        }