run-file_analysis.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include "tools/ccanlint/ccanlint.h"
  2. #include "ccan/tap/tap.h"
  3. #include "tools/ccanlint/file_analysis.c"
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <stdio.h>
  8. #include <assert.h>
  9. /* This is our test file. */
  10. struct test {
  11. enum line_info_type type;
  12. bool continued;
  13. const char *line;
  14. };
  15. static struct test testfile[] = {
  16. { PREPROC_LINE, false, "#ifndef TEST_H" },
  17. { PREPROC_LINE, false, "#define TEST_H" },
  18. { DOC_LINE, false, "/**" },
  19. { DOC_LINE, false, " * Comment here." },
  20. { DOC_LINE, false, " * Comment here too." },
  21. { DOC_LINE, false, " */" },
  22. { COMMENT_LINE, false, "// Normal one-line comment" },
  23. { COMMENT_LINE, false, " // Spaced one-line comment" },
  24. { COMMENT_LINE, false, "/* Normal one-line comment */" },
  25. { COMMENT_LINE, false, " /* Spaced one-line comment */" },
  26. { COMMENT_LINE, false, " /* Spaced two-line comment" },
  27. { COMMENT_LINE, false, " continued comment */" },
  28. { CODE_LINE, false, "extern int x;"},
  29. { CODE_LINE, false, "extern int y; // With new-style comment"},
  30. { CODE_LINE, false, "extern int z; /* With old-style comment */"},
  31. { CODE_LINE, false, "extern int v; /* With two-line comment"},
  32. { COMMENT_LINE, false, " Second line of comment"},
  33. { COMMENT_LINE, false, "/* comment1 */ // comment 2"},
  34. { COMMENT_LINE, false, "/* comment1 */ /* comment 2 */ "},
  35. { CODE_LINE, false, "/* comment1 */ code; /* comment 2 */ "},
  36. { CODE_LINE, false, "/* comment1 */ code; // comment 2"},
  37. { COMMENT_LINE, false, "/* comment start \\"},
  38. { COMMENT_LINE, true, " comment finish */"},
  39. { PREPROC_LINE, false, "#define foo \\"},
  40. { PREPROC_LINE, true, " (bar + \\"},
  41. { PREPROC_LINE, true, " baz)"},
  42. { CODE_LINE, false, "extern int \\"},
  43. { CODE_LINE, true, "#x;"},
  44. /* Variants of the same thing. */
  45. { PREPROC_LINE, false, "#ifdef BAR"},
  46. { CODE_LINE, false, "BAR"},
  47. { PREPROC_LINE, false, "#else"},
  48. { CODE_LINE, false, "!BAR"},
  49. { PREPROC_LINE, false, "#endif"},
  50. { PREPROC_LINE, false, "#if defined BAR"},
  51. { CODE_LINE, false, "BAR"},
  52. { PREPROC_LINE, false, "#else"},
  53. { CODE_LINE, false, "!BAR"},
  54. { PREPROC_LINE, false, "#endif"},
  55. { PREPROC_LINE, false, "#if defined(BAR)"},
  56. { CODE_LINE, false, "BAR"},
  57. { PREPROC_LINE, false, "#else"},
  58. { CODE_LINE, false, "!BAR"},
  59. { PREPROC_LINE, false, "#endif"},
  60. { PREPROC_LINE, false, "#if !defined(BAR)"},
  61. { CODE_LINE, false, "!BAR"},
  62. { PREPROC_LINE, false, "#else"},
  63. { CODE_LINE, false, "BAR"},
  64. { PREPROC_LINE, false, "#endif"},
  65. { PREPROC_LINE, false, "#if HAVE_FOO"},
  66. { CODE_LINE, false, "HAVE_FOO"},
  67. { PREPROC_LINE, false, "#elif HAVE_BAR"},
  68. { CODE_LINE, false, "HAVE_BAR"},
  69. { PREPROC_LINE, false, "#else"},
  70. { CODE_LINE, false, "neither"},
  71. { PREPROC_LINE, false, "#endif /* With a comment. */"},
  72. { PREPROC_LINE, false, "#endif /* TEST_H */" },
  73. };
  74. #define NUM_LINES (sizeof(testfile)/sizeof(testfile[0]))
  75. static const char *line_type_name(enum line_info_type type)
  76. {
  77. switch (type) {
  78. case PREPROC_LINE: return "PREPROC_LINE";
  79. case CODE_LINE: return "CODE_LINE";
  80. case DOC_LINE: return "DOC_LINE";
  81. case COMMENT_LINE: return "COMMENT_LINE";
  82. default: return "**INVALID**";
  83. }
  84. }
  85. /* This just tests parser for the moment. */
  86. int main(int argc, char *argv[])
  87. {
  88. unsigned int i;
  89. struct line_info *line_info;
  90. struct ccan_file *f = tal(NULL, struct ccan_file);
  91. plan_tests(NUM_LINES * 2 + 2 + 86);
  92. f->num_lines = NUM_LINES;
  93. f->line_info = NULL;
  94. f->lines = tal_array(f, char *, f->num_lines);
  95. for (i = 0; i < f->num_lines; i++)
  96. f->lines[i] = tal_strdup(f->lines, testfile[i].line);
  97. line_info = get_ccan_line_info(f);
  98. ok1(line_info == f->line_info);
  99. for (i = 0; i < f->num_lines; i++) {
  100. ok(f->line_info[i].type == testfile[i].type,
  101. "Line %u:'%s' type %s should be %s",
  102. i, testfile[i].line,
  103. line_type_name(f->line_info[i].type),
  104. line_type_name(testfile[i].type));
  105. ok(f->line_info[i].continued == testfile[i].continued,
  106. "Line %u:'%s' continued should be %s",
  107. i, testfile[i].line,
  108. testfile[i].continued ? "TRUE" : "FALSE");
  109. }
  110. /* Should cache. */
  111. ok1(get_ccan_line_info(f) == line_info);
  112. /* Expect line 1 condition to be NULL. */
  113. ok1(line_info[0].cond == NULL);
  114. /* Line 2, should depend on TEST_H being undefined. */
  115. ok1(line_info[1].cond != NULL);
  116. ok1(line_info[1].cond->type == PP_COND_IFDEF);
  117. ok1(line_info[1].cond->inverse);
  118. ok1(line_info[1].cond->parent == NULL);
  119. ok1(streq(line_info[1].cond->symbol, "TEST_H"));
  120. /* Every line BAR should depend on BAR being defined. */
  121. for (i = 0; i < f->num_lines; i++) {
  122. if (!streq(testfile[i].line, "BAR"))
  123. continue;
  124. ok1(line_info[i].cond->type == PP_COND_IFDEF);
  125. ok1(!line_info[i].cond->inverse);
  126. ok1(streq(line_info[i].cond->symbol, "BAR"));
  127. ok1(line_info[i].cond->parent == line_info[1].cond);
  128. }
  129. /* Every line !BAR should depend on BAR being undefined. */
  130. for (i = 0; i < f->num_lines; i++) {
  131. if (!streq(testfile[i].line, "!BAR"))
  132. continue;
  133. ok1(line_info[i].cond->type == PP_COND_IFDEF);
  134. ok1(line_info[i].cond->inverse);
  135. ok1(streq(line_info[i].cond->symbol, "BAR"));
  136. ok1(line_info[i].cond->parent == line_info[1].cond);
  137. }
  138. /* Every line HAVE_BAR should depend on HAVE_BAR being set. */
  139. for (i = 0; i < f->num_lines; i++) {
  140. if (!streq(testfile[i].line, "HAVE_BAR"))
  141. continue;
  142. ok1(line_info[i].cond->type == PP_COND_IF);
  143. ok1(!line_info[i].cond->inverse);
  144. ok1(streq(line_info[i].cond->symbol, "HAVE_BAR"));
  145. ok1(line_info[i].cond->parent == line_info[1].cond);
  146. }
  147. /* Every line HAVE_FOO should depend on HAVE_FOO being set. */
  148. for (i = 0; i < f->num_lines; i++) {
  149. if (!streq(testfile[i].line, "HAVE_FOO"))
  150. continue;
  151. ok1(line_info[i].cond->type == PP_COND_IF);
  152. ok1(!line_info[i].cond->inverse);
  153. ok1(streq(line_info[i].cond->symbol, "HAVE_FOO"));
  154. ok1(line_info[i].cond->parent == line_info[1].cond);
  155. }
  156. /* Now check using interface. */
  157. for (i = 0; i < f->num_lines; i++) {
  158. unsigned int val = 1;
  159. if (streq(testfile[i].line, "BAR")) {
  160. /* If we don't know if the TEST_H was undefined,
  161. * best we get is a MAYBE. */
  162. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
  163. NULL) == MAYBE_COMPILED);
  164. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
  165. NULL) == NOT_COMPILED);
  166. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
  167. "TEST_H", NULL,
  168. NULL) == COMPILED);
  169. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
  170. "TEST_H", NULL,
  171. NULL) == NOT_COMPILED);
  172. } else if (streq(testfile[i].line, "!BAR")) {
  173. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
  174. NULL) == NOT_COMPILED);
  175. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
  176. NULL) == MAYBE_COMPILED);
  177. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", &val,
  178. "TEST_H", NULL,
  179. NULL) == NOT_COMPILED);
  180. ok1(get_ccan_line_pp(line_info[i].cond, "BAR", NULL,
  181. "TEST_H", NULL,
  182. NULL) == COMPILED);
  183. } else if (streq(testfile[i].line, "HAVE_BAR")) {
  184. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
  185. &val, NULL) == MAYBE_COMPILED);
  186. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
  187. &val, "TEST_H", NULL,
  188. NULL) == COMPILED);
  189. val = 0;
  190. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
  191. &val, NULL) == NOT_COMPILED);
  192. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_BAR",
  193. &val, "TEST_H", NULL,
  194. NULL) == NOT_COMPILED);
  195. } else if (streq(testfile[i].line, "HAVE_FOO")) {
  196. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
  197. &val, NULL) == MAYBE_COMPILED);
  198. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
  199. &val, "TEST_H", NULL,
  200. NULL) == COMPILED);
  201. val = 0;
  202. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
  203. &val, NULL) == NOT_COMPILED);
  204. ok1(get_ccan_line_pp(line_info[i].cond, "HAVE_FOO",
  205. &val, "TEST_H", NULL,
  206. NULL) == NOT_COMPILED);
  207. }
  208. }
  209. return exit_status();
  210. }