bionic (1) checkmk.1.gz

Provided by: check_0.10.0-3build2_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 http://check.sourceforge.net/
       <URL:http://check.sourceforge.net/>.

       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 supressed 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)