ccanlint: print coverage amount when -vv
[ccan] / tools / ccanlint / tests / info_documentation_exists.c
1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/doc_extract.h>
3 #include <tools/tools.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <limits.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <err.h>
13 #include <ccan/str/str.h>
14 #include <ccan/talloc/talloc.h>
15 #include <ccan/noerr/noerr.h>
16 #include <ccan/grab_file/grab_file.h>
17
18 REGISTER_TEST(info_documentation_exists);
19
20 static void create_info_template_doc(struct manifest *m, struct score *score)
21 {
22         int fd = open("_info.new", O_WRONLY|O_CREAT|O_EXCL, 0666);
23         FILE *new;
24         char *oldcontents;
25
26         if (fd < 0 || !(new = fdopen(fd, "w")))
27                 err(1, "Creating _info.new to insert documentation");
28
29         if (fprintf(new,
30                     "/**\n"
31                     " * %s - [[ONE LINE DESCRIPTION HERE]]\n"
32                     " *\n"
33                     " * Paragraphs why %s exists and where to use it.\n"
34                     " *\n"
35                     " * Followed by an Example: section with a standalone\n"
36                     " * (trivial and usually useless) program\n"
37                     " */\n", m->basename, m->basename) < 0) {
38                 unlink_noerr("_info.new");
39                 err(1, "Writing to _info.new to insert documentation");
40         }
41
42         oldcontents = grab_file(m, "_info", NULL);
43         if (!oldcontents) {
44                 unlink_noerr("_info.new");
45                 err(1, "Reading _info");
46         }
47         if (fprintf(new, "%s", oldcontents) < 0) {
48                 unlink_noerr("_info.new");
49                 err(1, "Appending _info to _info.new");
50         }
51         if (fclose(new) != 0) {
52                 unlink_noerr("_info.new");
53                 err(1, "Closing _info.new");
54         }
55         if (!move_file("_info.new", "_info")) {
56                 unlink_noerr("_info.new");
57                 err(1, "Renaming _info.new to _info");
58         }
59 }
60
61 static void check_info_documentation_exists(struct manifest *m,
62                                          bool keep,
63                                          unsigned int *timeleft,
64                                          struct score *score)
65 {
66         struct list_head *infodocs = get_ccan_file_docs(m->info_file);
67         struct doc_section *d;
68         bool summary = false, description = false;
69
70         list_for_each(infodocs, d, list) {
71                 if (!streq(d->function, m->basename))
72                         continue;
73                 if (streq(d->type, "summary"))
74                         summary = true;
75                 if (streq(d->type, "description"))
76                         description = true;
77         }
78
79         if (summary && description) {
80                 score->score = score->total;
81                 score->pass = true;
82         } else if (!summary) {
83                 score->error = talloc_strdup(score,
84                 "_info file has no module documentation.\n\n"
85                 "CCAN modules use /**-style comments for documentation: the\n"
86                 "overall documentation belongs in the _info metafile.\n");
87                 info_documentation_exists.handle = create_info_template_doc;
88         } else if (!description)  {
89                 score->error = talloc_strdup(score,
90                 "_info file has no module description.\n\n"
91                 "The lines after the first summary line in the _info file\n"
92                 "documentation should describe the purpose and use of the\n"
93                 "overall package\n");
94         }
95 }
96
97 struct ccanlint info_documentation_exists = {
98         .key = "info_documentation_exists",
99         .name = "Module has documentation in _info",
100         .check = check_info_documentation_exists,
101         .needs = "info_exists"
102 };
103