Commit 4e0dfdad authored by Rusty Russell's avatar Rusty Russell

ccanlint: compile and run tests.

This means we should skip building if there are no C files in module: running tests requires building the module, but not necessarily that it has any C files.
parent 3f011090
......@@ -22,6 +22,7 @@ struct manifest {
struct list_head api_tests;
struct list_head compile_ok_tests;
struct list_head compile_fail_tests;
struct list_head other_test_c_files;
struct list_head other_test_files;
struct list_head other_files;
......@@ -124,6 +125,9 @@ struct ccan_file {
struct line_info *line_info;
struct list_head *doc_sections;
/* If this file gets compiled (eg. .C file to .o file), result here. */
const char *compiled;
};
/* A new ccan_file, with the given name (talloc_steal onto returned value). */
......
......@@ -40,6 +40,7 @@ struct ccan_file *new_ccan_file(const void *ctx, char *name)
f->lines = NULL;
f->line_info = NULL;
f->doc_sections = NULL;
f->compiled = NULL;
f->name = talloc_steal(f, name);
return f;
}
......@@ -115,7 +116,7 @@ static void add_files(struct manifest *m, const char *dir)
else if (strstarts(f->name, "test/compile_fail"))
dest = &m->compile_fail_tests;
else
dest = &m->other_test_files;
dest = &m->other_test_c_files;
} else
dest = &m->other_test_files;
} else
......@@ -162,6 +163,7 @@ struct manifest *get_manifest(const void *ctx)
list_head_init(&m->run_tests);
list_head_init(&m->compile_ok_tests);
list_head_init(&m->compile_fail_tests);
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->dep_dirs);
......
......@@ -16,8 +16,6 @@
static const char *can_build(struct manifest *m)
{
if (list_empty(&m->c_files))
return "No C files in module";
if (safe_mode)
return "Safe mode enabled";
return NULL;
......@@ -39,6 +37,11 @@ static char *obj_list(const struct manifest *m)
/* We leave this object file around after ccanlint runs, all built. */
static void *do_build(struct manifest *m)
{
if (list_empty(&m->c_files)) {
/* No files? No score, but we "pass". */
build.total_score = 0;
return NULL;
}
return run_command(m, "ld -r -o ../%s.o %s", m->basename, obj_list(m));
}
......
......@@ -16,8 +16,6 @@
static const char *can_build(struct manifest *m)
{
if (list_empty(&m->c_files))
return "No C files in module";
if (safe_mode)
return "Safe mode enabled";
return NULL;
......
......@@ -46,7 +46,7 @@ static char *lib_list(const struct manifest *m)
char *ret = talloc_strdup(m, "");
for (i = 0; i < num; i++)
ret = talloc_asprintf_append(ret, "-l %s ", libs[i]);
ret = talloc_asprintf_append(ret, "-l%s ", libs[i]);
return ret;
}
......
......@@ -50,11 +50,11 @@ static bool expect_obj_file(const char *dir)
static void *check_depends_built(struct manifest *m)
{
struct ccan_file *i;
struct stat st;
char *report = NULL;
list_for_each(&m->dep_dirs, i, list) {
char *objfile;
struct stat st;
if (!expect_obj_file(i->name))
continue;
......@@ -70,6 +70,17 @@ static void *check_depends_built(struct manifest *m)
}
}
/* We may need libtap for testing, unless we're "tap" */
if (!streq(m->basename, "tap")
&& (!list_empty(&m->run_tests) || !list_empty(&m->api_tests))) {
if (stat("../tap.o", &st) != 0) {
report = talloc_asprintf_append(report,
"object file ../tap.o"
" (for tests)\n");
}
}
return talloc_steal(m, report);
}
......
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.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>
static const char *can_build(struct manifest *m)
{
if (safe_mode)
return "Safe mode enabled";
return NULL;
}
static int cleanup_testfile(char *testfile)
{
unlink(testfile);
return 0;
}
static char *objname(const void *ctx, const char *cfile)
{
return talloc_asprintf(ctx, "%.*s.o ", strlen(cfile) - 2, cfile);
}
static char *compile(struct manifest *m, const char *cfile)
{
char *obj;
obj = objname(m, cfile);
talloc_set_destructor(obj, cleanup_testfile);
return run_command(m, "cc " CFLAGS " -c -o %s %s", obj, cfile);
}
static void *do_compile_test_helpers(struct manifest *m)
{
char *cmdout = NULL;
struct ccan_file *i;
list_for_each(&m->other_test_c_files, i, list) {
compile_tests.total_score++;
cmdout = compile(m, i->name);
if (cmdout)
return talloc_asprintf(m,
"Failed to compile helper C"
" code file %s:\n%s",
i->name, cmdout);
}
return NULL;
}
static const char *describe_compile_test_helpers(struct manifest *m,
void *check_result)
{
return check_result;
}
struct ccanlint compile_test_helpers = {
.name = "Compiling test helper files",
.total_score = 1,
.check = do_compile_test_helpers,
.describe = describe_compile_test_helpers,
.can_run = can_build,
};
REGISTER_TEST(compile_test_helpers, &depends_built);
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.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>
static const char *can_build(struct manifest *m)
{
if (safe_mode)
return "Safe mode enabled";
return NULL;
}
static char *obj_list(const struct manifest *m, bool link_with_module)
{
char *list = talloc_strdup(m, "../tap.o");
struct ccan_file *i;
/* Objects from any other C files. */
list_for_each(&m->other_test_c_files, i, list)
list = talloc_asprintf_append(list, " %.*s.o",
strlen(i->name) - 2, i->name);
if (link_with_module)
list = talloc_asprintf_append(list, " ../%s.o", m->basename);
return list;
}
static char *lib_list(const struct manifest *m)
{
unsigned int i, num;
char **libs = get_libs(m, ".", ".", &num);
char *ret = talloc_strdup(m, "");
for (i = 0; i < num; i++)
ret = talloc_asprintf_append(ret, "-l%s ", libs[i]);
return ret;
}
static int cleanup_testfile(const char *testfile)
{
unlink(testfile);
return 0;
}
static char *compile(const void *ctx,
struct manifest *m, struct ccan_file *file, bool fail,
bool link_with_module)
{
file->compiled = talloc_strdup(ctx, tempnam("/tmp", "ccanlint"));
talloc_set_destructor(file->compiled, cleanup_testfile);
return run_command(m, "cc " CFLAGS " %s -o %s %s %s %s",
fail ? "-DFAIL" : "",
file->compiled, file->name,
obj_list(m, link_with_module), lib_list(m));
}
struct compile_tests_result {
struct list_node list;
const char *filename;
const char *description;
const char *output;
};
static void *do_compile_tests(struct manifest *m)
{
struct list_head *list = talloc(m, struct list_head);
char *cmdout;
struct ccan_file *i;
struct compile_tests_result *res;
list_head_init(list);
compile_tests.total_score = 0;
list_for_each(&m->compile_ok_tests, i, list) {
compile_tests.total_score++;
cmdout = compile(list, m, i, false, false);
if (cmdout) {
res = talloc(list, struct compile_tests_result);
res->filename = i->name;
res->description = "failed to compile";
res->output = talloc_steal(res, cmdout);
list_add_tail(list, &res->list);
}
}
list_for_each(&m->run_tests, i, list) {
compile_tests.total_score++;
cmdout = compile(m, m, i, false, false);
if (cmdout) {
res = talloc(list, struct compile_tests_result);
res->filename = i->name;
res->description = "failed to compile";
res->output = talloc_steal(res, cmdout);
list_add_tail(list, &res->list);
}
}
list_for_each(&m->api_tests, i, list) {
compile_tests.total_score++;
cmdout = compile(m, m, i, false, true);
if (cmdout) {
res = talloc(list, struct compile_tests_result);
res->filename = i->name;
res->description = "failed to compile";
res->output = talloc_steal(res, cmdout);
list_add_tail(list, &res->list);
}
}
list_for_each(&m->compile_fail_tests, i, list) {
compile_tests.total_score++;
cmdout = compile(list, m, i, true, false);
if (cmdout) {
res = talloc(list, struct compile_tests_result);
res->filename = i->name;
res->description = "failed to compile without -DFAIL";
res->output = talloc_steal(res, cmdout);
list_add_tail(list, &res->list);
} else {
cmdout = compile(list, m, i, false, false);
if (!cmdout) {
res = talloc(list, struct compile_tests_result);
res->filename = i->name;
res->description = "compiled successfully"
" with -DFAIL";
res->output = "";
list_add_tail(list, &res->list);
}
}
}
if (list_empty(list)) {
talloc_free(list);
list = NULL;
}
return list;
}
static unsigned int score_compile_tests(struct manifest *m,
void *check_result)
{
struct list_head *list = check_result;
struct compile_tests_result *i;
unsigned int score = compile_tests.total_score;
list_for_each(list, i, list)
score--;
return score;
}
static const char *describe_compile_tests(struct manifest *m,
void *check_result)
{
struct list_head *list = check_result;
struct compile_tests_result *i;
char *descrip = talloc_strdup(list, "Compilation tests failed:\n");
list_for_each(list, i, list)
descrip = talloc_asprintf_append(descrip, "%s %s\n%s",
i->filename, i->description,
i->output);
return descrip;
}
struct ccanlint compile_tests = {
.name = "Compile tests succeed",
.total_score = 1,
.score = score_compile_tests,
.check = do_compile_tests,
.describe = describe_compile_tests,
.can_run = can_build,
};
REGISTER_TEST(compile_tests, &compile_test_helpers, NULL);
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.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>
static const char *can_run(struct manifest *m)
{
if (safe_mode)
return "Safe mode enabled";
return NULL;
}
static void *do_run_tests(struct manifest *m)
{
struct list_head *list = talloc(m, struct list_head);
char *failures = talloc_strdup(m, "");
struct ccan_file *i;
list_head_init(list);
run_tests.total_score = 0;
list_for_each(&m->run_tests, i, list) {
char *testout;
run_tests.total_score++;
/* FIXME: timeout here */
testout = run_command(m, i->compiled);
if (!testout)
continue;
failures = talloc_asprintf_append(failures,
"Running %s failed:\n",
i->name);
failures = talloc_append_string(failures, testout);
}
list_for_each(&m->api_tests, i, list) {
char *testout;
run_tests.total_score++;
/* FIXME: timeout here */
testout = run_command(m, i->compiled);
if (!testout)
continue;
failures = talloc_asprintf_append(failures,
"Running %s failed:\n",
i->name);
failures = talloc_append_string(failures, testout);
}
if (streq(failures, "")) {
talloc_free(failures);
failures = NULL;
}
return failures;
}
static unsigned int score_run_tests(struct manifest *m, void *check_result)
{
/* FIXME: be cleverer here */
return 0;
}
static const char *describe_run_tests(struct manifest *m,
void *check_result)
{
char *descrip = talloc_strdup(check_result, "Running tests failed:\n");
return talloc_append_string(descrip, check_result);
}
struct ccanlint run_tests = {
.name = "run and api tests run successfully",
.total_score = 1,
.score = score_run_tests,
.check = do_run_tests,
.describe = describe_run_tests,
.can_run = can_run,
};
REGISTER_TEST(run_tests, &compile_tests, NULL);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment