ccanlint.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /*
  2. * ccanlint: assorted checks and advice for a ccan package
  3. * Copyright (C) 2008 Rusty Russell, Idris Soule
  4. * Copyright (C) 2010 Rusty Russell, Idris Soule
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 2 of the License, or (at your option)
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along with
  17. * this program; if not, write to the Free Software Foundation, Inc., 51
  18. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include "ccanlint.h"
  21. #include "../tools.h"
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <err.h>
  27. #include <ctype.h>
  28. #include <ccan/btree/btree.h>
  29. #include <ccan/str/str.h>
  30. #include <ccan/str_talloc/str_talloc.h>
  31. #include <ccan/talloc/talloc.h>
  32. #include <ccan/opt/opt.h>
  33. #include <ccan/foreach/foreach.h>
  34. #include <ccan/grab_file/grab_file.h>
  35. #include <ccan/cast/cast.h>
  36. #include <ccan/tlist/tlist.h>
  37. #include <ccan/strmap/strmap.h>
  38. struct ccanlint_map {
  39. STRMAP_MEMBERS(struct ccanlint *);
  40. };
  41. int verbose = 0;
  42. static struct ccanlint_map tests;
  43. bool safe_mode = false;
  44. static bool targeting = false;
  45. static struct btree *cmdline_exclude;
  46. static struct btree *info_exclude;
  47. static unsigned int timeout;
  48. static struct dgraph_node all;
  49. /* These are overridden at runtime if we can find config.h */
  50. const char *compiler = NULL;
  51. const char *cflags = NULL;
  52. const char *config_header;
  53. #if 0
  54. static void indent_print(const char *string)
  55. {
  56. while (*string) {
  57. unsigned int line = strcspn(string, "\n");
  58. printf("\t%.*s", line, string);
  59. if (string[line] == '\n') {
  60. printf("\n");
  61. line++;
  62. }
  63. string += line;
  64. }
  65. }
  66. #endif
  67. bool ask(const char *question)
  68. {
  69. char reply[80];
  70. printf("%s ", question);
  71. fflush(stdout);
  72. return fgets(reply, sizeof(reply), stdin) != NULL
  73. && toupper(reply[0]) == 'Y';
  74. }
  75. static const char *should_skip(struct manifest *m, struct ccanlint *i)
  76. {
  77. if (btree_lookup(cmdline_exclude, i->key))
  78. return "excluded on command line";
  79. if (btree_lookup(info_exclude, i->key))
  80. return "excluded in _info file";
  81. if (i->skip)
  82. return i->skip;
  83. if (i->skip_fail)
  84. return "dependency failed";
  85. if (i->can_run)
  86. return i->can_run(m);
  87. return NULL;
  88. }
  89. static bool skip_node(struct dgraph_node *to, const char *failmsg)
  90. {
  91. struct ccanlint *c = container_of(to, struct ccanlint, node);
  92. if (!c->skip) {
  93. if (failmsg) {
  94. c->skip = failmsg;
  95. c->skip_fail = true;
  96. } else {
  97. c->skip = "dependency was skipped";
  98. }
  99. }
  100. return true;
  101. }
  102. struct run_info {
  103. bool quiet;
  104. unsigned int score, total;
  105. struct manifest *m;
  106. const char *prefix;
  107. bool pass;
  108. };
  109. static bool run_test(struct dgraph_node *n, struct run_info *run)
  110. {
  111. struct ccanlint *i = container_of(n, struct ccanlint, node);
  112. unsigned int timeleft;
  113. const char *skip;
  114. struct score *score;
  115. if (i->done)
  116. return true;
  117. score = talloc(run->m, struct score);
  118. list_head_init(&score->per_file_errors);
  119. score->error = NULL;
  120. score->pass = false;
  121. score->score = 0;
  122. score->total = 1;
  123. skip = should_skip(run->m, i);
  124. if (skip) {
  125. skip:
  126. if (verbose)
  127. printf("%s%s: skipped (%s)\n",
  128. run->prefix, i->name, skip);
  129. /* If we're skipping this because a prereq failed, we fail:
  130. * count it as a score of 1. */
  131. if (i->skip_fail)
  132. run->total++;
  133. dgraph_traverse_from(&i->node, skip_node,
  134. i->skip_fail ? "dependency failed" : NULL);
  135. dgraph_clear_node(&i->node);
  136. score->pass = i->skip_fail ? false : true;
  137. goto out;
  138. }
  139. timeleft = timeout ? timeout : default_timeout_ms;
  140. i->check(run->m, i->keep_results, &timeleft, score);
  141. if (timeout && timeleft == 0) {
  142. skip = "timeout";
  143. goto skip;
  144. }
  145. assert(score->score <= score->total);
  146. if ((!score->pass && !run->quiet)
  147. || (score->score < score->total && verbose)
  148. || verbose > 1) {
  149. printf("%s%s (%s): %s",
  150. run->prefix, i->name, i->key,
  151. score->pass ? "PASS" : "FAIL");
  152. if (score->total > 1)
  153. printf(" (+%u/%u)", score->score, score->total);
  154. printf("\n");
  155. }
  156. if ((!run->quiet && !score->pass) || verbose) {
  157. if (score->error) {
  158. printf("%s%s", score->error,
  159. strends(score->error, "\n") ? "" : "\n");
  160. }
  161. }
  162. if (!run->quiet && score->score < score->total && i->handle)
  163. i->handle(run->m, score);
  164. run->score += score->score;
  165. run->total += score->total;
  166. if (!score->pass) {
  167. /* Skip any tests which depend on this one. */
  168. dgraph_traverse_from(&i->node, skip_node, "dependency failed");
  169. }
  170. dgraph_clear_node(&i->node);
  171. out:
  172. /* FIXME: Free score. */
  173. run->pass &= score->pass;
  174. i->done = true;
  175. if (!score->pass && i->compulsory) {
  176. warnx("%s%s failed", run->prefix, i->name);
  177. run->score = 0;
  178. return false;
  179. }
  180. return true;
  181. }
  182. static void register_test(struct ccanlint *test)
  183. {
  184. if (!strmap_add(&tests, test->key, test))
  185. err(1, "Adding test %s", test->key);
  186. test->options = talloc_array(NULL, char *, 1);
  187. test->options[0] = NULL;
  188. dgraph_init_node(&test->node);
  189. dgraph_add_edge(&test->node, &all);
  190. test->done = false;
  191. }
  192. static bool get_test(const char *member, struct ccanlint *i,
  193. struct ccanlint **ret)
  194. {
  195. if (tlist_empty(&i->node.edge[DGRAPH_TO])) {
  196. *ret = i;
  197. return false;
  198. }
  199. return true;
  200. }
  201. /**
  202. * get_next_test - retrieves the next test to be processed
  203. **/
  204. static inline struct ccanlint *get_next_test(void)
  205. {
  206. struct ccanlint *i = NULL;
  207. strmap_iterate(&tests, get_test, &i);
  208. if (i)
  209. return i;
  210. if (strmap_empty(&tests))
  211. return NULL;
  212. errx(1, "Can't make process; test dependency cycle");
  213. }
  214. static struct ccanlint *find_test(const char *key)
  215. {
  216. return strmap_get(&tests, key);
  217. }
  218. bool is_excluded(const char *name)
  219. {
  220. return btree_lookup(cmdline_exclude, name) != NULL
  221. || btree_lookup(info_exclude, name) != NULL
  222. || find_test(name)->skip != NULL;
  223. }
  224. static bool reset_deps(const char *member, struct ccanlint *c, void *unused)
  225. {
  226. char **deps = strsplit(NULL, c->needs, " ");
  227. unsigned int i;
  228. c->skip = NULL;
  229. c->skip_fail = false;
  230. for (i = 0; deps[i]; i++) {
  231. struct ccanlint *dep;
  232. dep = find_test(deps[i]);
  233. if (!dep)
  234. errx(1, "BUG: unknown dep '%s' for %s",
  235. deps[i], c->key);
  236. dgraph_add_edge(&dep->node, &c->node);
  237. }
  238. talloc_free(deps);
  239. return true;
  240. }
  241. static bool check_names(const char *member, struct ccanlint *c,
  242. struct ccanlint_map *names)
  243. {
  244. if (!strmap_add(names, c->name, c))
  245. err(1, "Duplicate name %s", c->name);
  246. return true;
  247. }
  248. #undef REGISTER_TEST
  249. #define REGISTER_TEST(name, ...) extern struct ccanlint name
  250. #include "generated-testlist"
  251. static void init_tests(void)
  252. {
  253. struct ccanlint_map names;
  254. /* This is the default target. */
  255. dgraph_init_node(&all);
  256. strmap_init(&tests);
  257. #undef REGISTER_TEST
  258. #define REGISTER_TEST(name) register_test(&name)
  259. #include "generated-testlist"
  260. strmap_iterate(&tests, reset_deps, NULL);
  261. /* Check for duplicate names. */
  262. strmap_init(&names);
  263. strmap_iterate(&tests, check_names, &names);
  264. strmap_clear(&names);
  265. }
  266. static bool print_deps(const char *member, struct ccanlint *c, void *unused)
  267. {
  268. if (!tlist_empty(&c->node.edge[DGRAPH_FROM])) {
  269. struct dgraph_edge *e;
  270. printf("These depend on %s:\n", c->key);
  271. dgraph_for_each_edge(&c->node, e, DGRAPH_FROM) {
  272. struct ccanlint *to = container_of(e->n[DGRAPH_TO],
  273. struct ccanlint,
  274. node);
  275. printf("\t%s\n", to->key);
  276. }
  277. }
  278. return true;
  279. }
  280. static void print_test_depends(void)
  281. {
  282. printf("Tests:\n");
  283. strmap_iterate(&tests, print_deps, NULL);
  284. }
  285. static int show_tmpdir(const char *dir)
  286. {
  287. printf("You can find ccanlint working files in '%s'\n", dir);
  288. return 0;
  289. }
  290. static bool keep_one_test(const char *member, struct ccanlint *c, void *unused)
  291. {
  292. c->keep_results = true;
  293. return true;
  294. }
  295. static char *keep_test(const char *testname, void *unused)
  296. {
  297. if (streq(testname, "all")) {
  298. strmap_iterate(&tests, keep_one_test, NULL);
  299. } else {
  300. struct ccanlint *i = find_test(testname);
  301. if (!i)
  302. errx(1, "No test %s to --keep", testname);
  303. keep_one_test(testname, i, NULL);
  304. }
  305. /* Don't automatically destroy temporary dir. */
  306. talloc_set_destructor(temp_dir(NULL), show_tmpdir);
  307. return NULL;
  308. }
  309. static char *skip_test(const char *testname, void *unused)
  310. {
  311. btree_insert(cmdline_exclude, testname);
  312. return NULL;
  313. }
  314. static char *list_tests(void *arg)
  315. {
  316. struct ccanlint *i;
  317. printf("Tests:\n");
  318. /* This makes them print in topological order. */
  319. while ((i = get_next_test()) != NULL) {
  320. printf(" %-25s %s\n", i->key, i->name);
  321. dgraph_clear_node(&i->node);
  322. strmap_del(&tests, i->key, NULL);
  323. }
  324. exit(0);
  325. }
  326. static bool draw_test(const char *member, struct ccanlint *c, const char *style)
  327. {
  328. /*
  329. * todo: escape labels in case ccanlint test keys have
  330. * characters interpreted as GraphViz syntax.
  331. */
  332. printf("\t\"%p\" [label=\"%s\"%s]\n", c, c->key, style);
  333. return true;
  334. }
  335. static void test_dgraph_vertices(const char *style)
  336. {
  337. strmap_iterate(&tests, draw_test, style);
  338. }
  339. static bool draw_edges(const char *member, struct ccanlint *c, void *unused)
  340. {
  341. struct dgraph_edge *e;
  342. dgraph_for_each_edge(&c->node, e, DGRAPH_FROM) {
  343. struct ccanlint *to = container_of(e->n[DGRAPH_TO],
  344. struct ccanlint,
  345. node);
  346. printf("\t\"%p\" -> \"%p\"\n", c->name, to->name);
  347. }
  348. return true;
  349. }
  350. static void test_dgraph_edges(void)
  351. {
  352. strmap_iterate(&tests, draw_edges, NULL);
  353. }
  354. static char *test_dependency_graph(void *arg)
  355. {
  356. puts("digraph G {");
  357. test_dgraph_vertices("");
  358. test_dgraph_edges();
  359. puts("}");
  360. exit(0);
  361. }
  362. /* Remove empty lines. */
  363. static char **collapse(char **lines, unsigned int *nump)
  364. {
  365. unsigned int i, j;
  366. for (i = j = 0; lines[i]; i++) {
  367. if (lines[i][0])
  368. lines[j++] = lines[i];
  369. }
  370. lines[j] = NULL;
  371. if (nump)
  372. *nump = j;
  373. return lines;
  374. }
  375. static void add_options(struct ccanlint *test, char **options,
  376. unsigned int num_options)
  377. {
  378. unsigned int num;
  379. if (!test->options)
  380. num = 0;
  381. else
  382. /* -1, because last one is NULL. */
  383. num = talloc_array_length(test->options) - 1;
  384. test->options = talloc_realloc(NULL, test->options,
  385. char *,
  386. num + num_options + 1);
  387. memcpy(&test->options[num], options, (num_options + 1)*sizeof(char *));
  388. }
  389. void add_info_options(struct ccan_file *info)
  390. {
  391. struct doc_section *d;
  392. unsigned int i;
  393. struct ccanlint *test;
  394. list_for_each(get_ccan_file_docs(info), d, list) {
  395. if (!streq(d->type, "ccanlint"))
  396. continue;
  397. for (i = 0; i < d->num_lines; i++) {
  398. unsigned int num_words;
  399. char **words = collapse(strsplit(d, d->lines[i], " \t"),
  400. &num_words);
  401. if (num_words == 0)
  402. continue;
  403. if (strncmp(words[0], "//", 2) == 0)
  404. continue;
  405. test = find_test(words[0]);
  406. if (!test) {
  407. warnx("%s: unknown ccanlint test '%s'",
  408. info->fullname, words[0]);
  409. continue;
  410. }
  411. if (!words[1]) {
  412. warnx("%s: no argument to test '%s'",
  413. info->fullname, words[0]);
  414. continue;
  415. }
  416. /* Known failure? */
  417. if (strcasecmp(words[1], "FAIL") == 0) {
  418. if (!targeting)
  419. btree_insert(info_exclude, words[0]);
  420. } else {
  421. if (!test->takes_options)
  422. warnx("%s: %s doesn't take options",
  423. info->fullname, words[0]);
  424. add_options(test, words+1, num_words-1);
  425. }
  426. }
  427. }
  428. }
  429. /* If options are of form "filename:<option>" they only apply to that file */
  430. char **per_file_options(const struct ccanlint *test, struct ccan_file *f)
  431. {
  432. char **ret;
  433. unsigned int i, j = 0;
  434. /* Fast path. */
  435. if (!test->options[0])
  436. return test->options;
  437. ret = talloc_array(f, char *, talloc_array_length(test->options));
  438. for (i = 0; test->options[i]; i++) {
  439. char *optname;
  440. if (!test->options[i] || !strchr(test->options[i], ':')) {
  441. optname = test->options[i];
  442. } else if (strstarts(test->options[i], f->name)
  443. && test->options[i][strlen(f->name)] == ':') {
  444. optname = test->options[i] + strlen(f->name) + 1;
  445. } else
  446. continue;
  447. /* FAIL overrides anything else. */
  448. if (streq(optname, "FAIL")) {
  449. ret = talloc_array(f, char *, 2);
  450. ret[0] = (char *)"FAIL";
  451. ret[1] = NULL;
  452. return ret;
  453. }
  454. ret[j++] = optname;
  455. }
  456. ret[j] = NULL;
  457. /* Shrink it to size so talloc_array_length() works as expected. */
  458. return talloc_realloc(NULL, ret, char *, j + 1);
  459. }
  460. static char *demangle_string(char *string)
  461. {
  462. unsigned int i;
  463. const char mapfrom[] = "abfnrtv";
  464. const char mapto[] = "\a\b\f\n\r\t\v";
  465. if (!strchr(string, '"'))
  466. return NULL;
  467. string = strchr(string, '"') + 1;
  468. if (!strrchr(string, '"'))
  469. return NULL;
  470. *strrchr(string, '"') = '\0';
  471. for (i = 0; i < strlen(string); i++) {
  472. if (string[i] == '\\') {
  473. char repl;
  474. unsigned len = 0;
  475. const char *p = strchr(mapfrom, string[i+1]);
  476. if (p) {
  477. repl = mapto[p - mapfrom];
  478. len = 1;
  479. } else if (strlen(string+i+1) >= 3) {
  480. if (string[i+1] == 'x') {
  481. repl = (string[i+2]-'0')*16
  482. + string[i+3]-'0';
  483. len = 3;
  484. } else if (cisdigit(string[i+1])) {
  485. repl = (string[i+2]-'0')*8*8
  486. + (string[i+3]-'0')*8
  487. + (string[i+4]-'0');
  488. len = 3;
  489. }
  490. }
  491. if (len == 0) {
  492. repl = string[i+1];
  493. len = 1;
  494. }
  495. string[i] = repl;
  496. memmove(string + i + 1, string + i + len + 1,
  497. strlen(string + i + len + 1) + 1);
  498. }
  499. }
  500. return string;
  501. }
  502. static void read_config_header(void)
  503. {
  504. char *fname = talloc_asprintf(NULL, "%s/config.h", ccan_dir);
  505. char **lines;
  506. unsigned int i;
  507. config_header = grab_file(NULL, fname, NULL);
  508. if (!config_header) {
  509. talloc_free(fname);
  510. return;
  511. }
  512. lines = strsplit(config_header, config_header, "\n");
  513. for (i = 0; i < talloc_array_length(lines) - 1; i++) {
  514. char *sym;
  515. const char **line = (const char **)&lines[i];
  516. if (!get_token(line, "#"))
  517. continue;
  518. if (!get_token(line, "define"))
  519. continue;
  520. sym = get_symbol_token(lines, line);
  521. if (streq(sym, "CCAN_COMPILER") && !compiler) {
  522. compiler = demangle_string(lines[i]);
  523. if (!compiler)
  524. errx(1, "%s:%u:could not parse CCAN_COMPILER",
  525. fname, i+1);
  526. if (verbose > 1)
  527. printf("%s: compiler set to '%s'\n",
  528. fname, compiler);
  529. } else if (streq(sym, "CCAN_CFLAGS") && !cflags) {
  530. cflags = demangle_string(lines[i]);
  531. if (!cflags)
  532. errx(1, "%s:%u:could not parse CCAN_CFLAGS",
  533. fname, i+1);
  534. if (verbose > 1)
  535. printf("%s: compiler flags set to '%s'\n",
  536. fname, cflags);
  537. }
  538. }
  539. if (!compiler)
  540. compiler = CCAN_COMPILER;
  541. if (!cflags)
  542. compiler = CCAN_CFLAGS;
  543. }
  544. static char *opt_set_const_charp(const char *arg, const char **p)
  545. {
  546. return opt_set_charp(arg, cast_const2(char **, p));
  547. }
  548. static char *opt_set_target(const char *arg, struct ccanlint **t)
  549. {
  550. *t = find_test(arg);
  551. if (!*t)
  552. return talloc_asprintf(NULL, "unknown --target %s", arg);
  553. return NULL;
  554. }
  555. static bool run_tests(struct ccanlint *target,
  556. bool summary,
  557. struct manifest *m,
  558. const char *prefix)
  559. {
  560. struct run_info run;
  561. run.quiet = summary;
  562. run.m = m;
  563. run.prefix = prefix;
  564. run.score = run.total = 0;
  565. run.pass = true;
  566. if (target) {
  567. dgraph_traverse_to(&target->node, run_test, &run);
  568. if (run.pass)
  569. run_test(&target->node, &run);
  570. } else
  571. dgraph_traverse_to(&all, run_test, &run);
  572. printf("%sTotal score: %u/%u\n",
  573. prefix, run.score, run.total);
  574. return run.pass;
  575. }
  576. int main(int argc, char *argv[])
  577. {
  578. bool summary = false, pass = true;
  579. unsigned int i;
  580. struct manifest *m;
  581. struct ccanlint *target = NULL;
  582. const char *prefix = "";
  583. char *dir = talloc_getcwd(NULL), *base_dir = dir, *testlink;
  584. cmdline_exclude = btree_new(btree_strcmp);
  585. info_exclude = btree_new(btree_strcmp);
  586. opt_register_early_noarg("--verbose|-v", opt_inc_intval, &verbose,
  587. "verbose mode (up to -vvvv)");
  588. opt_register_noarg("-n|--safe-mode", opt_set_bool, &safe_mode,
  589. "do not compile anything");
  590. opt_register_noarg("-l|--list-tests", list_tests, NULL,
  591. "list tests ccanlint performs (and exit)");
  592. opt_register_noarg("--test-dep-graph", test_dependency_graph, NULL,
  593. "print dependency graph of tests in Graphviz .dot format");
  594. opt_register_arg("-k|--keep <testname>", keep_test, NULL, NULL,
  595. "keep results of <testname>"
  596. " (can be used multiple times, or 'all')");
  597. opt_register_noarg("--summary|-s", opt_set_bool, &summary,
  598. "simply give one line summary");
  599. opt_register_arg("-x|--exclude <testname>", skip_test, NULL, NULL,
  600. "exclude <testname> (can be used multiple times)");
  601. opt_register_arg("-t|--timeout <milleseconds>", opt_set_uintval,
  602. NULL, &timeout,
  603. "ignore (terminate) tests that are slower than this");
  604. opt_register_arg("--target <testname>", opt_set_target,
  605. NULL, &target,
  606. "only run one test (and its prerequisites)");
  607. opt_register_arg("--compiler <compiler>", opt_set_const_charp,
  608. NULL, &compiler, "set the compiler");
  609. opt_register_arg("--cflags <flags>", opt_set_const_charp,
  610. NULL, &cflags, "set the compiler flags");
  611. opt_register_noarg("-?|-h|--help", opt_usage_and_exit,
  612. "\nA program for checking and guiding development"
  613. " of CCAN modules.",
  614. "This usage message");
  615. /* Do verbose before anything else... */
  616. opt_early_parse(argc, argv, opt_log_stderr_exit);
  617. /* We move into temporary directory, so gcov dumps its files there. */
  618. if (chdir(temp_dir(talloc_autofree_context())) != 0)
  619. err(1, "Error changing to %s temporary dir", temp_dir(NULL));
  620. init_tests();
  621. if (verbose >= 3) {
  622. compile_verbose = true;
  623. print_test_depends();
  624. }
  625. if (verbose >= 4)
  626. tools_verbose = true;
  627. opt_parse(&argc, argv, opt_log_stderr_exit);
  628. /* This links back to the module's test dir. */
  629. testlink = talloc_asprintf(NULL, "%s/test", temp_dir(NULL));
  630. /* Defaults to pwd. */
  631. if (argc == 1) {
  632. i = 1;
  633. goto got_dir;
  634. }
  635. for (i = 1; i < argc; i++) {
  636. unsigned int score, total_score;
  637. dir = argv[i];
  638. if (dir[0] != '/')
  639. dir = talloc_asprintf_append(NULL, "%s/%s",
  640. base_dir, dir);
  641. while (strends(dir, "/"))
  642. dir[strlen(dir)-1] = '\0';
  643. got_dir:
  644. if (dir != base_dir)
  645. prefix = talloc_append_string(talloc_basename(NULL,dir),
  646. ": ");
  647. init_tests();
  648. m = get_manifest(talloc_autofree_context(), dir);
  649. /* FIXME: This has to come after we've got manifest. */
  650. if (i == 1)
  651. read_config_header();
  652. /* Create a symlink from temp dir back to src dir's
  653. * test directory. */
  654. unlink(testlink);
  655. if (symlink(talloc_asprintf(m, "%s/test", dir), testlink) != 0)
  656. err(1, "Creating test symlink in %s", temp_dir(NULL));
  657. score = total_score = 0;
  658. if (!run_tests(target, summary, m, prefix))
  659. pass = false;
  660. }
  661. return pass ? 0 : 1;
  662. }