cb093264c74ba7d2a3500c49fe6b2151f6518395
[ccan] / tools / ccanlint / tests / tests_pass.c
1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/tools.h>
3 #include <ccan/take/take.h>
4 #include <ccan/str/str.h>
5 #include <ccan/foreach/foreach.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <limits.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <err.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include "tests_pass.h"
18
19 bool do_valgrind = false;
20
21 static const char *can_run(struct manifest *m)
22 {
23         unsigned int timeleft = default_timeout_ms;
24         char *output;
25         if (safe_mode)
26                 return "Safe mode enabled";
27
28         if (!is_excluded("tests_pass_valgrind")
29             && run_command(m, &timeleft, &output,
30                            "valgrind -q true"))
31                 do_valgrind = true;
32
33         return NULL;
34 }
35
36 static const char *concat(struct score *score, char *bits[])
37 {
38         unsigned int i;
39         char *ret = tal_strdup(score, "");
40
41         for (i = 0; bits[i]; i++) {
42                 if (i)
43                         ret = tal_strcat(score, take(ret), " ");
44                 ret = tal_strcat(score, take(ret), bits[i]);
45         }
46         return ret;
47 }
48
49 static void run_test(void *ctx,
50                      struct manifest *m,
51                      unsigned int *timeleft,
52                      struct ccan_file *i)
53 {
54         if (do_valgrind) {
55                 const char *options;
56                 options = concat(ctx,
57                                  per_file_options(&tests_pass_valgrind, i));
58
59                 if (!streq(options, "FAIL")) {
60                         /* FIXME: Valgrind's output sucks.  XML is
61                          * unreadable by humans *and* doesn't support
62                          * children reporting. */
63                         i->valgrind_log = tal_fmt(m,
64                                           "%s.valgrind-log",
65                                           i->compiled[COMPILE_NORMAL]);
66
67                         run_command_async(i, *timeleft,
68                                           "valgrind -q"
69                                           " --leak-check=full"
70                                           " --log-fd=3 %s %s"
71                                           " 3> %s",
72                                           options,
73                                           i->compiled[COMPILE_NORMAL],
74                                           i->valgrind_log);
75                         return;
76                 }
77         }
78
79         run_command_async(i, *timeleft, "%s",
80                           i->compiled[COMPILE_NORMAL]);
81 }
82
83 static void do_run_tests(struct manifest *m,
84                          unsigned int *timeleft,
85                          struct score *score)
86 {
87         struct list_head *list;
88         struct ccan_file *i;
89         char *cmdout;
90         bool ok;
91
92         score->total = 0;
93         foreach_ptr(list, &m->run_tests, &m->api_tests) {
94                 list_for_each(list, i, list) {
95                         score->total++;
96                         if (verbose >= 2)
97                                 printf("   %s...\n", i->name);
98                         run_test(score, m, timeleft, i);
99                 }
100         }
101
102         while ((i = collect_command(&ok, &cmdout)) != NULL) {
103                 if (!ok)
104                         score_file_error(score, i, 0, "%s", cmdout);
105                 else
106                         score->score++;
107                 if (verbose >= 2)
108                         printf("   ...%s\n", i->name);
109         }
110
111         if (score->score == score->total)
112                 score->pass = true;
113 }
114
115
116 /* Gcc's warn_unused_result is fascist bullshit. */
117 #define doesnt_matter()
118
119 static void run_under_debugger(struct manifest *m, struct score *score)
120 {
121         char *command;
122         struct file_error *first;
123
124         first = list_top(&score->per_file_errors, struct file_error, list);
125
126         if (!ask("Should I run the first failing test under the debugger?"))
127                 return;
128
129         command = tal_fmt(m, "gdb -ex 'break tap.c:139' -ex 'run' %s",
130                           first->file->compiled[COMPILE_NORMAL]);
131         if (system(command))
132                 doesnt_matter();
133 }
134
135 struct ccanlint tests_pass = {
136         .key = "tests_pass",
137         .name = "Module's run and api tests pass",
138         .check = do_run_tests,
139         .handle = run_under_debugger,
140         .can_run = can_run,
141         .needs = "tests_compile"
142 };
143
144 REGISTER_TEST(tests_pass);