15df1ed69e7cefc8315a780cf47d3904732ab76d
[ccan] / tools / ccanlint / tests / tests_pass.c
1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/tools.h>
3 #include <ccan/talloc/talloc.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 = talloc_strdup(score, "");
40
41         for (i = 0; bits[i]; i++) {
42                 if (i)
43                         ret = talloc_append_string(ret, " ");
44                 ret = talloc_append_string(ret, bits[i]);
45         }
46         return ret;
47 }
48
49 static bool run_test(void *ctx,
50                      struct manifest *m,
51                      unsigned int *timeleft, char **cmdout,
52                      struct ccan_file *i,
53                      bool use_valgrind)
54 {
55         if (use_valgrind) {
56                 const char *options;
57                 options = concat(ctx,
58                                  per_file_options(&tests_pass_valgrind, i));
59
60                 if (!streq(options, "FAIL")) {
61                         /* FIXME: Valgrind's output sucks.  XML is
62                          * unreadable by humans *and* doesn't support
63                          * children reporting. */
64                         i->valgrind_log = talloc_asprintf(m,
65                                                           "%s.valgrind-log",
66                                                           i->compiled);
67                         talloc_set_destructor(i->valgrind_log,
68                                               unlink_file_destructor);
69
70                         return run_command(ctx, timeleft, cmdout,
71                                            "valgrind -q"
72                                            " --leak-check=full"
73                                            " --log-fd=3 %s %s"
74                                            " 3> %s",
75                                            options,
76                                            i->compiled, i->valgrind_log);
77                 }
78         }
79
80         return run_command(m, timeleft, cmdout, "%s", i->compiled);
81 }
82
83 static void run_tests(struct manifest *m,
84                       bool keep,
85                       unsigned int *timeleft,
86                       struct score *score,
87                       bool use_valgrind)
88 {
89         struct list_head *list;
90         struct ccan_file *i;
91         char *cmdout;
92
93         score->total = 0;
94         foreach_ptr(list, &m->run_tests, &m->api_tests) {
95                 list_for_each(list, i, list) {
96                         score->total++;
97                         if (run_test(score, m, timeleft, &cmdout, i,
98                                      use_valgrind))
99                                 score->score++;
100                         else
101                                 score_file_error(score, i, 0, "%s", cmdout);
102                 }
103         }
104
105         if (score->score == score->total)
106                 score->pass = true;
107 }
108
109 static void do_run_tests(struct manifest *m,
110                          bool keep,
111                          unsigned int *timeleft,
112                          struct score *score)
113 {
114         run_tests(m, keep, timeleft, score, do_valgrind);
115 }
116
117 static void do_run_tests_without_features(struct manifest *m,
118                                           bool keep,
119                                           unsigned int *timeleft,
120                                           struct score *score)
121 {
122         run_tests(m, keep, timeleft, score, false);
123 }
124
125 /* Gcc's warn_unused_result is fascist bullshit. */
126 #define doesnt_matter()
127
128 static void run_under_debugger(struct manifest *m, struct score *score)
129 {
130         char *command;
131         struct file_error *first;
132
133         first = list_top(&score->per_file_errors, struct file_error, list);
134
135         if (!ask("Should I run the first failing test under the debugger?"))
136                 return;
137
138         command = talloc_asprintf(m, "gdb -ex 'break tap.c:139' -ex 'run' %s",
139                                   first->file->compiled);
140         if (system(command))
141                 doesnt_matter();
142 }
143
144 struct ccanlint tests_pass = {
145         .key = "tests_pass",
146         .name = "Module's run and api tests pass",
147         .check = do_run_tests,
148         .handle = run_under_debugger,
149         .can_run = can_run,
150         .needs = "tests_compile"
151 };
152
153 REGISTER_TEST(tests_pass);
154
155 struct ccanlint tests_pass_without_features = {
156         .key = "tests_pass_without_features",
157         .name = "Module's run and api tests pass (without features)",
158         .check = do_run_tests_without_features,
159         .handle = run_under_debugger,
160         .needs = "tests_compile_without_features"
161 };
162
163 REGISTER_TEST(tests_pass_without_features);