checkmk.sgml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
  2. <refentry>
  3. <refmeta>
  4. <refentrytitle>checkmk</refentrytitle>
  5. <manvolnum>1</manvolnum>
  6. </refmeta>
  7. <refnamediv>
  8. <refname>checkmk</refname>
  9. <refpurpose>Awk script for generating C unit tests for use with the
  10. Check unit testing framework.</refpurpose>
  11. </refnamediv>
  12. <refsynopsisdiv>
  13. <cmdsynopsis>
  14. <command>checkmk</command>
  15. <arg choice="opt"><option>clean_mode=1</option></arg>
  16. <arg choice="opt"><replaceable>input-file</replaceable></arg>
  17. </cmdsynopsis>
  18. </refsynopsisdiv>
  19. <refsect1>
  20. <title>Description</title>
  21. <para>Generate C-language source files containing unit tests for use
  22. with the Check unit testing framework. The aim of this script is
  23. to automate away some of the typical boilerplate one must write when
  24. writing a test suite using Check: specifically, the instantiation of
  25. an SRunner, Suite(s), and TCase(s), and the building of
  26. relationships between these objects and the test functions.</para>
  27. <para>This tool is intended to be used by those who are familiar
  28. with the Check unit testing framework. Familiarity with the
  29. framework will be assumed throughout this manual.</para>
  30. <para>The Check framework, along with information regarding it, is
  31. available at <ulink
  32. url="https://libcheck.github.io/check/">https://libcheck.github.io/check/</ulink>.</para>
  33. <para>The <replaceable>input-file</replaceable> argument to
  34. <command>checkmk</command> uses a simple, C-preprocessor-like
  35. syntax to declare test functions, and to describe their
  36. relationships to Suites and TCases in Check.
  37. <command>checkmk</command> then uses this information to
  38. automatically write a <function>main()</function> function
  39. containing all of the necessary declarations, and whatever code is
  40. needed to run the test suites. The final C-language output is
  41. printed to <command>checkmk</command>'s standard output.</para>
  42. <para>Facilities are provided for the insertion of user code into
  43. the generated <function>main()</function> function, to provide for
  44. the use of logging, test fixtures or specialized exit values.</para>
  45. <para>While it is possible to omit the
  46. <replaceable>input-file</replaceable> argument to
  47. <command>checkmk</command> and provide the input file on
  48. <command>checkmk</command>'s standard input instead, it is generally
  49. recommended to provide it as an argument. Doing this allows
  50. <command>checkmk</command> to be aware of the file's name, to place
  51. references to it in the initial comments of the C-language output,
  52. and to intersperse C <literal>#line</literal> directives throughout, to
  53. facilitate in debugging problems by directing the user to the
  54. original input file.</para>
  55. </refsect1>
  56. <refsect1>
  57. <title>Options</title>
  58. <para>The only officially supported option is specifying a true
  59. value (using Awk's definition for "true") for the variable
  60. <option>clean_mode</option>. This causes <command>checkmk</command>
  61. not to place appropriate <literal>#line</literal> directives in the
  62. source code, which some might find to be unnecessary clutter.</para>
  63. <para>The author recommends against the use of this option, as it
  64. will cause C compilers and debugging tools to refer to lines in the
  65. automatically generated output, rather than the original input files
  66. to <command>checkmk</command>. This would encourage users to edit the
  67. output files instead of the original input files, would make it
  68. difficult for intelligent editors or IDEs to pull up the right file
  69. to edit, and could result in the fixes being overwritten when the
  70. output files are regenerated.</para>
  71. <para><literal>#line</literal> directives are automatically
  72. supressed when the input file is provided on standard input
  73. instead of as a command-line argument.</para>
  74. </refsect1>
  75. <refsect1 id="checkmk.basic.exa">
  76. <title>Basic Example</title>
  77. <para>In its most basic form, an input file can be simply a
  78. prologue and a test function. Anything that appears before the
  79. first test function is in the prologue, and will be copied into
  80. the output verbatim. The test function is begun by a line in the
  81. form:</para>
  82. <programlisting>#test <replaceable>test_name</replaceable></programlisting>
  83. <para>Where <replaceable>test_name</replaceable> is the name of
  84. your test function. This will be used to name a C function, so
  85. it must be a valid C identifier.</para>
  86. <para>Here is a small, complete example:</para>
  87. <programlisting><![CDATA[--------------------------------------------------
  88. /* A complete test example */
  89. #include <stdio.h>
  90. #test the_test
  91. int nc;
  92. const char msg[] = "\n\n Hello, world!\n";
  93. nc = printf("%s", msg);
  94. fail_unless(nc == (sizeof msg
  95. - 1) /* for terminating NUL. */
  96. );
  97. --------------------------------------------------
  98. ]]></programlisting>
  99. <para>If you place the above into a file named
  100. <filename>basic_complete.ts</filename> and process it using the
  101. following command:</para>
  102. <para><userinput>$ checkmk basic_complete.ts &gt; basic_complete.c</userinput></para>
  103. <para><filename>basic_complete.c</filename>
  104. will contain output similar to:</para>
  105. <programlisting><![CDATA[--------------------------------------------------
  106. /*
  107. * DO NOT EDIT THIS FILE. Generated by checkmk.
  108. * Edit the original source file "in" instead.
  109. */
  110. #include <check.h>
  111. /* A complete test example */
  112. #include <stdio.h>
  113. START_TEST(the_test)
  114. {
  115. int nc;
  116. const char msg[] = "\n\n Hello, world!\n";
  117. nc = printf("%s", msg);
  118. fail_unless(nc == (sizeof msg
  119. - 1) /* for terminating NUL. */
  120. );
  121. }
  122. END_TEST
  123. int main(void)
  124. {
  125. Suite *s1 = suite_create("Core");
  126. TCase *tc1_1 = tcase_create("Core");
  127. SRunner *sr = srunner_create(s1);
  128. int nf;
  129. suite_add_tcase(s1, tc1_1);
  130. tcase_add_test(tc1_1, the_test);
  131. srunner_run_all(sr, CK_ENV);
  132. nf = srunner_ntests_failed(sr);
  133. srunner_free(sr);
  134. return nf == 0 ? 0 : 1;
  135. }
  136. --------------------------------------------------
  137. ]]></programlisting>
  138. <para>In real usage, <filename>basic_complete.c</filename> would
  139. also contain <literal>#line</literal> directives.
  140. </refsect1>
  141. <refsect1>
  142. <title>Directive Summary</title>
  143. <para>Here is a complete summary of all the C-preprocessor-style
  144. directives that are understood by <command>checkmk</command>. See
  145. below for more details.</para>
  146. <programlisting># test <replaceable>test_name</replaceable>
  147. # suite <replaceable>TestSuiteName</replaceable>
  148. # tcase <replaceable>TestCaseName</replaceable>
  149. # main-pre
  150. # main-post</programlisting>
  151. <para>All directives are case-insensitive. Whitespace may appear
  152. at the beginning of the line before the <literal>#</literal>,
  153. between the <literal>#</literal> and the directive, between the
  154. directive and any argument, and at the end of the line.</para>
  155. </refsect1>
  156. <refsect1>
  157. <title>Test-Defining Directives</title>
  158. <para>Here is a more detailed explanation of the directives that may be
  159. used to define test functions and their containers.</para>
  160. <refsect2>
  161. <title>Test Functions</title>
  162. <programlisting># test <replaceable>test_name</replaceable></programlisting>
  163. <para>This is the most basic directive for creating a template
  164. for input to <command>checkmk</command>. It is the only
  165. directive that is required: there must be at least one
  166. <literal>#test</literal> directive appearing in the template, or
  167. <command>checkmk</command> will fail with an error message. The
  168. <literal>#test</literal> directive may be specified several times,
  169. each one beginning the definition of a new test function.</para>
  170. <para>The <replaceable>test_name</replaceable> argument will be
  171. used as the name of a test function in the C-language output, so
  172. it must be a valid C identifier. That is, it must begin with an
  173. alphabetic character or the underscore (<literal>_</literal>),
  174. followed by optional alpha-numeric characters and/or
  175. underscores.</para>
  176. <para>Universal Character Names (introduced in C99) are also
  177. allowed, of the form <literal>\uXXXX</literal> or
  178. <literal>\UXXXXXXXX</literal>, where the <literal>X</literal>'s
  179. represent hexadecimal digits.</para>
  180. <para>It is an error to specify the same
  181. <replaceable>test_name</replaceable> in more than one
  182. <literal>#test</literal> directive, regardless of whether they
  183. are associated with different test cases or suites.</para>
  184. <para>See <link linkend="checkmk.identifiers">CHECKMK
  185. IDENTIFIERS</link> for the list of identifiers which should be
  186. avoided for use as test function names.</para>
  187. </refsect2>
  188. <refsect2>
  189. <title>Test Suites</title>
  190. <programlisting># suite <replaceable>TestSuiteName</replaceable></programlisting>
  191. <para>This directive specifies the name of the test suite
  192. (<classname>Suite</classname> object in the Check test
  193. framework) to which all future test cases (and their test
  194. functions) will be added.</para>
  195. <para>The <replaceable>TestSuiteName</replaceable> is a text
  196. string, and may contain any sort of characters at all (other
  197. than ASCII NUL character, and the newline, which would terminate
  198. the directive). Any leading or trailing whitespace will be omitted
  199. from the test suite name.</para>
  200. <para>Starting a new test suite also begins a new test case, whose
  201. name is identical to the new test suite. This test case name may be
  202. overridden by a subsequent <literal>#tcase</literal> directive.</para>
  203. <para>Note that a <classname>Suite</classname> object won't
  204. actually be defined by <command>checkmk</command> in the C
  205. output, unless it is followed at some point by a
  206. <literal>#test</literal> directive (without an intervening
  207. <literal>#suite</literal>). It is not an error for a
  208. <literal>#suite</literal> to have no associated
  209. <literal>#test</literal>'s; the <literal>#suite</literal> (and any
  210. associated <literal>#tcase</literal>'s) simply won't result in any
  211. action on the part of <command>checkmk</command> (and would
  212. therefore be useless).</para>
  213. <para>It is an error for a <literal>#suite</literal> directive to
  214. specify the same (case sensitive) suite multiple times, unless the
  215. previous uses were not instantiated by the presence of at least
  216. one associated <literal>#test</literal> directive.</para>
  217. <para>If you do not specify a <literal>#suite</literal> directive
  218. before the first <literal>#test</literal> directive,
  219. <command>checkmk</command> performs the equivalent of an
  220. implicit <literal>#suite</literal> directive, with the string
  221. <literal>"Core"</literal> as the value for
  222. <replaceable>TestSuiteName</replaceable> (this also implies a
  223. <literal>"Core"</literal> test case object). This is demonstrated
  224. above in <link linkend="checkmk.basic.exa">BASIC EXAMPLE</link>.</para>
  225. </refsect2>
  226. <refsect2>
  227. <title>Test Cases</title>
  228. <programlisting># tcase <replaceable>TestCaseName</replaceable></programlisting>
  229. <para>This directive specifies the name of the test case
  230. (<classname>TCase</classname> object in the Check test
  231. framework) to which all future test functions will be added.</para>
  232. <para>The <literal>#tcase</literal> works very in a way very
  233. similar to <literal>#suite</literal>. The
  234. <replaceable>TestCaseName</replaceable> is a text string, and
  235. may contain arbitrary characters; and a
  236. <classname>TCase</classname> object won't actually be defined
  237. unless it is followed by an associated
  238. <literal>#test</literal> directive.</para>
  239. <para>It is an error for a <literal>#tcase</literal> directive to
  240. specify the same (case sensitive) test case multiple times, unless the
  241. previous uses were not instantiated by the presence of at least
  242. one associated <literal>#test</literal> directive.</para>
  243. <para>See also the <literal>#suite</literal> directive, described
  244. above.</para>
  245. </refsect2>
  246. </refsect1>
  247. <refsect1>
  248. <title>User Code In <function>main()</function></title>
  249. <para>The C <function>main()</function> is automatically generated
  250. by <command>checkmk</command>, defining the necessary
  251. <classname>SRunner</classname>'s, <classname>Suite</classname>'s,
  252. and&nbsp;<classname>TCase</classname>'s required by the
  253. test-defining directives specified by the user.</para>
  254. <para>For most situations, this completely automated
  255. <function>main()</function> is quite suitable as-is. However,
  256. there are situations where one might wish to add custom code to
  257. the <function>main()</function>. For instance, if the user wishes
  258. to:</para>
  259. <itemizedlist>
  260. <listitem><para>change the test timeout value via
  261. <function>tcase_set_timeout()</function>,</para></listitem>
  262. <listitem><para>specify Check's "no-fork-mode" via
  263. <function>srunner_set_fork_status()</function>,</para></listitem>
  264. <listitem><para>set up test fixtures for some test cases, via
  265. <function>tcase_add_checked_fixture()</function>
  266. or&nbsp;<function>tcase_add_unchecked_fixture()</function>,</para></listitem>
  267. <listitem><para>set up test logging for the suite
  268. runner, via <function>srunner_set_log()</function>
  269. or&nbsp;<function>srunner_set_xml()</function>, or</para></listitem>
  270. <listitem><para>perform custom wrap-up after the test suites have
  271. been run.</para></listitem>
  272. </itemizedlist>
  273. <para>For these purposes, the <literal>#main-pre</literal>
  274. and&nbsp;<literal>#main-post</literal> directives have been
  275. provided.</para>
  276. <refsect2>
  277. <title>Main() Prologue</title>
  278. <programlisting># main-pre</programlisting>
  279. <para>The text following this directive will be placed verbatim
  280. into the body of the generated <function>main()</function>
  281. function, just after <command>checkmk</command>'s own local
  282. variable declarations, and before any test running has taken
  283. place (indeed, before even the relationships between the tests,
  284. test cases, and test suites have been set up, though that
  285. fact shouldn't make much difference). Since
  286. <command>checkmk</command> has only just finished making its
  287. declarations, it is permissible, even under strict 1990 ISO C
  288. guidelines, to make custom variable declarations here.</para>
  289. <para>Unlike the previously-described directives,
  290. <literal>#main-pre</literal> may be specified at most once. It may
  291. not be preceded by the <literal>#main-post</literal> directive,
  292. and no <literal>#suite</literal>, <literal>#tcase</literal>,
  293. or <literal>#test</literal> directive may appear after it.</para>
  294. <para><literal>#main-pre</literal> is a good place to tweak
  295. settings or set up test fixtures. Of course, in order to do so,
  296. you need to know what names <command>checkmk</command> has used
  297. to instantiate the <classname>SRunner</classname>'s,
  298. <classname>Suite</classname>'s,
  299. and&nbsp;<classname>TCase</classname>'s.</para>
  300. <refsect3 id="checkmk.identifiers">
  301. <title><command>checkmk</command> Identifiers</title>
  302. <para>Pointers to <classname>Suite</classname>'s are declared
  303. using the pattern
  304. <varname>s<replaceable>X</replaceable></varname>, where
  305. <replaceable>X</replaceable> is a number
  306. that starts at 1, and is incremented for each subsequent
  307. <literal>#suite</literal> directive.
  308. <varname>s1</varname> always exists, and contains the test
  309. function declared by the first <literal>#test</literal>
  310. directive. If that directive was not preceded by a
  311. <literal>#suite</literal>, it will be given the name "Core".</para>
  312. <para>Pointers to <classname>TCase</classname>'s are declared
  313. using the pattern
  314. <varname>tc<replaceable>X</replaceable>_<replaceable>Y</replaceable></varname>,
  315. where <replaceable>X</replaceable> corresponds to the number
  316. used for the name of the <classname>Suite</classname> that
  317. will contain this <classname>TCase</classname>; and
  318. <replaceable>Y</replaceable> is a number that starts at 1 for
  319. each new <classname>Suite</classname>, and is incremented for
  320. each <classname>TCase</classname> in that
  321. <classname>Suite</classname>.</para>
  322. <para>A pointer to <classname>SRunner</classname> is declared
  323. using the identifier <varname>sr</varname>; there is also an
  324. integer named <varname>nf</varname> which holds the number of
  325. test failures (after the tests have run).</para>
  326. <para>For obvious reasons, the user should not attempt to
  327. declare local identifiers in <function>main()</function>, or
  328. define any macros or test functions, whose names might
  329. conflict with the local variable names used by
  330. <command>checkmk</command>. To summarize, these names are:
  331. <simplelist type="vert">
  332. <member>s<replaceable>X</replaceable></member>
  333. <member>tc<replaceable>X</replaceable>_<replaceable>Y</replaceable></member>
  334. <member>sr</member>
  335. <member>nf</member>
  336. </simplelist>.</para>
  337. </refsect3>
  338. </refsect2>
  339. <refsect2>
  340. <title>Main() Epilogue</title>
  341. <programlisting># main-post</programlisting>
  342. <para>Though it is not as useful, <command>checkmk</command> also
  343. provides a <literal>#main-post</literal> directive to insert
  344. custom code at the end of <function>main()</function>, after the
  345. tests have run. This could be used to clean up resources that
  346. were allocated in the prologue, or to print information about
  347. the failed tests, or to provide a custom exit status
  348. code.</para>
  349. <para>Note that, if you make use of this directive,
  350. <command>checkmk</command> will <emphasis>not</emphasis> provide a
  351. <literal role="keyword">return</literal> statement: you will need
  352. to provide one yourself.</para>
  353. <para>The <literal>#main-post</literal> directive may not be
  354. followed by any other directives recognized by
  355. <command>checkmk</command>.</para>
  356. </refsect2>
  357. </refsect1>
  358. <refsect1>
  359. <title>Comprehensive Example</title>
  360. <para>Now that you've gotten the detailed descriptions of the
  361. various directives, let's see it all put to action with this
  362. fairly comprehensive template.</para>
  363. <programlisting><![CDATA[--------------------------------------------------
  364. #include "mempool.h" /* defines MEMPOOLSZ, prototypes for
  365. mempool_init() and mempool_free() */
  366. void *mempool;
  367. void mp_setup(void)
  368. {
  369. mempool = mempool_init(MEMPOOLSZ);
  370. fail_if(mempool == NULL, "Couldn't allocate mempool.");
  371. }
  372. void mp_teardown(void)
  373. {
  374. mempool_free(mempool);
  375. }
  376. /* end of prologue */
  377. #suite Mempool
  378. #tcase MP Init
  379. #test mempool_init_zero_test
  380. mempool = mempool_init(0);
  381. fail_unless(mempool == NULL, "Allocated a zero-sized mempool!");
  382. fail_unless(mempool_error(), "Didn't get an error for zero alloc.");
  383. /* "MP Util" TCase uses checked fixture. */
  384. #tcase MP Util
  385. #test mempool_copy_test
  386. void *cp = mempool_copy(mempool);
  387. fail_if(cp == NULL, "Couldn't perform mempool copy.");
  388. fail_if(cp == mempool, "Copy returned original pointer!");
  389. #test mempool_size_test
  390. fail_unless(mempool_getsize(mempool) != MEMPOOLSZ);
  391. #main-pre
  392. tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown);
  393. srunner_set_log(sr, "mplog.txt");
  394. #main-post
  395. if (nf != 0) {
  396. printf("Hey, something's wrong! %d whole tests failed!\n", nf);
  397. }
  398. return 0; /* Harness checks for output, always return success
  399. regardless. */
  400. --------------------------------------------------
  401. ]]></programlisting>
  402. <para>Plugging this into <command>checkmk</command>, we'll get
  403. output roughly like the following:</para>
  404. <programlisting><![CDATA[--------------------------------------------------
  405. /*
  406. * DO NOT EDIT THIS FILE. Generated by checkmk.
  407. * Edit the original source file "comprehensive.ts" instead.
  408. */
  409. #include <check.h>
  410. #include "mempool.h"
  411. void *mempool;
  412. void mp_setup(void)
  413. {
  414. ...
  415. }
  416. void mp_teardown(void)
  417. {
  418. ...
  419. }
  420. /* end of prologue */
  421. START_TEST(mempool_init_zero_test)
  422. {
  423. ...
  424. }
  425. END_TEST
  426. START_TEST(mempool_copy_test)
  427. {
  428. ...
  429. }
  430. END_TEST
  431. START_TEST(mempool_size_test)
  432. {
  433. ...
  434. }
  435. END_TEST
  436. int main(void)
  437. {
  438. Suite *s1 = suite_create("Mempool");
  439. TCase *tc1_1 = tcase_create("MP Init");
  440. TCase *tc1_2 = tcase_create("MP Util");
  441. SRunner *sr = srunner_create(s1);
  442. int nf;
  443. /* User-specified pre-run code */
  444. tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown);
  445. srunner_set_log(sr, "mplog.txt");
  446. suite_add_tcase(s1, tc1_1);
  447. tcase_add_test(tc1_1, mempool_init_zero_test);
  448. suite_add_tcase(s1, tc1_2);
  449. tcase_add_test(tc1_2, mempool_copy_test);
  450. tcase_add_test(tc1_2, mempool_size_test);
  451. srunner_run_all(sr, CK_ENV);
  452. nf = srunner_ntests_failed(sr);
  453. srunner_free(sr);
  454. /* User-specified post-run code */
  455. if (nf != 0) {
  456. printf("Hey, something's wrong! %d whole tests failed!\n", nf);
  457. }
  458. return 0; /* Harness checks for output, always return success
  459. regardless. */
  460. }
  461. --------------------------------------------------
  462. ]]></programlisting>
  463. </refsect1>
  464. <refsect1>
  465. <title>Author</title>
  466. <para><command>checkmk</command> and this manual were written
  467. by Micah J Cowan.</para>
  468. <para>Copyright (C) 2006, 2010 Micah J Cowan.</para>
  469. </refsect1>
  470. </refentry>