From f9492529ffcc609036bb817561ee2a20546071ab Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 25 Sep 2010 22:06:20 +0930 Subject: [PATCH] tools/ccanlint: extract examples in separate test. This is a precursor to doing something useful with them. --- tools/ccanlint/ccanlint.h | 1 + tools/ccanlint/file_analysis.c | 1 + tools/ccanlint/tests/has_examples.c | 141 ++++++++++++++++++ tools/ccanlint/tests/has_info_documentation.c | 16 +- 4 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 tools/ccanlint/tests/has_examples.c diff --git a/tools/ccanlint/ccanlint.h b/tools/ccanlint/ccanlint.h index 3a79fb94..46d1fc9d 100644 --- a/tools/ccanlint/ccanlint.h +++ b/tools/ccanlint/ccanlint.h @@ -33,6 +33,7 @@ struct manifest { struct list_head other_test_files; struct list_head other_files; + struct list_head examples; /* From tests/check_depends_exist.c */ struct list_head dep_dirs; diff --git a/tools/ccanlint/file_analysis.c b/tools/ccanlint/file_analysis.c index 93baf8eb..4908a895 100644 --- a/tools/ccanlint/file_analysis.c +++ b/tools/ccanlint/file_analysis.c @@ -174,6 +174,7 @@ struct manifest *get_manifest(const void *ctx, const char *dir) list_head_init(&m->other_test_c_files); list_head_init(&m->other_test_files); list_head_init(&m->other_files); + list_head_init(&m->examples); list_head_init(&m->dep_dirs); olddir = talloc_getcwd(NULL); diff --git a/tools/ccanlint/tests/has_examples.c b/tools/ccanlint/tests/has_examples.c new file mode 100644 index 00000000..12035e62 --- /dev/null +++ b/tools/ccanlint/tests/has_examples.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Creates and adds an example file. */ +static char *add_example(struct manifest *m, struct ccan_file *source, + bool keep, + struct doc_section *example) +{ + char *name; + unsigned int i; + int fd; + struct ccan_file *f; + + name = maybe_temp_file(m, ".c", keep, + talloc_asprintf(m, "example-%s-%s", + source->name, + example->function)); + f = new_ccan_file(m, talloc_dirname(m, name), talloc_basename(m, name)); + talloc_steal(f, name); + list_add(&m->examples, &f->list); + + fd = open(f->fullname, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) + return talloc_asprintf(m, "Creating temporary file %s: %s", + f->fullname, strerror(errno)); + + for (i = 0; i < example->num_lines; i++) { + if (write(fd, example->lines[i], strlen(example->lines[i])) + != strlen(example->lines[i]) + || write(fd, "\n", 1) != 1) { + close(fd); + return "Failure writing to temporary file"; + } + } + close(fd); + return NULL; +} + +/* FIXME: We should have one example per function in header. */ +struct score { + bool info_example, header_example; + char *error; +}; + +static void *extract_examples(struct manifest *m, + bool keep, + unsigned int *timeleft) +{ + 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; + + 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; + } + } + + /* Check main header. */ + list_for_each(&m->h_files, f, list) { + if (!strstarts(f->name, m->basename) + || strlen(f->name) != strlen(m->basename) + 2) + continue; + + list_for_each(get_ccan_file_docs(f), d, list) { + if (streq(d->type, "example")) { + score->error = add_example(m, f, keep, d); + if (score->error) + return score; + score->header_example = true; + } + } + } + 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; + total += score->header_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"); + + if (!score->header_example) + 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; +} + +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); diff --git a/tools/ccanlint/tests/has_info_documentation.c b/tools/ccanlint/tests/has_info_documentation.c index 2823e66b..cdfb0e2c 100644 --- a/tools/ccanlint/tests/has_info_documentation.c +++ b/tools/ccanlint/tests/has_info_documentation.c @@ -19,7 +19,6 @@ struct info_docs { bool summary; bool description; - bool example; }; static void *check_has_info_documentation(struct manifest *m, @@ -28,7 +27,7 @@ static void *check_has_info_documentation(struct manifest *m, { struct list_head *infodocs = get_ccan_file_docs(m->info_file); struct doc_section *d; - struct info_docs id = { false, false, false }; + struct info_docs id = { false, false }; list_for_each(infodocs, d, list) { if (!streq(d->function, m->basename)) @@ -37,11 +36,9 @@ static void *check_has_info_documentation(struct manifest *m, id.summary = true; if (streq(d->type, "description")) id.description = true; - if (streq(d->type, "example")) - id.example = true; } - if (id.summary && id.description && id.example) + if (id.summary && id.description) return NULL; return talloc_memdup(m, &id, sizeof(id)); } @@ -109,11 +106,6 @@ static const char *describe_has_info_documentation(struct manifest *m, "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"); - if (!id->example) - reason = talloc_asprintf_append(reason, - "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"); return reason; } @@ -121,13 +113,13 @@ static unsigned int has_info_documentation_score(struct manifest *m, void *check_result) { struct info_docs *id = check_result; - return id->summary + id->description + id->example; + return (unsigned int)id->summary + id->description; } struct ccanlint has_info_documentation = { .key = "info-documentation", .name = "Module has documentation in _info", - .total_score = 3, + .total_score = 2, .score = has_info_documentation_score, .check = check_has_info_documentation, .describe = describe_has_info_documentation, -- 2.39.2