author Rusty Russell Tue, 9 Nov 2010 02:44:39 +0000 (13:14 +1030) committer Rusty Russell Tue, 9 Nov 2010 02:44:39 +0000 (13:14 +1030)
Previously each check returned a void *, but in fact most of them fell into
similar patterns.  So define 'struct score' and a helper to add files to it,
and use that.

Under these rules, you get 0/1 if you skip a test because a dependency failed
which in theory means your score (as a percentage) could drop if you fix
a test.

25 files changed:

@@ -88,30 +88,37 @@ static const char *should_skip(struct manifest *m, struct ccanlint *i)

static bool run_test(struct ccanlint *i,
bool quiet,
-                    unsigned int *score,
-                    unsigned int *total_score,
+                    unsigned int *running_score,
+                    unsigned int *running_total,
struct manifest *m)
{
-       void *result;
-       unsigned int this_score, max_score, timeleft;
+       unsigned int timeleft;
const struct dependent *d;
const char *skip;
+       struct score *score;

//one less test to run through
list_for_each(&i->dependencies, d, node)
d->dependent->num_depends--;

+       score = talloc(m, struct score);
+       score->error = NULL;
+       score->pass = false;
+       score->score = 0;
+       score->total = 1;
+
skip = should_skip(m, i);

if (skip) {
skip:
if (verbose && !streq(skip, "not relevant to target"))
-                       printf("  %s: skipped (%s)\n", i->name, skip);
+                       printf("%s: skipped (%s)\n", i->name, skip);

-               /* If we're skipping this because a prereq failed, we fail. */
+               /* If we're skipping this because a prereq failed, we fail:
+                * count it as a score of 1. */
if (i->skip_fail)
-                       *total_score += i->total_score;
+                       (*running_total)++;

list_del(&i->list);
@@ -121,55 +128,52 @@ static bool run_test(struct ccanlint *i,
d->dependent->skip = "dependency was skipped";
d->dependent->skip_fail = i->skip_fail;
}
-               return true;
+               return i->skip_fail ? false : true;
}

timeleft = timeout ? timeout : default_timeout_ms;
-       result = i->check(m, i->keep_results, &timeleft);
+       i->check(m, i->keep_results, &timeleft, score);
if (timeout && timeleft == 0) {
skip = "timeout";
goto skip;
}

-       max_score = i->total_score;
-       if (!max_score)
-               max_score = 1;
-
-       if (!result)
-               this_score = max_score;
-       else if (i->score)
-               this_score = i->score(m, result);
-       else
-               this_score = 0;
-
-       bad = (this_score == 0);
-       good = (this_score >= max_score);
-
-       if (verbose || (!good && !quiet)) {
-               printf("  %s: %s", i->name,
-                      bad ? "FAIL" : good ? "PASS" : "PARTIAL");
-               if (max_score > 1)
-                       printf(" (+%u/%u)", this_score, max_score);
+       assert(score->score <= score->total);
+       if ((!score->pass && !quiet)
+           || (score->score < score->total && verbose)
+           || verbose > 1) {
+               printf("%s: %s", i->name, score->pass ? "PASS" : "FAIL");
+               if (score->total > 1)
+                       printf(" (+%u/%u)", score->score, score->total);
printf("\n");
}

-       if (!quiet && result) {
-               const char *desc;
-               if (i->describe && (desc = i->describe(m, result)) != NULL)
-                       printf("    %s\n", desc);
+       if (!quiet && !score->pass) {
+               struct file_error *f;
+
+               if (score->error)
+                       printf("%s:\n", score->error);
+
+               list_for_each(&score->per_file_errors, f, list) {
+                       if (f->line)
+                               printf("%s:%u:%s\n",
+                                      f->file->fullname, f->line, f->error);
+                       else if (f->file)
+                               printf("%s:%s\n", f->file->fullname, f->error);
+                       else
+                               printf("%s\n", f->error);
+               }
if (i->handle)
-                       i->handle(m, result);
+                       i->handle(m, score);
}

-       if (i->total_score) {
-               *score += this_score;
-               *total_score += i->total_score;
-       }
+       *running_score += score->score;
+       *running_total += score->total;

list_del(&i->list);

+       if (!score->pass) {
/* Skip any tests which depend on this one. */
list_for_each(&i->dependencies, d, node) {
if (d->dependent->skip)
@@ -178,7 +182,7 @@ static bool run_test(struct ccanlint *i,
d->dependent->skip_fail = true;
}
}
-       return good;
+       return score->pass;
}

static void register_test(struct list_head *h, struct ccanlint *test, ...)
@@ -451,9 +455,6 @@ int main(int argc, char *argv[])
}

/* If you don't pass the compulsory tests, you get a score of 0. */
-       if (verbose)
-               printf("Compulsory tests:\n");
-
while ((i = get_next_test(&compulsory_tests)) != NULL) {
if (!run_test(i, summary, &score, &total_score, m)) {
printf("%sTotal score: 0/%u\n", prefix, total_score);
@@ -462,9 +463,6 @@ int main(int argc, char *argv[])
}

-
-       if (verbose)
-               printf("\nNormal tests:\n");
while ((i = get_next_test(&normal_tests)) != NULL)
run_test(i, summary, &score, &total_score, m);

index 8c2ee0e8826b5ff0ba974f888f879a6953721e8e..0e57140018ffee1693bbf3f1010dd622316e1335 100644 (file)
@@ -42,6 +42,20 @@ struct manifest {

struct manifest *get_manifest(const void *ctx, const char *dir);

+struct file_error {
+       struct list_node list;
+       struct ccan_file *file;
+       unsigned int line; /* 0 not to print */
+       const char *error;
+};
+
+struct score {
+       bool pass;
+       unsigned int score, total;
+       const char *error;
+};
+
struct ccanlint {
struct list_node list;

@@ -51,27 +65,18 @@ struct ccanlint {
/* Unique name of test */
const char *name;

-       /* Total score that this test is worth. */
-       unsigned int total_score;
-
/* Can we run this test?  Return string explaining why, if not. */
const char *(*can_run)(struct manifest *m);

-       /* If this returns non-NULL, it means the check failed.
-        * keep is set if you should keep the results.
-        * If timeleft is set to 0, means it timed out. */
-       void *(*check)(struct manifest *m, bool keep, unsigned int *timeleft);
-
-       /* The non-NULL return from check is passed to one of these: */
-
-       /* So, what did this get out of the total_score?  (NULL means 0). */
-       unsigned int (*score)(struct manifest *m, void *check_result);
-
-       /* Verbose description of what was wrong. */
-       const char *(*describe)(struct manifest *m, void *check_result);
+       /* keep is set if you should keep the results.
+        * If timeleft is set to 0, means it timed out.
+        * score is the result, and a talloc context freed after all our
+        * depends are done. */
+       void (*check)(struct manifest *m,
+                     bool keep, unsigned int *timeleft, struct score *score);

/* Can we do something about it? (NULL if not) */
-       void (*handle)(struct manifest *m, void *check_result);
+       void (*handle)(struct manifest *m, struct score *score);

/* Internal use fields: */
/* Who depends on us? */
@@ -184,11 +189,9 @@ char *get_symbol_token(void *ctx, const char **line);

-/* Call the reporting on every line in the file.  sofar contains
- * previous results. */
-                     char *(*report)(const char *),
-                     char *sofar);
+/* Add an error about this file (and line, if non-zero) to the score struct */
+void score_file_error(struct score *, struct ccan_file *f, unsigned line,
+                     const char *error);

/* Normal tests. */
extern struct ccanlint trailing_whitespace;
index c78e500b238f4e0953e7084f46a36deba03c0f44..7c73f0d4f834c98519dc68ff18420cb935d4d6cc 100644 (file)
@@ -33,42 +33,41 @@ static char *obj_list(const struct manifest *m)
return list;
}

-static void *do_build(struct manifest *m,
-                     bool keep,
-                     unsigned int *timeleft)
+static void do_build(struct manifest *m,
+                    bool keep,
+                    unsigned int *timeleft,
+                    struct score *score)
{
-       char *filename, *err;
+       char *filename, *errstr;

if (list_empty(&m->c_files)) {
/* No files?  No score, but we "pass". */
-               build.total_score = 0;
-               return NULL;
+               score->total = 0;
+               score->pass = true;
+               return;
}
-       filename = link_objects(m, m->basename, false, obj_list(m), &err);
-       if (filename && keep) {
+
+       filename = link_objects(m, m->basename, false, obj_list(m), &errstr);
+       if (!filename) {
+               score->error = "The object file didn't build";
+               score_file_error(score, NULL, 0, errstr);
+               return;
+       }
+
+       if (keep) {
char *realname = talloc_asprintf(m, "%s.o", m->dir);
/* We leave this object file around, all built. */
if (!move_file(filename, realname))
-                       return talloc_asprintf(m, "Failed to rename %s to %s",
-                                              filename, realname);
-               return NULL;
+                       err(1, "Renaming %s to %s", filename, realname);
}
-       return err;
-}
-
-static const char *describe_build(struct manifest *m, void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "The object file for the module didn't build:\n"
-                              "%s", (char *)check_result);
+       score->pass = true;
+       score->score = score->total;
}

struct ccanlint build = {
.key = "build",
.name = "Module can be built from object files",
-       .total_score = 1,
.check = do_build,
-       .describe = describe_build,
.can_run = can_build,
};

index af7a57b73e8482c18f627abfe5d2e0e814222764..aa8e7b36a5ebce098d9967d359eb86147395cf8e 100644 (file)
@@ -21,42 +21,37 @@ static const char *can_build(struct manifest *m)
return NULL;
}

-static void *check_objs_build(struct manifest *m,
-                             bool keep, unsigned int *timeleft)
+static void check_objs_build(struct manifest *m,
+                            bool keep,
+                            unsigned int *timeleft, struct score *score)
{
-       char *report = NULL;
struct ccan_file *i;

+       if (list_empty(&m->c_files))
+               score->total = 0;
+
list_for_each(&m->c_files, i, list) {
char *err;
char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);

-               /* One point for each obj file. */
-               build_objs.total_score++;
-
i->compiled = maybe_temp_file(m, "", keep, fullfile);
err = compile_object(m, fullfile, ccan_dir, "", i->compiled);
if (err) {
talloc_free(i->compiled);
-                       if (report)
-                               report = talloc_append_string(report, err);
-                       else
-                               report = err;
+                       score->error = "Compiling object files";
+                       score_file_error(score, i, 0, err);
}
}
-       return report;
-}
-
-static const char *describe_objs_build(struct manifest *m, void *check_result)
-{
-       return check_result;
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint build_objs = {
.key = "build-objects",
.name = "Module object files can be built",
.check = check_objs_build,
-       .describe = describe_objs_build,
.can_run = can_build,
};

index 42eda13ae56aede90e2fd9df85927e9a1260129c..9175b91835f5bb2271f6e645d9040038030c8663 100644 (file)
@@ -45,9 +45,9 @@ static char *lib_list(const struct manifest *m)
return ret;
}

-static void *check_use_build(struct manifest *m,
-                            bool keep,
-                            unsigned int *timeleft)
+static void check_use_build(struct manifest *m,
+                           bool keep,
+                           unsigned int *timeleft, struct score *score)
{
char *contents;
char *tmpfile;
@@ -58,8 +58,7 @@ static void *check_use_build(struct manifest *m,

fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0)
-               return talloc_asprintf(m, "Creating temporary file: %s",
-                                      strerror(errno));
+               err(1, "Creating temporary file %s", tmpfile);

contents = talloc_asprintf(tmpfile,
"#include <ccan/%s/%s.h>\n"
@@ -68,30 +67,23 @@ static void *check_use_build(struct manifest *m,
"    return 0;\n"
"}\n",
m->basename, m->basename);
-       if (write(fd, contents, strlen(contents)) != strlen(contents)) {
-               close(fd);
-               return "Failure writing to temporary file";
-       }
+       if (write(fd, contents, strlen(contents)) != strlen(contents))
+               err(1, "Failure writing to temporary file %s", tmpfile);
close(fd);

-       return compile_and_link(m, tmpfile, ccan_dir, obj_list(m), "",
-                               lib_list(m),
-                               maybe_temp_file(m, "", keep, tmpfile));
-}
-
-static const char *describe_use_build(struct manifest *m, void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "%s", (char *)check_result);
+       score->error = compile_and_link(m, tmpfile, ccan_dir, obj_list(m), "",
+                                       lib_list(m),
+                                       maybe_temp_file(m, "", keep, tmpfile));
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint check_build = {
.name = "Module can be linked against trivial program",
-       .total_score = 1,
.check = check_use_build,
-       .describe = describe_use_build,
.can_run = can_build,
};

index 04ef54eb2c79a0060d5b0a43982653b4c671004a..41e5d8885e52aea5026d73d426c10eee9c592e99 100644 (file)
@@ -35,13 +35,12 @@ static bool expect_obj_file(const char *dir)
return has_c_files;
}

-static void *check_depends_built(struct manifest *m,
-                                bool keep,
-                                unsigned int *timeleft)
+static void check_depends_built(struct manifest *m,
+                               bool keep,
+                               unsigned int *timeleft, struct score *score)
{
struct ccan_file *i;
struct stat st;
-       char *report = NULL;

list_for_each(&m->dep_dirs, i, list) {
if (!expect_obj_file(i->fullname))
@@ -49,9 +48,11 @@ static void *check_depends_built(struct manifest *m,

i->compiled = talloc_asprintf(i, "%s.o", i->fullname);
if (stat(i->compiled, &st) != 0) {
-                       report = talloc_asprintf_append(report,
-                                                       "object file %s\n",
-                                                       i->compiled);
+                       score->error = "Dependencies are not built";
+                       score_file_error(score, i, 0,
+                                        talloc_asprintf(score,
+                                                       "object file %s",
+                                                        i->compiled));
i->compiled = NULL;
}
}
@@ -61,30 +62,21 @@ static void *check_depends_built(struct manifest *m,
&& (!list_empty(&m->run_tests) || !list_empty(&m->api_tests))) {
char *tapobj = talloc_asprintf(m, "%s/ccan/tap.o", ccan_dir);
if (stat(tapobj, &st) != 0) {
-                       report = talloc_asprintf_append(report,
-                                                       "object file %s"
-                                                       " (for tests)\n",
-                                                       tapobj);
+                       score->error = talloc_asprintf(score,
+                                              "tap object file not built");
}
}

-       return talloc_steal(m, report);
-}
-
-static const char *describe_depends_built(struct manifest *m,
-                                         void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "The following dependencies are not built:\n"
-                              "%s", (char *)check_result);
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint depends_built = {
.key = "depends-built",
.name = "Module's CCAN dependencies are already built",
-       .total_score = 1,
.check = check_depends_built,
-       .describe = describe_depends_built,
.can_run = can_build,
};

#include <string.h>
#include <ctype.h>

-static char *add_dep(char *sofar, struct manifest *m, const char *dep)
+static void add_dep(struct manifest *m, const char *dep, struct score *score)
{
struct stat st;
struct ccan_file *f;

f = new_ccan_file(m, ccan_dir, talloc_strdup(m, dep));
if (stat(f->fullname, &st) != 0) {
-               return talloc_asprintf_append(sofar,
-                                             "ccan/%s: expected it in"
-                                             " directory %s\n",
-                                             dep, f->fullname);
-       }
-
-       return sofar;
+               score->error = "Depends don't exist";
+               score_file_error(score, f, 0, "could not stat");
+       } else
}

-static void *check_depends_exist(struct manifest *m,
-                                bool keep,
-                                unsigned int *timeleft)
+static void check_depends_exist(struct manifest *m,
+                               bool keep,
+                               unsigned int *timeleft, struct score *score)
{
unsigned int i;
-       char *report = NULL;
char **deps;
char *updir = talloc_strdup(m, m->dir);

@@ -52,25 +47,18 @@ static void *check_depends_exist(struct manifest *m,
if (!strstarts(deps[i], "ccan/"))
continue;

-               report = add_dep(report, m, deps[i]);
+       }
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
}
-       return report;
-}
-
-static const char *describe_depends_exist(struct manifest *m,
-                                         void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "The following dependencies are are expected:\n"
-                              "%s", (char *)check_result);
}

struct ccanlint depends_exist = {
.key = "depends-exist",
.name = "Module's CCAN dependencies are present",
-       .total_score = 1,
.check = check_depends_exist,
-       .describe = describe_depends_exist,
};

REGISTER_TEST(depends_exist, NULL);
index 79d10d29775d65c7fa3a7e2695c113429ff17d35..cc5edc4ccaabbf2525b9072a4e64da3ceef6d02f 100644 (file)
@@ -32,12 +32,12 @@ static struct ccan_file *main_header(struct manifest *m)
return f;
}
/* Should not happen: we depend on has_main_header */
-       return NULL;
+       abort();
}

-static void *check_includes_build(struct manifest *m,
-                                 bool keep,
-                                 unsigned int *timeleft)
+static void check_includes_build(struct manifest *m,
+                                bool keep,
+                                unsigned int *timeleft, struct score *score)
{
char *contents;
char *tmpsrc, *tmpobj;
@@ -49,34 +49,29 @@ static void *check_includes_build(struct manifest *m,

fd = open(tmpsrc, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0)
-               return talloc_asprintf(m, "Creating temporary file %s: %s",
-                                      tmpsrc, strerror(errno));
+               err(1, "Creating temporary file %s", tmpsrc);

contents = talloc_asprintf(tmpsrc, "#include <ccan/%s/%s.h>\n",
m->basename, m->basename);
-       if (write(fd, contents, strlen(contents)) != strlen(contents)) {
-               close(fd);
-               return "Failure writing to temporary file";
-       }
+       if (write(fd, contents, strlen(contents)) != strlen(contents))
+               err(1, "writing to temporary file %s", tmpsrc);
close(fd);

-       return compile_object(m, tmpsrc, ccan_dir, "", tmpobj);
-}
-
-static const char *describe_includes_build(struct manifest *m,
-                                          void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "#include of the main header file:\n"
-                              "%s", (char *)check_result);
+       score->error = compile_object(m, tmpsrc, ccan_dir, "", tmpobj);
+       if (score->error) {
+               score->error = talloc_asprintf(score,
+                                      "#include of the main header file:\n%s",
+                                      score->error);
+       } else {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint includes_build = {
.key = "include-main",
.name = "Modules main header compiles",
-       .total_score = 1,
.check = check_includes_build,
-       .describe = describe_includes_build,
.can_run = can_build,
};

index 77867dedd9c875ff22bcc4f42c7886065bd99265..ce131f85686ec88111c1b0ea709a04c77fbbcc50 100644 (file)
#include <ccan/noerr/noerr.h>
#include <ccan/talloc/talloc.h>

-static void *check_has_info(struct manifest *m,
-                           bool keep,
-                           unsigned int *timeleft)
+static void check_has_info(struct manifest *m,
+                          bool keep,
+                          unsigned int *timeleft,
+                          struct score *score)
{
-       if (m->info_file)
-               return NULL;
-       return m;
-}
-
-static const char *describe_has_info(struct manifest *m, void *check_result)
-{
-       return "You have no _info file.\n\n"
+       if (m->info_file) {
+               score->pass = true;
+               score->score = score->total;
+       } else {
+               score->error = "You have no _info file.\n\n"
"The file _info contains the metadata for a ccan package: things\n"
"like the dependencies, the documentation for the package as a whole\n"
+       }
}

static const char template[] =
@@ -55,7 +54,7 @@ static const char template[] =
"       return 1;\n"
"}\n";

-static void create_info_template(struct manifest *m, void *check_result)
+static void create_info_template(struct manifest *m, struct score *score)
{
FILE *info;
const char *filename;
@@ -79,7 +78,6 @@ struct ccanlint has_info = {
.key = "info",
.name = "Module has _info file",
.check = check_has_info,
-       .describe = describe_has_info,
.handle = create_info_template,
};

index eb74e9f0101b016a577e98218428cd4e7e97cff6..bce6ef485a2b448778e0aefd69742e426ce243b7 100644 (file)
#include <ccan/talloc/talloc.h>
#include <ccan/noerr/noerr.h>

-                                  bool keep,
-                                  unsigned int *timeleft)
+                                 bool keep,
+                                 unsigned int *timeleft, struct score *score)
{
struct ccan_file *f;

list_for_each(&m->h_files, f, list) {
if (strstarts(f->name, m->basename)
-                   && strlen(f->name) == strlen(m->basename) + 2)
-                       return NULL;
+                   && strlen(f->name) == strlen(m->basename) + 2) {
+                       score->pass = true;
+                       score->score = score->total;
+                       return;
+               }
}
-       return m;
-}
-
-static const char *describe_has_main_header(struct manifest *m,
-                                           void *check_result)
-{
-       return talloc_asprintf(m,
+       score->error = talloc_asprintf(score,
"You have no %s/%s.h header file.\n\n"
"CCAN modules have a name, the same as the directory name.  They're\n"
"expected to have an interface in the header of the same name.\n",
-                              m->basename, m->basename);
+                                      m->basename, m->basename);
}

.name = "Module has main header file",
};

index b83e877e0455f6c3006537c90ea023e0034b2aaf..f58dddf241b377c5d99a433abfb5df4e765955a4 100644 (file)
@@ -139,30 +139,6 @@ static void add_files(struct manifest *m, const char *dir)
closedir(d);
}

-                     char *(*report)(const char *),
-                     char *sofar)
-{
-       struct ccan_file *f;
-
-       list_for_each(files, f, list) {
-               unsigned int i;
-               char **lines = get_ccan_file_lines(f);
-
-               for (i = 0; i < f->num_lines; i++) {
-                       char *r = report(lines[i]);
-                       if (!r)
-                               continue;
-
-                       sofar = talloc_asprintf_append(sofar,
-                                                      "%s:%u:%s\n",
-                                                      f->name, i+1, r);
-                       talloc_free(r);
-               }
-       }
-       return sofar;
-}
-
struct manifest *get_manifest(const void *ctx, const char *dir)
{
struct manifest *m = talloc(ctx, struct manifest);
@@ -574,3 +550,12 @@ enum line_compiled get_ccan_line_pp(struct pp_conditions *cond,
return ret;
}

+void score_file_error(struct score *score, struct ccan_file *f, unsigned line,
+                     const char *error)
+{
+       struct file_error *fe = talloc(score, struct file_error);
+       fe->file = f;
+       fe->line = line;
+       fe->error = error;
+}
index 98f7948d750b8af20aefce59d5a38c86093e3505..edb3cb22f95f58558ea2910f75a028fef15ec2e2 100644 (file)
@@ -25,8 +25,9 @@ static const char *can_run_coverage(struct manifest *m)
return NULL;
}

-static char *build_module_objs_with_coverage(struct manifest *m, bool keep,
-                                            char **modobjs)
+static bool build_module_objs_with_coverage(struct manifest *m, bool keep,
+                                           struct score *score,
+                                           char **modobjs)
{
struct ccan_file *i;

@@ -39,13 +40,15 @@ static char *build_module_objs_with_coverage(struct manifest *m, bool keep,
err = compile_object(m, fullfile, ccan_dir, "",
i->cov_compiled);
if (err) {
+                       score_file_error(score, i, 0, err);
talloc_free(i->cov_compiled);
-                       return err;
+                       i->cov_compiled = NULL;
+                       return false;
}
*modobjs = talloc_asprintf_append(*modobjs,
" %s", i->cov_compiled);
}
-       return NULL;
+       return true;
}

static char *obj_list(const struct manifest *m, const char *modobjs)
@@ -101,97 +104,53 @@ static char *cov_compile(const void *ctx,
lib_list(m), file->cov_compiled);
if (errmsg) {
talloc_free(file->cov_compiled);
+               file->cov_compiled = NULL;
return errmsg;
}

return NULL;
}

-struct compile_tests_result {
-       struct list_node list;
-       const char *filename;
-       const char *description;
-       const char *output;
-};
-
-static void *do_compile_coverage_tests(struct manifest *m,
-                                      bool keep,
-                                      unsigned int *timeleft)
+/* FIXME: Coverage from testable examples as well. */
+static void do_compile_coverage_tests(struct manifest *m,
+                                     bool keep,
+                                     unsigned int *timeleft,
+                                     struct score *score)
{
char *cmdout, *modobjs = NULL;
struct ccan_file *i;
-       struct compile_tests_result *res;

-
-       if (!list_empty(&m->api_tests)) {
-               cmdout = build_module_objs_with_coverage(m, keep, &modobjs);
-               if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = "Module objects with coverage";
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
-                       return list;
-               }
+       if (!list_empty(&m->api_tests)
+           && !build_module_objs_with_coverage(m, keep, score, &modobjs)) {
+               score->error = "Failed to compile module objects with coverage";
+               return;
}

list_for_each(&m->run_tests, i, list) {
-               compile_tests.total_score++;
cmdout = cov_compile(m, m, i, NULL, keep);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
+                       score->error = "Failed to compile test with coverage";
+                       score_file_error(score, i, 0, cmdout);
}
}

list_for_each(&m->api_tests, i, list) {
-               compile_tests.total_score++;
cmdout = cov_compile(m, m, i, modobjs, keep);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
+                       score->error = "Failed to compile test with coverage";
+                       score_file_error(score, i, 0, cmdout);
}
}
-
-       if (list_empty(list)) {
-               talloc_free(list);
-               list = NULL;
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
}
-
-       return list;
-}
-
-static const char *describe_compile_coverage_tests(struct manifest *m,
-                                                  void *check_result)
-{
-       struct list_head *list = check_result;
-       struct compile_tests_result *i;
-       char *descrip;
-
-       descrip = talloc_strdup(list,
-                               "Compilation of tests for coverage failed:\n");
-
-       list_for_each(list, i, list)
-               descrip = talloc_asprintf_append(descrip, "%s %s\n%s",
-                                                i->filename, i->description,
-                                                i->output);
-       return descrip;
}

struct ccanlint compile_coverage_tests = {
.key = "compile-coverage-tests",
.name = "Module tests compile with profiling",
.check = do_compile_coverage_tests,
-       .total_score = 1,
-       .describe = describe_compile_coverage_tests,
.can_run = can_run_coverage,
};

@@ -14,7 +14,7 @@
#include <string.h>
#include <ctype.h>

-static const char *can_build(struct manifest *m)
+static const char *can_run(struct manifest *m)
{
if (safe_mode)
return "Safe mode enabled";
@@ -30,39 +30,35 @@ static char *compile(struct manifest *m,
cfile->compiled);
}

-static void *do_compile_test_helpers(struct manifest *m,
-                                    bool keep,
-                                    unsigned int *timeleft)
+static void do_compile_test_helpers(struct manifest *m,
+                                   bool keep,
+                                   unsigned int *timeleft,
+                                   struct score *score)
{
-       char *cmdout = NULL;
struct ccan_file *i;

-       compile_tests.total_score = 0;
+       if (list_empty(&m->other_test_c_files))
+               score->total = 0;
+
list_for_each(&m->other_test_c_files, i, list) {
-               compile_tests.total_score++;
-               cmdout = compile(m, keep, i);
-               if (cmdout)
-                       return talloc_asprintf(m,
-                                              "Failed to compile helper C"
-                                              " code file %s:\n%s",
-                                              i->name, cmdout);
+               char *cmdout = compile(m, keep, i);
+               if (cmdout) {
+                       score->error = "Failed to compile helper C files";
+                       score_file_error(score, i, 0, cmdout);
+               }
}
-       return NULL;
-}

-static const char *describe_compile_test_helpers(struct manifest *m,
-                                                void *check_result)
-{
-       return check_result;
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint compile_test_helpers = {
.key = "compile-helpers",
.name = "Module test helper objects compile",
-       .total_score = 1,
.check = do_compile_test_helpers,
-       .describe = describe_compile_test_helpers,
-       .can_run = can_build,
+       .can_run = can_run,
};

REGISTER_TEST(compile_test_helpers, &depends_built, &has_tests, NULL);
index 3d6d3881883d5494bffa504050faea9172ab0ca6..062912d427ea3bb49e2b22a71cca94082c606df3 100644 (file)
@@ -82,124 +82,64 @@ static char *compile(const void *ctx,
return NULL;
}

-struct compile_tests_result {
-       struct list_node list;
-       const char *filename;
-       const char *description;
-       const char *output;
-};
-
-static void *do_compile_tests(struct manifest *m,
-                             bool keep,
-                             unsigned int *timeleft)
+static void do_compile_tests(struct manifest *m,
+                            bool keep,
+                            unsigned int *timeleft, struct score *score)
{
char *cmdout;
struct ccan_file *i;
-       struct compile_tests_result *res;

-
-       compile_tests.total_score = 0;
list_for_each(&m->compile_ok_tests, i, list) {
-               compile_tests.total_score++;
-               cmdout = compile(list, m, i, false, false, keep);
+               cmdout = compile(score, m, i, false, false, keep);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
+                       score->error = "Failed to compile tests";
+                       score_file_error(score, i, 0, cmdout);
}
}

list_for_each(&m->run_tests, i, list) {
-               compile_tests.total_score++;
-               cmdout = compile(m, m, i, false, false, keep);
+               cmdout = compile(score, m, i, false, false, keep);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
+                       score->error = "Failed to compile tests";
+                       score_file_error(score, i, 0, cmdout);
}
}

list_for_each(&m->api_tests, i, list) {
-               compile_tests.total_score++;
-               cmdout = compile(m, m, i, false, true, keep);
+               cmdout = compile(score, m, i, false, true, keep);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile";
-                       res->output = talloc_steal(res, cmdout);
+                       score->error = "Failed to compile tests";
+                       score_file_error(score, i, 0, cmdout);
}
}

+       /* The compile fail tests are a bit weird, handle them separately */
+       if (score->error)
+               return;
+
list_for_each(&m->compile_fail_tests, i, list) {
-               compile_tests.total_score++;
-               cmdout = compile(list, m, i, false, false, false);
+               cmdout = compile(score, m, i, false, false, false);
if (cmdout) {
-                       res = talloc(list, struct compile_tests_result);
-                       res->filename = i->name;
-                       res->description = "failed to compile without -DFAIL";
-                       res->output = talloc_steal(res, cmdout);
-               } else {
-                       cmdout = compile(list, m, i, true, false, false);
-                       if (!cmdout) {
-                               res = talloc(list, struct compile_tests_result);
-                               res->filename = i->name;
-                               res->description = "compiled successfully"
-                                       " with -DFAIL";
-                               res->output = "";
-                       }
+                       score->error = "Failed to compile without -DFAIL";
+                       score_file_error(score, i, 0, cmdout);
+                       return;
+               }
+               cmdout = compile(score, m, i, true, false, false);
+               if (!cmdout) {
+                       score->error = "Compiled successfully with -DFAIL?";
+                       score_file_error(score, i, 0, NULL);
+                       return;
}
}

-       if (list_empty(list)) {
-               talloc_free(list);
-               list = NULL;
-       }
-
-       return list;
-}
-
-static unsigned int score_compile_tests(struct manifest *m,
-                                       void *check_result)
-{
-       struct list_head *list = check_result;
-       struct compile_tests_result *i;
-       unsigned int score = compile_tests.total_score;
-
-       list_for_each(list, i, list)
-               score--;
-       return score;
-}
-
-static const char *describe_compile_tests(struct manifest *m,
-                                         void *check_result)
-{
-       struct list_head *list = check_result;
-       struct compile_tests_result *i;
-       char *descrip = talloc_strdup(list, "Compilation tests failed:\n");
-
-       list_for_each(list, i, list)
-               descrip = talloc_asprintf_append(descrip, "%s %s\n%s",
-                                                i->filename, i->description,
-                                                i->output);
-       return descrip;
+       score->pass = true;
+       score->score = score->total;
}

struct ccanlint compile_tests = {
.key = "compile-tests",
.name = "Module tests compile",
-       .score = score_compile_tests,
-       .total_score = 1,
.check = do_compile_tests,
-       .describe = describe_compile_tests,
.can_run = can_build,
};

@@ -46,12 +46,11 @@ static bool has_dep(struct manifest *m, const char *depname, bool tap_ok)
return false;
}

-static void *check_depends_accurate(struct manifest *m,
-                                   bool keep,
-                                   unsigned int *timeleft)
+static void check_depends_accurate(struct manifest *m,
+                                  bool keep,
+                                  unsigned int *timeleft, struct score *score)
{
-       char *report = talloc_strdup(m, "");

foreach_ptr(list, &m->c_files, &m->h_files,
&m->run_tests, &m->api_tests,
@@ -61,7 +60,7 @@ static void *check_depends_accurate(struct manifest *m,
bool tap_ok;

/* Including ccan/tap is fine for tests. */
-               tap_ok =  (list != &m->c_files && list != &m->h_files);
+               tap_ok = (list != &m->c_files && list != &m->h_files);

list_for_each(list, f, list) {
unsigned int i;
@@ -79,35 +78,25 @@ static void *check_depends_accurate(struct manifest *m,
if (!strchr(strchr(p, '/') + 1, '/'))
continue;
*strchr(strchr(p, '/') + 1, '/') = '\0';
-                               if (!has_dep(m, p, tap_ok))
-                                       report = talloc_asprintf_append(report,
-                                              "%s:%u:%s\n",
-                                              f->name, i+1, lines[i]);
+                               if (has_dep(m, p, tap_ok))
+                                       continue;
+                               score->error = "Includes a ccan module"
+                                       " not listed in _info";
+                               score_file_error(score, f, i+1, lines[i]);
}
}
}

-       if (streq(report, "")) {
-               talloc_free(report);
-               report = NULL;
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
}
-       return report;
-}
-
-static const char *describe_depends_accurage(struct manifest *m,
-                                            void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "You include ccan modules you don't list as dependencies:\n"
-                              "%s", (char *)check_result);
}

struct ccanlint depends_accurate = {
.key = "depends-accurate",
.name = "Module's CCAN dependencies are the only ccan files #included",
-       .total_score = 1,
.check = check_depends_accurate,
-       .describe = describe_depends_accurage,
};

REGISTER_TEST(depends_accurate, &depends_exist, NULL);
index 80c5ba631375e58bd24d78463b6aa65139434679..b34846371cfb8b96bca5e8ae1d383cfa85bc3067 100644 (file)
@@ -15,6 +15,8 @@ static const char *can_run(struct manifest *m)
{
if (safe_mode)
return "Safe mode enabled";
+       if (list_empty(&m->examples))
+               return "No examples to compile";
return NULL;
}

@@ -128,11 +130,6 @@ static char *compile(const void *ctx,
return NULL;
}

-struct score {
-       unsigned int score;
-       char *errors;
-};
-
static char *start_main(char *ret, const char *why)
{
return talloc_asprintf_append(ret,
@@ -434,22 +431,21 @@ static struct ccan_file *mangle_example(struct manifest *m,
return f;
}

-static void *build_examples(struct manifest *m, bool keep,
-                           unsigned int *timeleft)
+static void build_examples(struct manifest *m, bool keep,
+                          unsigned int *timeleft, struct score *score)
{
struct ccan_file *i;
-       struct score *score = talloc(m, struct score);
char **prev = NULL;

-       score->score = 0;
-       score->errors = talloc_strdup(score, "");
+       score->total = 0;
+       score->pass = true;

-       examples_compile.total_score = 0;
list_for_each(&m->examples, i, list) {
char *ret, *ret1, *ret2 = NULL;
struct ccan_file *mangle1, *mangle2 = NULL;
+               char *err;

-               examples_compile.total_score++;
+               score->total++;
/* Simplify our dumb parsing. */
ret = compile(i, m, i, keep);
@@ -481,64 +477,46 @@ static void *build_examples(struct manifest *m, bool keep,
}
}

-               score->errors = talloc_asprintf_append(score->errors,
-                                      "%s: tried standalone example:\n"
-                                      "%s\n"
-                                      "Errors: %s\n\n",
-                                      i->name,
-                                      get_ccan_file_contents(i),
-                                      ret);
-               score->errors = talloc_asprintf_append(score->errors,
-                                      "%s\n"
-                                      "Errors: %s\n\n",
-                                      i->name,
-                                      get_ccan_file_contents(mangle1),
-                                      ret1);
-
-               if (mangle2) {
-                       score->errors = talloc_asprintf_append(score->errors,
-                                      "%s: tried combining with"
-                                      " previous example:\n"
+               score->pass = false;
+               score->error = "Compiling extracted examples failed";
+               if (!verbose) {
+                       if (mangle2)
+                                       "and including previous "
+                                       "example all failed";
+                       else
+                               err = "Standalone compile and"
+               } else {
+                       err = talloc_asprintf("Standalone example:\n"
+                                             "%s\n"
+                                             "Errors: %s\n\n"
+                                             "%s\n"
+                                             "Errors: %s\n\n",
+                                             get_ccan_file_contents(i),
+                                             ret,
+                                             get_ccan_file_contents(mangle1),
+                                             ret1);
+
+                       if (mangle2)
+                               err = talloc_asprintf_append(err,
+                                      "Combining with previous example:\n"
"%s\n"
"Errors: %s\n\n",
-                                      i->name,
get_ccan_file_contents(mangle2),
ret2);
}
+               score_file_error(score, i, 0, err);
/* This didn't work, so not a candidate for combining. */
prev = NULL;
}
-
-       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 >= 2 && score->errors)
-               return talloc_asprintf(m, "Compile errors building examples:\n"
-                                      "%s", score->errors);
-       return NULL;
}

struct ccanlint examples_compile = {
.key = "examples-compile",
.name = "Module examples compile",
-       .score = score_examples,
-       .total_score = 3, /* This gets changed to # examples, if they exist */
.check = build_examples,
-       .describe = describe,
.can_run = can_run,
};

index 522feb0a0bf320422c80f4bc5c5fb73335b159b0..3cb456d49fa69d38f073f76229aa706b1ccb8e5a 100644 (file)

static const char *can_run(struct manifest *m)
{
+
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)
@@ -224,26 +224,21 @@ static char *unexpected(struct ccan_file *i, const char *input,
return output;
}

-static void *run_examples(struct manifest *m, bool keep,
-                         unsigned int *timeleft)
+static void run_examples(struct manifest *m, bool keep,
+                        unsigned int *timeleft, struct score *score)
{
struct ccan_file *i;
-       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;
-
lines = get_ccan_file_lines(i);

for (expect = find_expect(i, lines, &input, &exact,
@@ -252,52 +247,34 @@ static void *run_examples(struct manifest *m, bool keep,
linenum++,
expect = find_expect(i, lines, &input,
&exact, &linenum)) {
-                               examples_run.total_score++;
+                               char *err;
+                               score->total++;
+                               if (i->compiled == NULL)
+                                       continue;
+
output = unexpected(i, input, expect, exact);
-                               if (!output)
+                               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;
}
+                               err = talloc_asprintf(score,
+                                                     "output '%s' didn't"
+                                                     " %s '%s'\n",
+                                                     output,
+                                                     exact
+                                                     ? "match" : "contain",
+                                                     expect);
+                               score_file_error(score, i, linenum+1, err);
+                               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;
}

struct ccanlint 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,
};

@@ -56,28 +56,22 @@ static char *add_example(struct manifest *m, struct ccan_file *source,
}

/* FIXME: We should have one example per function in header. */
-struct score {
-       char *error;
-};
-
-static void *extract_examples(struct manifest *m,
-                             bool keep,
-                             unsigned int *timeleft)
+static void extract_examples(struct manifest *m,
+                            bool keep,
+                            unsigned int *timeleft,
+                            struct score *score)
{
struct ccan_file *f;
struct doc_section *d;
-       struct score *score = talloc(m, struct score);
-
-       score->info_example = score->header_example = false;
-       score->error = NULL;
+       bool have_info_example = false, have_header_example = false;

+       score->total = 2;
list_for_each(get_ccan_file_docs(m->info_file), d, list) {
if (streq(d->type, "example")) {
score->error = add_example(m, m->info_file, keep, d);
if (score->error)
-                               return score;
-                       score->info_example = true;
+                               return;
+                       have_info_example = true;
}
}

@@ -91,57 +85,35 @@ static void *extract_examples(struct manifest *m,
if (streq(d->type, "example")) {
score->error = add_example(m, f, keep, d);
if (score->error)
-                                       return score;
+                                       return;
}
}
}
-       return score;
-}
-
-static unsigned int score_examples(struct manifest *m, void *check_result)
-{
-       struct score *score = check_result;
-       int total = 0;
-
-       if (score->error)
-               return 0;
-       total += score->info_example;
-       return total;
-}
-
-static const char *describe_examples(struct manifest *m,
-                                    void *check_result)
-{
-       struct score *score = check_result;
-       char *descrip = NULL;
-
-       if (score->error)
-               return score->error;

-       if (!score->info_example)
-               descrip = talloc_asprintf(score,
-               "Your _info file has no module example.\n\n"
-               "There should be an Example: section of the _info documentation\n"
-               "which provides a concise toy program which uses your module\n");
-
-               descrip = talloc_asprintf(score,
-                "%sMain header file file has no examples\n\n"
-                "There should be an Example: section for each public function\n"
-                 "demonstrating its use\n", descrip ? descrip : "");
-
-       return descrip;
+       if (!have_info_example && !have_header_example) {
+               score->error = "You don't have any Example: sections";
+               score->score = 0;
+       } else if (!have_info_example) {
+               score->error = "You don't have an Example: section in _info";
+               score->score = 1;
+               score->pass = true;
+       } else if (!have_header_example) {
+               score->error = talloc_asprintf(score,
+                              "You don't have an Example: section in %s.h",
+                              m->basename);
+               score->score = 1;
+               score->pass = true;
+       } else {
+               score->score = score->total;
+               score->pass = true;
+       }
}

struct ccanlint has_examples = {
.key = "has-examples",
.name = "_info and header files have examples",
-       .score = score_examples,
.check = extract_examples,
-       .describe = describe_examples,
-       .total_score = 2,
};

REGISTER_TEST(has_examples, &has_info, NULL);
#include <ccan/noerr/noerr.h>
#include <ccan/grab_file/grab_file.h>

-struct info_docs
-{
-       bool summary;
-       bool description;
-};
-
-static void *check_has_info_documentation(struct manifest *m,
-                                         bool keep,
-                                         unsigned int *timeleft)
-{
-       struct list_head *infodocs = get_ccan_file_docs(m->info_file);
-       struct doc_section *d;
-       struct info_docs id = { false, false };
-
-       list_for_each(infodocs, d, list) {
-               if (!streq(d->function, m->basename))
-                       continue;
-               if (streq(d->type, "summary"))
-                       id.summary = true;
-               if (streq(d->type, "description"))
-                       id.description = true;
-       }
-
-       if (id.summary && id.description)
-               return NULL;
-       return talloc_memdup(m, &id, sizeof(id));
-}
-
-/* This is defined below. */
-extern struct ccanlint has_info_documentation;
-
-static void create_info_template_doc(struct manifest *m, void *check_result)
+static void create_info_template_doc(struct manifest *m, struct score *score)
{
int fd = open("_info.new", O_WRONLY|O_CREAT|O_EXCL, 0666);
FILE *new;
@@ -87,42 +56,44 @@ static void create_info_template_doc(struct manifest *m, void *check_result)
}
}

-static const char *describe_has_info_documentation(struct manifest *m,
-                                                  void *check_result)
+static void check_has_info_documentation(struct manifest *m,
+                                        bool keep,
+                                        unsigned int *timeleft,
+                                        struct score *score)
{
-       struct info_docs *id = check_result;
-       char *reason = talloc_strdup(m, "");
+       struct list_head *infodocs = get_ccan_file_docs(m->info_file);
+       struct doc_section *d;
+       bool summary = false, description = false;

-       if (!id->summary) {
-               has_info_documentation.handle = create_info_template_doc;
-               reason = talloc_asprintf_append(reason,
-               "Your _info file has no module documentation.\n\n"
+       list_for_each(infodocs, d, list) {
+               if (!streq(d->function, m->basename))
+                       continue;
+               if (streq(d->type, "summary"))
+                       summary = true;
+               if (streq(d->type, "description"))
+                       description = true;
+       }
+
+       if (summary && description) {
+               score->score = score->total;
+               score->pass = true;
+       } else if (!summary) {
+               score->error = "_info file has no module documentation.\n\n"
"CCAN modules use /**-style comments for documentation: the\n"
-               "overall documentation belongs in the _info metafile.\n");
+               "overall documentation belongs in the _info metafile.\n";
+               has_info_documentation.handle = create_info_template_doc;
}
-       if (!id->description)
-               reason = talloc_asprintf_append(reason,
-               "Your _info file has no module description.\n\n"
+       else if (!description)
+               score->error = "_info file has no module description.\n\n"
"The lines after the first summary line in the _info file\n"
"documentation should describe the purpose and use of the\n"
-               "overall package\n");
-       return reason;
-}
-
-static unsigned int has_info_documentation_score(struct manifest *m,
-                                                void *check_result)
-{
-       struct info_docs *id = check_result;
-       return (unsigned int)id->summary + id->description;
+               "overall package\n";
}

struct ccanlint has_info_documentation = {
.key = "info-documentation",
.name = "Module has documentation in _info",
-       .total_score = 2,
-       .score = has_info_documentation_score,
.check = check_has_info_documentation,
-       .describe = describe_has_info_documentation,
};

REGISTER_TEST(has_info_documentation, NULL);
index 4237540011fed95d5a351d40246998ae9449ec17..0a510a034629b62d10bffa5ab06b04cfb043b0c3 100644 (file)
#include <err.h>
#include <ccan/talloc/talloc.h>

-static char test_is_not_dir[] = "test is not a directory";
-
-static void *check_has_tests(struct manifest *m,
-                            bool keep,
-                            unsigned int *timeleft)
+static void handle_no_tests(struct manifest *m, struct score *score)
{
-       struct stat st;
+       FILE *run;
+       struct ccan_file *i;
char *test_dir = talloc_asprintf(m, "%s/test", m->dir);

-       if (lstat(test_dir, &st) != 0) {
-               if (errno != ENOENT)
-                       err(1, "statting %s", test_dir);
-               return "You have no test directory";
-       }
-
-       if (!S_ISDIR(st.st_mode))
-               return test_is_not_dir;
-
-       if (list_empty(&m->api_tests)
-           && list_empty(&m->run_tests)
-           && list_empty(&m->compile_ok_tests)) {
-               if (list_empty(&m->compile_fail_tests))
-                       return "You have no tests in the test directory";
-               else
-                       return "You have no positive tests in the test directory";
-       }
-       return NULL;
-}
-
-static const char *describe_has_tests(struct manifest *m, void *check_result)
-{
-       return talloc_asprintf(m, "%s\n\n"
-        "CCAN modules have a directory called test/ which contains tests.\n"
+       printf(
+       "CCAN modules have a directory called test/ which contains tests.\n"
"There are four kinds of tests: api, run, compile_ok and compile_fail:\n"
"you can tell which type of test a C file is by its name, eg 'run.c'\n"
"and 'run-simple.c' are both run tests.\n\n"

"The simplest kind of test is a run test, which must compile with no\n"
-       "warnings, and then run: it is expected to use libtap to report its\n"
+       "warnings, and then run: it is expected to use ccan/tap to report its\n"
"results in a simple and portable format.  It should #include the C\n"
"files from the module directly (so it can probe the internals): the\n"
"module will not be linked in.  The test will be run in a temporary\n"
@@ -67,20 +42,8 @@ static const char *describe_has_tests(struct manifest *m, void *check_result)
"when it's not defined: this helps ensure unrelated errors don't make\n"
"compilation fail.\n\n"

-       "Note that the tests are not linked against the files in the\n"
-       "above: you should directly #include those C files you want.  This\n"
-       "allows access to static functions and use special effects inside\n"
-       "test files\n", (char *)check_result);
-}
-
-static void handle_no_tests(struct manifest *m, void *check_result)
-{
-       FILE *run;
-       struct ccan_file *i;
-       char *test_dir = talloc_asprintf(m, "%s/test", m->dir);
-
-       if (check_result == test_is_not_dir)
-               return;
+       "Note that only API tests are linked against the files in the module!\n"
+               );

if (!ask("Should I create a template test/run.c file for you?"))
return;
@@ -101,41 +64,70 @@ static void handle_no_tests(struct manifest *m, void *check_result)
fprintf(run, "#include <ccan/%s/%s>\n",
m->basename, i->name);
}
-       fputs("#include <ccan/tap/tap.h>\n", run);
-       fputs("\n", run);
-
-       fputs("int main(void)\n", run);
-       fputs("{\n", run);
-       fputs("\t/* This is how many tests you plan to run */\n", run);
-       fputs("\tplan_tests(3);\n", run);
-       fputs("\n", run);
-       fputs("\t/* Simple thing we expect to succeed */\n", run);
-       fputs("\tok1(some_test())\n", run);
-       fputs("\t/* Same, with an explicit description of the test. */\n", run);
-       fputs("\tok(some_test(), \"%s with no args should return 1\", \"some_test\")\n", run);
-       fputs("\t/* How to print out messages for debugging. */\n", run);
-       fputs("\tdiag(\"Address of some_test is %p\", &some_test)\n", run);
-       fputs("\t/* Conditional tests must be explicitly skipped. */\n", run);
-       fputs("#if HAVE_SOME_FEATURE\n", run);
-       fputs("\tok1(test_some_feature())\n", run);
-       fputs("#else\n", run);
-       fputs("\tskip(1, \"Don\'t have SOME_FEATURE\")\n", run);
-       fputs("#endif\n", run);
-       fputs("\n", run);
-       fputs("\t/* This exits depending on whether all tests passed */\n", run);
-       fputs("\treturn exit_status();\n", run);
-       fputs("}\n", run);
-
+       fprintf(run, "%s",
+               "#include <ccan/tap/tap.h>\n\n"
+               "int main(void)\n"
+               "{\n"
+               "       /* This is how many tests you plan to run */\n"
+               "       plan_tests(3);\n"
+               "\n"
+               "       /* Simple thing we expect to succeed */\n"
+               "       ok1(some_test())\n"
+               "       /* Same, with an explicit description of the test. */\n"
+               "       ok(some_test(), \"%s with no args should return 1\", \"some_test\")\n"
+               "       /* How to print out messages for debugging. */\n"
+               "       diag(\"Address of some_test is %p\", &some_test)\n"
+               "       /* Conditional tests must be explicitly skipped. */\n"
+               "#if HAVE_SOME_FEATURE\n"
+               "       ok1(test_some_feature())\n"
+               "#else\n"
+               "       skip(1, \"Don\'t have SOME_FEATURE\")\n"
+               "#endif\n"
+               "\n"
+               "       /* This exits depending on whether all tests passed */\n"
+               "       return exit_status();\n"
+               "}\n");
fclose(run);
}

+static void check_has_tests(struct manifest *m,
+                           bool keep,
+                           unsigned int *timeleft, struct score *score)
+{
+       struct stat st;
+       char *test_dir = talloc_asprintf(m, "%s/test", m->dir);
+
+       if (lstat(test_dir, &st) != 0) {
+               score->error = "No test directory";
+               if (errno != ENOENT)
+                       err(1, "statting %s", test_dir);
+               has_tests.handle = handle_no_tests;
+               return;
+       }
+
+       if (!S_ISDIR(st.st_mode)) {
+               score->error = "test is not a directory";
+               return;
+       }
+
+       if (list_empty(&m->api_tests)
+           && list_empty(&m->run_tests)
+           && list_empty(&m->compile_ok_tests)) {
+               if (list_empty(&m->compile_fail_tests)) {
+                       score->error = "No tests in test directory";
+                       has_tests.handle = handle_no_tests;
+               } else
+                       score->error = "No positive tests in test directory";
+               return;
+       }
+       score->pass = true;
+       score->score = score->total;
+}
+
struct ccanlint has_tests = {
.key = "has-tests",
.name = "Module has tests",
.check = check_has_tests,
-       .describe = describe_has_tests,
-       .total_score = 1,
-       .handle = handle_no_tests,
};

REGISTER_TEST(has_tests, NULL);
index 95040cf62b09b2f012d77d8b3683f6a9712d79e9..7ab4a57b7e31080e5630be981de524f4967524c9 100644 (file)
static const char explain[]
= "Headers usually start with the C preprocessor lines to prevent multiple\n"
"inclusions.  These look like the following:\n"
+  "#ifndef CCAN_<MODNAME>_H\n"
+  "#define CCAN_<MODNAME>_H\n"
"...\n"
+  "#endif /* CCAN_<MODNAME>_H */\n";

-static char *report_idem(struct ccan_file *f, char *sofar)
+static void fix_name(char *name)
+{
+       unsigned int i, j;
+
+       for (i = j = 0; name[i]; i++) {
+               if (isalnum(name[i]) || name[i] == '_')
+                       name[j++] = toupper(name[i]);
+       }
+       name[j] = '\0';
+}
+
+static void handle_idem(struct manifest *m, struct score *score)
+{
+       struct file_error *e;
+
+       list_for_each(&score->per_file_errors, e, list) {
+               char *name, *q, *tmpname;
+               FILE *out;
+               unsigned int i;
+
+               /* Main header gets CCAN_FOO_H, others CCAN_FOO_XXX_H */
+               if (strstarts(e->file->name, m->basename)
+                   || strlen(e->file->name) != strlen(m->basename) + 2)
+                       name = talloc_asprintf(score, "CCAN_%s_H", m->basename);
+               else
+                       name = talloc_asprintf(score, "CCAN_%s_%s_H",
+                                              m->basename, e->file->name);
+               fix_name(name);
+
+               q = talloc_asprintf(score,
+                           "Should I wrap %s in #ifndef/#define %s for you?",
+                           e->file->name, name);
+                       continue;
+
+               tmpname = maybe_temp_file(score, ".h", false, e->file->name);
+               out = fopen(tmpname, "w");
+               if (!out)
+                       err(1, "Opening %s", tmpname);
+               if (fprintf(out, "#ifndef %s\n#define %s\n", name, name) < 0)
+                       err(1, "Writing %s", tmpname);
+
+               for (i = 0; i < e->file->num_lines; i++)
+                       if (fprintf(out, "%s\n", e->file->lines[i]) < 0)
+                               err(1, "Writing %s", tmpname);
+
+               if (fprintf(out, "#endif /* %s */\n", name) < 0)
+                       err(1, "Writing %s", tmpname);
+
+               if (fclose(out) != 0)
+                       err(1, "Closing %s", tmpname);
+
+               if (!move_file(tmpname, e->file->fullname))
+                       err(1, "Moving %s to %s", tmpname, e->file->fullname);
+       }
+}
+
+static bool check_idem(struct ccan_file *f, struct score *score)
{
struct line_info *line_info;
unsigned int i, first_preproc_line;
@@ -31,44 +88,48 @@ static char *report_idem(struct ccan_file *f, char *sofar)
line_info = get_ccan_line_info(f);
if (f->num_lines < 3)
/* FIXME: We assume small headers probably uninteresting. */
-               return sofar;
+               return true;

+       score->error = "Headers are not idempotent";
for (i = 0; i < f->num_lines; i++) {
if (line_info[i].type == DOC_LINE
|| line_info[i].type == COMMENT_LINE)
continue;
-               if (line_info[i].type == CODE_LINE)
-                       return talloc_asprintf_append(sofar,
-                             "%s:%u:expect first non-comment line to be #ifndef.\n", f->name, i+1);
-               else if (line_info[i].type == PREPROC_LINE)
+               if (line_info[i].type == CODE_LINE) {
+                       score_file_error(score, f, i+1,
+                                        "Expect first non-comment line to be"
+                                        " #ifndef.");
+                       return false;
+               } else if (line_info[i].type == PREPROC_LINE)
break;
}

/* No code at all?  Don't complain. */
if (i == f->num_lines)
-               return sofar;
+               return true;

first_preproc_line = i;
for (i = first_preproc_line+1; i < f->num_lines; i++) {
if (line_info[i].type == DOC_LINE
|| line_info[i].type == COMMENT_LINE)
continue;
-               if (line_info[i].type == CODE_LINE)
-                       return talloc_asprintf_append(sofar,
-                             "%s:%u:expect second line to be #define.\n", f->name, i+1);
-               else if (line_info[i].type == PREPROC_LINE)
+               if (line_info[i].type == CODE_LINE) {
+                       score_file_error(score, f, i+1,
+                                        "Expect second non-comment line to be"
+                                        " #define.");
+                       return false;
+               } else if (line_info[i].type == PREPROC_LINE)
break;
}

/* No code at all?  Weird. */
if (i == f->num_lines)
-               return sofar;
+               return true;

/* We expect a condition on this line. */
if (!line_info[i].cond) {
-               return talloc_asprintf_append(sofar,
-                                             "%s:%u:expected #ifndef.\n",
-                                             f->name, first_preproc_line+1);
+               score_file_error(score, f, i+1, "Expected #ifndef");
+               return false;
}

line = f->lines[i];
@@ -76,24 +137,27 @@ static char *report_idem(struct ccan_file *f, char *sofar)
/* We expect the condition to be ! IFDEF <symbol>. */
if (line_info[i].cond->type != PP_COND_IFDEF
|| !line_info[i].cond->inverse) {
-               return talloc_asprintf_append(sofar,
-                                             "%s:%u:expected #ifndef.\n",
-                                             f->name, first_preproc_line+1);
+               score_file_error(score, f, i+1, "Expected #ifndef");
+               return false;
}

/* And this to be #define <symbol> */
if (!get_token(&line, "#"))
abort();
if (!get_token(&line, "define")) {
-               return talloc_asprintf_append(sofar,
-                             "%s:%u:expected '#define %s'.\n",
-                             f->name, i+1, line_info[i].cond->symbol);
+               char *str = talloc_asprintf(score,
+                                           "expected '#define %s'",
+                                           line_info[i].cond->symbol);
+               score_file_error(score, f, i+1, str);
+               return false;
}
sym = get_symbol_token(f, &line);
if (!sym || !streq(sym, line_info[i].cond->symbol)) {
-               return talloc_asprintf_append(sofar,
-                             "%s:%u:expected '#define %s'.\n",
-                             f->name, i+1, line_info[i].cond->symbol);
+               char *str = talloc_asprintf(score,
+                                           "expected '#define %s'",
+                                           line_info[i].cond->symbol);
+               score_file_error(score, f, i+1, str);
+               return false;
}

/* Rest of code should all be covered by that conditional. */
@@ -103,42 +167,35 @@ static char *report_idem(struct ccan_file *f, char *sofar)
|| line_info[i].type == COMMENT_LINE)
continue;
if (get_ccan_line_pp(line_info[i].cond, sym, &val, NULL)
-                   != NOT_COMPILED)
-                       return talloc_asprintf_append(sofar,
-                             "%s:%u:code outside idempotent region.\n",
-                             f->name, i+1);
+                   != NOT_COMPILED) {
+                       score_file_error(score, f, i+1, "code outside"
+                                        " idempotent region");
+                       return false;
+               }
}

-       return sofar;
+       return true;
}

-static void *check_idempotent(struct manifest *m,
-                             bool keep,
-                             unsigned int *timeleft)
+static void check_idempotent(struct manifest *m,
+                            bool keep,
+                            unsigned int *timeleft, struct score *score)
{
struct ccan_file *f;
-       char *report = NULL;
-
-       list_for_each(&m->h_files, f, list)
-               report = report_idem(f, report);

-       return report;
-}
-
-static const char *describe_idempotent(struct manifest *m, void *check_result)
-{
-       return talloc_asprintf(check_result,
-                              "%s\n%s", (char *)check_result,
-                              explain);
+       list_for_each(&m->h_files, f, list) {
+               if (!check_idem(f, score))
+                       return;
+       }
+       score->pass = true;
+       score->score = score->total;
}

struct ccanlint idempotent = {
.key = "idempotent",
.name = "Module headers are #ifndef/#define wrapped",
-       .total_score = 1,
.check = check_idempotent,
-       .describe = describe_idempotent,
+       .handle = handle_idem,
};

REGISTER_TEST(idempotent, NULL);
index a1bd8dea59f79a4a145d16594408182f66fe01b4..8e756c7db732faed28d89028c6c9d0b7a2afb48b 100644 (file)
@@ -4,6 +4,7 @@
#include <ccan/str_talloc/str_talloc.h>
#include <ccan/grab_file/grab_file.h>
#include <ccan/str/str.h>
+#include <ccan/foreach/foreach.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>

-struct coverage_result {
-       float uncovered;
-       const char *what;
-       char *output;
-};
-
-static bool find_source_file(struct manifest *m, const char *filename)
+static bool find_source_file(const struct manifest *m, const char *filename)
{
-       struct ccan_file *i;
+       const struct ccan_file *i;

list_for_each(&m->c_files, i, list) {
if (streq(i->fullname, filename))
@@ -37,12 +32,25 @@ static bool find_source_file(struct manifest *m, const char *filename)
return false;
}

+/* 1 point for 50%, 2 points for 75%, 3 points for 87.5%... */
+static unsigned int score_coverage(float covered, unsigned total)
+{
+       float thresh, uncovered = 1.0 - covered;
+       unsigned int i;
+
+       for (i = 0, thresh = 0.5; i < total; i++, thresh /= 2) {
+               if (uncovered > thresh)
+                       break;
+       }
+       return i;
+}
+
+
/* FIXME: Don't know how stable this is.  Read cov files directly? */
-static void analyze_coverage(struct manifest *m,
-                            struct coverage_result *res, const char *output,
-                            bool full_gcov)
+static void analyze_coverage(struct manifest *m, bool full_gcov,
+                            const char *output, struct score *score)
{
-       char **lines = strsplit(res, output, "\n", NULL);
+       char **lines = strsplit(score, output, "\n", NULL);
float covered_lines = 0.0;
unsigned int i, total_lines = 0;
bool lines_matter = false;
@@ -81,17 +89,14 @@ static void analyze_coverage(struct manifest *m,
apostrophe = strchr(filename, '\'');
*apostrophe = '\0';
if (lines_matter) {
-                               file = grab_file(res, filename, NULL);
+                               file = grab_file(score, filename, NULL);
if (!file) {
-                                       res->what = talloc_asprintf(res,
+                                       score->error = talloc_asprintf(score,
filename);
-                                       res->output = talloc_strdup(res,
-                                                           strerror(errno));
return;
}
-                               res->output = talloc_append_string(res->output,
-                                                                  file);
+                               printf("%s", file);
}
if (tools_verbose)
@@ -99,114 +104,65 @@ static void analyze_coverage(struct manifest *m,
}
}

+       score->pass = true;
+
/* Nothing covered?  We can't tell if there's a source file which
* was never executed, or there really is no code to execute, so
* assume the latter: this test deserves no score. */
-       if (total_lines == 0) {
-               res->uncovered = 1.0;
-               run_coverage_tests.total_score = 0;
-       } else
-               res->uncovered = 1.0 - covered_lines / total_lines;
+       if (total_lines == 0)
+               score->total = score->score = 0;
+       else {
+               score->total = 5;
+               score->score = score_coverage(covered_lines / total_lines,
+                                             score->total);
+       }
}

-static void *do_run_coverage_tests(struct manifest *m,
-                                  bool keep,
-                                  unsigned int *timeleft)
+static void do_run_coverage_tests(struct manifest *m,
+                                 bool keep,
+                                 unsigned int *timeleft, struct score *score)
{
-       struct coverage_result *res;
struct ccan_file *i;
char *cmdout;
char *covcmd;
bool ok;
bool full_gcov = (verbose > 1);
-
-       res = talloc(m, struct coverage_result);
-       res->what = NULL;
-       res->output = talloc_strdup(res, "");
-       res->uncovered = 1.0;

/* This tells gcov where we put those .gcno files. */
covcmd = talloc_asprintf(m, "gcov %s -o %s",
full_gcov ? "" : "-n",
-                                talloc_dirname(res, m->info_file->compiled));
+                                talloc_dirname(score, m->info_file->compiled));

/* Run them all. */
-       list_for_each(&m->run_tests, i, list) {
-               cmdout = run_command(m, timeleft, i->cov_compiled);
-               if (cmdout) {
-                       res->what = i->fullname;
-                       res->output = talloc_steal(res, cmdout);
-                       return res;
-               }
-               covcmd = talloc_asprintf_append(covcmd, " %s", i->fullname);
-       }
-
-       list_for_each(&m->api_tests, i, list) {
-               cmdout = run_command(m, timeleft, i->cov_compiled);
-               if (cmdout) {
-                       res->what = i->fullname;
-                       res->output = talloc_steal(res, cmdout);
-                       return res;
+       foreach_ptr(list, &m->run_tests, &m->api_tests) {
+               list_for_each(list, i, list) {
+                       cmdout = run_command(m, timeleft, i->cov_compiled);
+                       if (cmdout) {
+                               score->error = "Running test with coverage";
+                               score_file_error(score, i, 0, cmdout);
+                               return;
+                       }
+                       covcmd = talloc_asprintf_append(covcmd, " %s",
+                                                       i->fullname);
}
-               covcmd = talloc_asprintf_append(covcmd, " %s", i->fullname);
}

/* Now run gcov: we want output even if it succeeds. */
cmdout = run_with_timeout(m, covcmd, &ok, timeleft);
if (!ok) {
-               res->what = "Running gcov";
-               res->output = talloc_steal(res, cmdout);
-               return res;
-       }
-
-       analyze_coverage(m, res, cmdout, full_gcov);
-
-       return res;
-}
-
-/* 1 point for 50%, 2 points for 75%, 3 points for 87.5%... */
-static unsigned int score_coverage(struct manifest *m, void *check_result)
-{
-       struct coverage_result *res = check_result;
-       float thresh;
-       unsigned int i;
-
-       for (i = 0, thresh = 0.5;
-            i < run_coverage_tests.total_score;
-            i++, thresh /= 2) {
-               if (res->uncovered > thresh)
-                       break;
+               score->error = talloc_asprintf(score, "Running gcov: %s",
+                                              cmdout);
+               return;
}
-       return i;
-}
-
-static const char *describe_run_coverage_tests(struct manifest *m,
-                                              void *check_result)
-{
-       struct coverage_result *res = check_result;
-       bool full_gcov = (verbose > 1);
-       char *ret;
-
-       if (res->what)
-               return talloc_asprintf(m, "%s: %s", res->what, res->output);
-
-       if (!verbose)
-               return NULL;

-       ret = talloc_asprintf(m, "Tests achieved %0.2f%% coverage",
-                             (1.0 - res->uncovered) * 100);
-       if (full_gcov)
-               ret = talloc_asprintf_append(ret, "\n%s", res->output);
-       return ret;
+       analyze_coverage(m, full_gcov, cmdout, score);
}

struct ccanlint run_coverage_tests = {
.key = "test-coverage",
.name = "Code coverage of module tests",
-       .total_score = 5,
-       .score = score_coverage,
.check = do_run_coverage_tests,
-       .describe = describe_run_coverage_tests,
};

REGISTER_TEST(run_coverage_tests, &compile_coverage_tests, &run_tests, NULL);
index 559a637880915a0e6b39c7fcd789cc855eeab441..0a8434c6e5a35563bfd3eae06f61cbf0e7554c84 100644 (file)
@@ -2,6 +2,7 @@
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
+#include <ccan/foreach/foreach.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -21,91 +22,43 @@ static const char *can_run(struct manifest *m)
return NULL;
}

-struct run_tests_result {
-       struct list_node list;
-       struct ccan_file *file;
-       const char *output;
-};
-
-static void *do_run_tests(struct manifest *m,
-                         bool keep,
-                         unsigned int *timeleft)
+static void do_run_tests(struct manifest *m,
+                        bool keep,
+                        unsigned int *timeleft,
+                        struct score *score)
{
-       struct run_tests_result *res;
struct ccan_file *i;
char *cmdout;

-       run_tests.total_score = 0;
-
-       list_for_each(&m->run_tests, i, list) {
-               run_tests.total_score++;
-               cmdout = run_command(m, timeleft, i->compiled);
-               if (cmdout) {
-                       res = talloc(list, struct run_tests_result);
-                       res->file = i;
-                       res->output = talloc_steal(res, cmdout);
-               }
-       }
-
-       list_for_each(&m->api_tests, i, list) {
-               run_tests.total_score++;
-               cmdout = run_command(m, timeleft, i->compiled);
-               if (cmdout) {
-                       res = talloc(list, struct run_tests_result);
-                       res->file = i;
-                       res->output = talloc_steal(res, cmdout);
+       score->total = 0;
+       foreach_ptr(list, &m->run_tests, &m->api_tests) {
+               list_for_each(list, i, list) {
+                       score->total++;
+                       cmdout = run_command(m, timeleft, i->compiled);
+                       if (cmdout)
+                               score_file_error(score, i, 0, cmdout);
+                       else
+                               score->score++;
}
}

-       if (list_empty(list)) {
-               talloc_free(list);
-               list = NULL;
-       }
-
-       return list;
-}
-
-static unsigned int score_run_tests(struct manifest *m, void *check_result)
-{
-       struct list_head *list = check_result;
-       struct run_tests_result *i;
-       unsigned int score = run_tests.total_score;
-
-       list_for_each(list, i, list)
-               score--;
-       return score;
-}
-
-static const char *describe_run_tests(struct manifest *m,
-                                         void *check_result)
-{
-       struct list_head *list = check_result;
-       char *descrip = talloc_strdup(check_result, "Running tests failed:\n");
-       struct run_tests_result *i;
-
-       list_for_each(list, i, list)
-               descrip = talloc_asprintf_append(descrip, "Running %s:\n%s",
-                                                i->file->name, i->output);
-       return descrip;
+       if (score->score == score->total)
+               score->pass = true;
}

/* Gcc's warn_unused_result is fascist bullshit. */
#define doesnt_matter()

-static void run_under_debugger(struct manifest *m, void *check_result)
+static void run_under_debugger(struct manifest *m, struct score *score)
{
char *command;
-       struct list_head *list = check_result;
-       struct run_tests_result *first;
+       struct file_error *first;

if (!ask("Should I run the first failing test under the debugger?"))
return;

-       first = list_top(list, struct run_tests_result, list);
+       first = list_top(&score->per_file_errors, struct file_error, list);
command = talloc_asprintf(m, "gdb -ex 'break tap.c:136' -ex 'run' %s",
first->file->compiled);
if (system(command))
@@ -115,12 +68,9 @@ static void run_under_debugger(struct manifest *m, void *check_result)
struct ccanlint run_tests = {
.key = "run",
.name = "Module's run and api tests pass",
-       .score = score_run_tests,
-       .total_score = 1,
.check = do_run_tests,
-       .describe = describe_run_tests,
+       .handle = run_under_debugger,
.can_run = can_run,
-       .handle = run_under_debugger
};

REGISTER_TEST(run_tests, &compile_tests, NULL);
index caf8323c2cfa26cf53257d226f698e69ac6a9a6c..e0c2ab9197db29d8fbe60c2194d1cbbd9e68e4d1 100644 (file)
@@ -2,6 +2,7 @@
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
+#include <ccan/foreach/foreach.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static const char *can_run_vg(struct manifest *m)
{
unsigned int timeleft = default_timeout_ms;
-       char *output = run_command(m, &timeleft, "valgrind -q --error-exitcode=0 true");
+       char *output = run_command(m, &timeleft,
+                                  "valgrind -q --error-exitcode=0 true");

if (output)
return talloc_asprintf(m, "No valgrind support: %s", output);
return NULL;
}

-struct run_tests_result {
-       struct list_node list;
-       struct ccan_file *file;
-       const char *output;
-};
-
-static void *do_run_tests_vg(struct manifest *m,
+/* FIXME: Run examples, too! */
+static void do_run_tests_vg(struct manifest *m,
bool keep,
-                            unsigned int *timeleft)
+                           unsigned int *timeleft,
+                           struct score *score)
{
-       struct run_tests_result *res;
struct ccan_file *i;
char *cmdout;

-       run_tests_vg.total_score = 0;
-
-       list_for_each(&m->run_tests, i, list) {
-               run_tests_vg.total_score++;
-               cmdout = run_command(m, timeleft,
-                                    "valgrind -q --error-exitcode=100 %s",
-                                    i->compiled);
-               if (cmdout) {
-                       res = talloc(list, struct run_tests_result);
-                       res->file = i;
-                       res->output = talloc_steal(res, cmdout);
-               }
-       }
-
-       list_for_each(&m->api_tests, i, list) {
-               run_tests_vg.total_score++;
-               cmdout = run_command(m, timeleft,
+       score->total = 0;
+       foreach_ptr(list, &m->run_tests, &m->api_tests) {
+               list_for_each(list, i, list) {
+                       score->total++;
+                       cmdout = run_command(m, timeleft,
"valgrind -q --error-exitcode=100 %s",
i->compiled);
-               if (cmdout) {
-                       res = talloc(list, struct run_tests_result);
-                       res->file = i;
-                       res->output = talloc_steal(res, cmdout);
+                       if (cmdout) {
+                               score->error = "Running under valgrind";
+                               score_file_error(score, i, 0, cmdout);
+                       } else
+                               score->score++;
}
}

-       if (list_empty(list)) {
-               talloc_free(list);
-               list = NULL;
-       }
-
-       return list;
-}
-
-static unsigned int score_run_tests_vg(struct manifest *m, void *check_result)
-{
-       struct list_head *list = check_result;
-       struct run_tests_result *i;
-       unsigned int score = run_tests_vg.total_score;
-
-       list_for_each(list, i, list)
-               score--;
-       return score;
-}
-
-static const char *describe_run_tests_vg(struct manifest *m,
-                                        void *check_result)
-{
-       struct list_head *list = check_result;
-       char *descrip = talloc_strdup(check_result, "Running tests under valgrind failed:\n");
-       struct run_tests_result *i;
-
-       list_for_each(list, i, list)
-               descrip = talloc_asprintf_append(descrip, "Running %s:\n%s",
-                                                i->file->name, i->output);
-       return descrip;
+       if (score->score == score->total)
+               score->pass = true;
}

/* Gcc's warn_unused_result is fascist bullshit. */
#define doesnt_matter()

-static void run_under_debugger_vg(struct manifest *m, void *check_result)
+static void run_under_debugger_vg(struct manifest *m, struct score *score)
{
-       struct list_head *list = check_result;
-       struct run_tests_result *first;
+       struct file_error *first;
char *command;

if (!ask("Should I run the first failing test under the debugger?"))
return;

-       first = list_top(list, struct run_tests_result, list);
+       first = list_top(&score->per_file_errors, struct file_error, list);
command = talloc_asprintf(m, "valgrind --db-attach=yes %s",
first->file->compiled);
if (system(command))
@@ -123,11 +77,8 @@ static void run_under_debugger_vg(struct manifest *m, void *check_result)
struct ccanlint run_tests_vg = {
.key = "valgrind-tests",
.name = "Module's run and api tests succeed under valgrind",
-       .score = score_run_tests_vg,
-       .total_score = 1,
-       .check = do_run_tests_vg,
-       .describe = describe_run_tests_vg,
.can_run = can_run_vg,
+       .check = do_run_tests_vg,
.handle = run_under_debugger_vg
};

index 439fc06d1b67907bf5096a2c4457afb89a533a6a..2d344435e9ff908233f9d82babb08a801e5fa4ca 100644 (file)
@@ -1,10 +1,11 @@
/* Trailing whitespace test.  Almost embarrassing, but trivial. */
#include <tools/ccanlint/ccanlint.h>
#include <ccan/talloc/talloc.h>
+#include <ccan/foreach/foreach.h>
#include <ccan/str/str.h>

/* FIXME: only print full analysis if verbose >= 2.  */
-static char *report_on_trailing_whitespace(const char *line)
+static char *get_trailing_whitespace(const char *line)
{
const char *e = strchr(line, 0);
while (e>line && (e[-1]==' ' || e[-1]=='\t'))
@@ -20,36 +21,38 @@ static char *report_on_trailing_whitespace(const char *line)
return talloc_asprintf(line, "'%s'", line);
}

-static void *check_trailing_whitespace(struct manifest *m,
-                                      bool keep,
-                                      unsigned int *timeleft)
+static void check_trailing_whitespace(struct manifest *m,
+                                     bool keep,
+                                     unsigned int *timeleft,
+                                     struct score *score)
{
-       char *report;
-
-       report = report_on_lines(&m->c_files, report_on_trailing_whitespace,
-                                NULL);
-       report = report_on_lines(&m->h_files, report_on_trailing_whitespace,
-                                report);
-
-       return report;
-}
-
-static const char *describe_trailing_whitespace(struct manifest *m,
-                                               void *check_result)
-{
-       if (!verbose)
-               return NULL;
-       return talloc_asprintf(check_result,
-                              "Some source files have trailing whitespace:\n"
-                              "%s", (char *)check_result);
+       struct ccan_file *f;
+       unsigned int i;
+
+       foreach_ptr(list, &m->c_files, &m->h_files) {
+               list_for_each(list, f, list) {
+                       char **lines = get_ccan_file_lines(f);
+                       for (i = 0; i < f->num_lines; i++) {
+                               char *err = get_trailing_whitespace(lines[i]);
+                               if (err) {
+                                       score->error = "Trailing whitespace"
+                                               "found";
+                                       score_file_error(score, f, i+1, err);
+                               }
+                       }
+               }
+       }
+       if (!score->error) {
+               score->pass = true;
+               score->score = score->total;
+       }
}

struct ccanlint trailing_whitespace = {
.key = "trailing-whitespace",
.name = "Module's source code has no trailing whitespace",
-       .total_score = 1,
.check = check_trailing_whitespace,
-       .describe = describe_trailing_whitespace,
};