summaryrefslogtreecommitdiff
path: root/tools/ccanlint/tests/tests_pass.c
blob: af71dbe4c9f58cce4cc5da90a8e58da2c84b129b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/take/take.h>
#include <ccan/str/str.h>
#include <ccan/foreach/foreach.h>
#include <ccan/tal/path/path.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <string.h>
#include <ctype.h>
#include "tests_pass.h"

bool do_valgrind = false;
const char *valgrind_suppress = "";

static const char *can_run(struct manifest *m)
{
	unsigned int timeleft = default_timeout_ms;
	char *output;
	if (safe_mode)
		return "Safe mode enabled";

	if (!is_excluded("tests_pass_valgrind")
	    && run_command(m, &timeleft, &output,
			   "valgrind -q true")) {
		const char *sfile;

		do_valgrind = true;

		/* Check for suppressions file for all of CCAN. */
		sfile = path_join(m, ccan_dir, ".valgrind_suppressions");
		if (path_is_file(sfile))
			valgrind_suppress = tal_fmt(m, "--suppressions=%s",
						    sfile);
	}

	return NULL;
}

static const char *concat(struct score *score, char *bits[])
{
	unsigned int i;
	char *ret = tal_strdup(score, "");

	for (i = 0; bits[i]; i++) {
		if (i)
			ret = tal_strcat(score, take(ret), " ");
		ret = tal_strcat(score, take(ret), bits[i]);
	}
	return ret;
}

static void run_test(void *ctx,
		     struct manifest *m,
		     unsigned int *timeleft,
		     struct ccan_file *i)
{
	if (do_valgrind) {
		const char *options;
		options = concat(ctx,
				 per_file_options(&tests_pass_valgrind, i));

		if (!streq(options, "FAIL")) {
			/* FIXME: Valgrind's output sucks.  XML is
			 * unreadable by humans *and* doesn't support
			 * children reporting. */
			i->valgrind_log = tal_fmt(m,
					  "%s.valgrind-log",
					  i->compiled[COMPILE_NORMAL]);

			run_command_async(i, *timeleft,
					  "valgrind -q"
					  " --leak-check=full"
					  " --log-fd=3 %s %s %s"
					  " 3> %s",
					  valgrind_suppress, options,
					  i->compiled[COMPILE_NORMAL],
					  i->valgrind_log);
			return;
		}
	}

	run_command_async(i, *timeleft, "%s",
			  i->compiled[COMPILE_NORMAL]);
}

static void do_run_tests(struct manifest *m,
			 unsigned int *timeleft,
			 struct score *score)
{
	struct list_head *list;
	struct ccan_file *i;
	char *cmdout;
	bool ok;

	score->total = 0;
	foreach_ptr(list, &m->run_tests, &m->api_tests) {
		list_for_each(list, i, list) {
			score->total++;
			if (verbose >= 2)
				printf("   %s...\n", i->name);
			run_test(score, m, timeleft, i);
		}
	}

	while ((i = collect_command(&ok, &cmdout)) != NULL) {
		if (!ok)
			score_file_error(score, i, 0, "%s", cmdout);
		else
			score->score++;
		if (verbose >= 2)
			printf("   ...%s\n", i->name);
	}

	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, struct score *score)
{
	char *command;
	struct file_error *first;

	first = list_top(&score->per_file_errors, struct file_error, list);

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

	command = tal_fmt(m, "gdb -ex 'break tap.c:139' -ex 'run' %s",
			  first->file->compiled[COMPILE_NORMAL]);
	if (system(command))
		doesnt_matter();
}

struct ccanlint tests_pass = {
	.key = "tests_pass",
	.name = "Module's run and api tests pass",
	.check = do_run_tests,
	.handle = run_under_debugger,
	.can_run = can_run,
	.needs = "tests_compile"
};

REGISTER_TEST(tests_pass);