Provided by: check_0.15.2-2+build1_amd64 bug

NAME

       checkmk  -  Awk  script for generating C unit tests for use with the    Check unit testing
       framework.

SYNOPSIS

       checkmk [ clean_mode=1 ] [ input-file ]

DESCRIPTION

       Generate C-language source files containing unit tests for use with the Check unit testing
       framework.  The aim of this script is to automate away some of the typical boilerplate one
       must write when writing a test suite using Check: specifically, the  instantiation  of  an
       SRunner,  Suite(s),  and TCase(s), and the building of relationships between these objects
       and the test functions.

       This tool is intended to be used by those who are familiar with  the  Check  unit  testing
       framework. Familiarity with the framework will be assumed throughout this manual.

       The   Check   framework,   along   with   information   regarding   it,  is  available  at
       https://libcheck.github.io/check/ <URL:https://libcheck.github.io/check/>.

       The input-file argument to checkmk uses a simple, C-preprocessor-like  syntax  to  declare
       test  functions,  and  to  describe  their  relationships  to  Suites and TCases in Check.
       checkmk then uses this information to automatically write a main() function containing all
       of  the  necessary  declarations,  and whatever code is needed to run the test suites. The
       final C-language output is printed to checkmk's standard output.

       Facilities are provided for the insertion of user code into the generated main() function,
       to provide for the use of logging, test fixtures or specialized exit values.

       While it is possible to omit the input-file argument to checkmk and provide the input file
       on checkmk's standard input instead, it is generally  recommended  to  provide  it  as  an
       argument. Doing this allows checkmk to be aware of the file's name, to place references to
       it in the initial comments of the C-language output, and to intersperse C #line directives
       throughout,  to  facilitate  in  debugging  problems by directing the user to the original
       input file.

OPTIONS

       The only officially supported option is specifying a true value  (using  Awk's  definition
       for  "true")  for  the  variable  clean_mode. This causes checkmk not to place appropriate
       #line directives in the source code, which some might find to be unnecessary clutter.

       The author recommends against the use of this option, as it will  cause  C  compilers  and
       debugging  tools  to refer to lines in the automatically generated output, rather than the
       original input files to checkmk. This would encourage  users  to  edit  the  output  files
       instead  of  the  original input files, would make it difficult for intelligent editors or
       IDEs to pull up the right file to edit, and could result in the  fixes  being  overwritten
       when the output files are regenerated.

       #line  directives are automatically suppressed when the input file is provided on standard
       input instead of as a command-line argument.

BASIC EXAMPLE

       In its most basic form, an input file can be  simply  a  prologue  and  a  test  function.
       Anything  that  appears  before  the  first  test function is in the prologue, and will be
       copied into the output verbatim. The test function is begun by a line in the form:

       #test test_name

       Where test_name is the name of your test function. This will be used to name a C function,
       so it must be a valid C identifier.

       Here is a small, complete example:

       --------------------------------------------------
       /* A complete test example */

       #include <stdio.h>

       #test the_test
           int nc;
           const char msg[] = "\n\n    Hello, world!\n";

           nc = printf("%s", msg);
           ck_assert(nc == (sizeof(msg) - 1)); /* for terminating NUL. */
       --------------------------------------------------

       If  you  place  the  above  into  a  file named basic_complete.ts and process it using the
       following command:

       $ checkmk basic_complete.ts > basic_complete.c

       basic_complete.c will contain output similar to:

       --------------------------------------------------
       /*
        * DO NOT EDIT THIS FILE. Generated by checkmk.
        * Edit the original source file "in" instead.
        */

       #include <check.h>

       /* A complete test example */

       #include <stdio.h>

       START_TEST(the_test)
       {
           int nc;
           const char msg[] = "\n\n    Hello, world!\n";

           nc = printf("%s", msg);
           ck_assert(nc == (sizeof(msg) - 1)); /* for terminating NUL. */
       }
       END_TEST

       int main(void)
       {
           Suite *s1 = suite_create("Core");
           TCase *tc1_1 = tcase_create("Core");
           SRunner *sr = srunner_create(s1);
           int nf;

           suite_add_tcase(s1, tc1_1);
           tcase_add_test(tc1_1, the_test);

           srunner_run_all(sr, CK_ENV);
           nf = srunner_ntests_failed(sr);
           srunner_free(sr);

           return nf == 0 ? 0 : 1;
       }
       --------------------------------------------------

       In real usage, basic_complete.c would also contain #line directives.

DIRECTIVE SUMMARY

       Here is a complete summary of all the C-preprocessor-style directives that are  understood
       by checkmk. See below for more details.

       # test test_name
       # test-signal(signal) test_name
       # test-exit(exit_code) test_name
       # test-loop(start, end) test_name
       # test-loop-signal(signal, start, end) test_name
       # test-loop-exit(exit_code, start, end) test_name
       # suite TestSuiteName
       # tcase TestCaseName
       # main-pre
       # main-post

       All  directives  are  case-insensitive. Whitespace may appear at the beginning of the line
       before the #, between the # and the directive, between the directive and any argument, and
       at the end of the line.

TEST-DEFINING DIRECTIVES

       Here  is  a  more  detailed  explanation of the directives that may be used to define test
       functions and their containers.

   TEST FUNCTIONS
       # test test_name
       # test-signal(signal) test_name
       # test-exit(exit_code) test_name
       # test-loop(start, end) test_name
       # test-loop-signal(signal, start, end) test_name
       # test-loop-exit(exit_code, start, end) test_name

       These are the most basic directives for creating a template for input to checkmk. They are
       the  only  directives  that  are  required:  there  must  be at least one #test* directive
       appearing in the template, or  checkmk  will  fail  with  an  error  message.  The  #test*
       directives may be specified several times, each one beginning the definition of a new test
       function.

       The test_name argument will be used as the name of  a  test  function  in  the  C-language
       output,  so  it  must  be  a valid C identifier. That is, it must begin with an alphabetic
       character or the underscore (_), followed  by  optional  alpha-numeric  characters  and/or
       underscores.

       Universal  Character  Names  (introduced  in  C99) are also allowed, of the form \uXXXX or
       \UXXXXXXXX, where the X's represent hexadecimal digits.

       It is an error to specify the same test_name in more than one #test* directive, regardless
       of whether they are associated with different test cases or suites.

       See  CHECKMK  IDENTIFIERS  for  the list of identifiers which should be avoided for use as
       test function names.

   TEST SUITES
       # suite TestSuiteName

       This directive specifies the name of the test  suite  (Suite  object  in  the  Check  test
       framework) to which all future test cases (and their test functions) will be added.

       The  TestSuiteName  is a text string, and may contain any sort of characters at all (other
       than ASCII NUL character, and the newline,  which  would  terminate  the  directive).  Any
       leading or trailing whitespace will be omitted from the test suite name.

       Starting  a new test suite also begins a new test case, whose name is identical to the new
       test suite. This test case name may be overridden by a subsequent #tcase directive.

       Note that a Suite object won't actually be defined by checkmk in the C output,  unless  it
       is  followed at some point by a #test directive (without an intervening #suite). It is not
       an error for a #suite to have no  associated  #test's;  the  #suite  (and  any  associated
       #tcase's) simply won't result in any action on the part of checkmk (and would therefore be
       useless).

       It is an error for a #suite directive to specify the same (case sensitive) suite  multiple
       times,  unless  the  previous  uses  were not instantiated by the presence of at least one
       associated #test directive.

       If you do not specify a  #suite  directive  before  the  first  #test  directive,  checkmk
       performs  the  equivalent  of  an implicit #suite directive, with the string "Core" as the
       value  for  TestSuiteName  (this  also  implies  a  "Core"  test  case  object).  This  is
       demonstrated above in BASIC EXAMPLE.

   TEST CASES
       # tcase TestCaseName

       This  directive  specifies  the  name  of  the  test  case (TCase object in the Check test
       framework) to which all future test functions will be added.

       The #tcase works very in a way very similar to #suite. The TestCaseName is a text  string,
       and  may contain arbitrary characters; and a TCase object won't actually be defined unless
       it is followed by an associated #test directive.

       It is an error for a #tcase directive to specify  the  same  (case  sensitive)  test  case
       multiple times, unless the previous uses were not instantiated by the presence of at least
       one associated #test directive.

       See also the #suite directive, described above.

USER CODE IN MAIN()

       The C main() is automatically generated by  checkmk,  defining  the  necessary  SRunner's,
       Suite's, and TCase's required by the test-defining directives specified by the user.

       For  most  situations,  this completely automated main() is quite suitable as-is. However,
       there are situations where one might wish to add custom code to the main(). For  instance,
       if the user wishes to:

       • change the test timeout value via tcase_set_timeout(),

       • specify Check's "no-fork-mode" via srunner_set_fork_status(),

       • set   up   test   fixtures   for   some   test  cases,  via  tcase_add_checked_fixture()
         or tcase_add_unchecked_fixture(),

       • set up test logging for the suite runner, via srunner_set_log() or srunner_set_xml(), or

       • perform custom wrap-up after the test suites have been run.

       For these purposes, the #main-pre and #main-post directives have been provided.

   MAIN() PROLOGUE
       # main-pre

       The text following this directive will be placed verbatim into the body of  the  generated
       main() function, just after checkmk's own local variable declarations, and before any test
       running has taken place (indeed, before even the relationships  between  the  tests,  test
       cases, and test suites have been set up, though that fact shouldn't make much difference).
       Since checkmk has only just finished making its  declarations,  it  is  permissible,  even
       under strict 1990 ISO C guidelines, to make custom variable declarations here.

       Unlike  the  previously-described  directives, #main-pre may be specified at most once. It
       may not be preceded by the #main-post directive, and no #suite, #tcase, or #test directive
       may appear after it.

       #main-pre  is  a good place to tweak settings or set up test fixtures. Of course, in order
       to do so, you need to know what names checkmk  has  used  to  instantiate  the  SRunner's,
       Suite's, and TCase's.

   CHECKMK IDENTIFIERS
       Pointers  to Suite's are declared using the pattern sX, where X is a number that starts at
       1, and is incremented for  each  subsequent  #suite  directive.   s1  always  exists,  and
       contains  the  test  function declared by the first #test directive. If that directive was
       not preceded by a #suite, it will be given the name "Core".

       Pointers to TCase's are declared using the pattern  tcX_Y,  where  X  corresponds  to  the
       number used for the name of the Suite that will contain this TCase; and Y is a number that
       starts at 1 for each new Suite, and is incremented for each TCase in that Suite.

       A pointer to SRunner is declared using the identifier sr; there is also an  integer  named
       nf which holds the number of test failures (after the tests have run).

       For  obvious  reasons, the user should not attempt to declare local identifiers in main(),
       or define any macros or test functions, whose names might conflict with the local variable
       names used by checkmk. To summarize, these names are:

       sX

       tcX_Y

       sr

       nf.

   MAIN() EPILOGUE
       # main-post

       Though  it is not as useful, checkmk also provides a #main-post directive to insert custom
       code at the end of main(), after the tests have run.  This  could  be  used  to  clean  up
       resources  that  were  allocated in the prologue, or to print information about the failed
       tests, or to provide a custom exit status code.

       Note that, if you make use of this directive, checkmk will not provide a return statement:
       you will need to provide one yourself.

       The  #main-post  directive  may  not  be  followed  by  any other directives recognized by
       checkmk.

COMPREHENSIVE EXAMPLE

       Now that you've gotten the detailed descriptions of the various directives, let's  see  it
       all put to action with this fairly comprehensive template.

       --------------------------------------------------
       #include "mempool.h"  /* defines MEMPOOLSZ, prototypes for
                                mempool_init() and mempool_free() */

       void *mempool;

       void mp_setup(void)
       {
           mempool = mempool_init(MEMPOOLSZ);
           ck_assert_msg(mempool != NULL, "Couldn't allocate mempool.");
       }

       void mp_teardown(void)
       {
           mempool_free(mempool);
       }

       /* end of prologue */

       #suite Mempool

       #tcase MP Init

       #test mempool_init_zero_test
           mempool = mempool_init(0);
           ck_assert_msg(mempool == NULL, "Allocated a zero-sized mempool!");
           ck_assert_msg(mempool_error(), "Didn't get an error for zero alloc.");

       /* "MP Util" TCase uses checked fixture. */
       #tcase MP Util

       #test mempool_copy_test
           void *cp = mempool_copy(mempool);
           ck_assert_msg(cp != NULL, "Couldn't perform mempool copy.");
           ck_assert_msg(cp != mempool, "Copy returned original pointer!");

       #test mempool_size_test
           ck_assert(mempool_getsize(mempool) == MEMPOOLSZ);

       #main-pre
           tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown);
           srunner_set_log(sr, "mplog.txt");

       #main-post
           if (nf != 0) {
             printf("Hey, something's wrong! %d whole tests failed!\n", nf);
           }
           return 0; /* Harness checks for output, always return success
                        regardless. */
       --------------------------------------------------

       Plugging this into checkmk, we'll get output roughly like the following:

       --------------------------------------------------
       /*
        * DO NOT EDIT THIS FILE. Generated by checkmk.
        * Edit the original source file "comprehensive.ts" instead.
        */

       #include <check.h>

       #include "mempool.h"

       void *mempool;

       void mp_setup(void)
       {
       ...
       }

       void mp_teardown(void)
       {
       ...
       }

       /* end of prologue */

       START_TEST(mempool_init_zero_test)
       {
       ...
       }
       END_TEST

       START_TEST(mempool_copy_test)
       {
       ...
       }
       END_TEST

       START_TEST(mempool_size_test)
       {
       ...
       }
       END_TEST

       int main(void)
       {
           Suite *s1 = suite_create("Mempool");
           TCase *tc1_1 = tcase_create("MP Init");
           TCase *tc1_2 = tcase_create("MP Util");
           SRunner *sr = srunner_create(s1);
           int nf;

           /* User-specified pre-run code */
           tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown);
           srunner_set_log(sr, "mplog.txt");

           suite_add_tcase(s1, tc1_1);
           tcase_add_test(tc1_1, mempool_init_zero_test);
           suite_add_tcase(s1, tc1_2);
           tcase_add_test(tc1_2, mempool_copy_test);
           tcase_add_test(tc1_2, mempool_size_test);

           srunner_run_all(sr, CK_ENV);
           nf = srunner_ntests_failed(sr);
           srunner_free(sr);

           /* User-specified post-run code */
           if (nf != 0) {
             printf("Hey, something's wrong! %d whole tests failed!\n", nf);
           }
           return 0; /* Harness checks for output, always return success
                        regardless. */
       }
       --------------------------------------------------

AUTHOR

       checkmk and this manual were written by Micah J Cowan.

       Copyright (C) 2006, 2010 Micah J Cowan.

                                         09 February 2010                              CHECKMK(1)