| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- .\" This manpage has been automatically generated by docbook2man
- .\" from a DocBook document. This tool can be found at:
- .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
- .\" Please send any bug reports, improvements, comments, patches,
- .\" etc. to Steve Cheng <steve@ggi-project.org>.
- .TH "CHECKMK" "1" "09 February 2010" "" ""
- .SH NAME
- checkmk \- Awk script for generating C unit tests for use with the Check unit testing framework.
- .SH SYNOPSIS
- \fBcheckmk\fR [ \fBclean_mode=1\fR ] [ \fB\fIinput-file\fB\fR ]
- .SH "DESCRIPTION"
- .PP
- 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.
- .PP
- 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.
- .PP
- The Check framework, along with information regarding it, is
- available at https://libcheck.github.io/check/ <URL:https://libcheck.github.io/check/>\&.
- .PP
- The \fIinput-file\fR argument to
- \fBcheckmk\fR uses a simple, C-preprocessor-like
- syntax to declare test functions, and to describe their
- relationships to Suites and TCases in Check.
- \fBcheckmk\fR then uses this information to
- automatically write a \fBmain()\fR 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 \fBcheckmk\fR\&'s standard output.
- .PP
- Facilities are provided for the insertion of user code into
- the generated \fBmain()\fR function, to provide for
- the use of logging, test fixtures or specialized exit values.
- .PP
- While it is possible to omit the
- \fIinput-file\fR argument to
- \fBcheckmk\fR and provide the input file on
- \fBcheckmk\fR\&'s standard input instead, it is generally
- recommended to provide it as an argument. Doing this allows
- \fBcheckmk\fR 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.
- .SH "OPTIONS"
- .PP
- The only officially supported option is specifying a true
- value (using Awk's definition for "true") for the variable
- \fBclean_mode\fR\&. This causes \fBcheckmk\fR
- not to place appropriate #line directives in the
- source code, which some might find to be unnecessary clutter.
- .PP
- 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 \fBcheckmk\fR\&. 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.
- .PP
- #line directives are automatically
- suppressed when the input file is provided on standard input
- instead of as a command-line argument.
- .SH "BASIC EXAMPLE"
- .PP
- 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:
- .nf
- #test \fItest_name\fR
- .fi
- .PP
- Where \fItest_name\fR is the name of
- your test function. This will be used to name a C function, so
- it must be a valid C identifier.
- .PP
- Here is a small, complete example:
- .nf
- --------------------------------------------------
- /* 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. */
- --------------------------------------------------
- .fi
- .PP
- If you place the above into a file named
- \fIbasic_complete.ts\fR and process it using the
- following command:
- .PP
- \fB$ checkmk basic_complete.ts > basic_complete.c\fR
- .PP
- \fIbasic_complete.c\fR
- will contain output similar to:
- .nf
- --------------------------------------------------
- /*
- * 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;
- }
- --------------------------------------------------
- .fi
- .PP
- In real usage, \fIbasic_complete.c\fR would
- also contain #line directives.
- .SH "DIRECTIVE SUMMARY"
- .PP
- Here is a complete summary of all the C-preprocessor-style
- directives that are understood by \fBcheckmk\fR\&. See
- below for more details.
- .nf
- # test \fItest_name\fR
- # test-signal(\fIsignal\fR) \fItest_name\fR
- # test-exit(\fIexit_code\fR) \fItest_name\fR
- # test-loop(\fIstart\fR, \fIend\fR) \fItest_name\fR
- # test-loop-signal(\fIsignal\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR
- # test-loop-exit(\fIexit_code\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR
- # suite \fITestSuiteName\fR
- # tcase \fITestCaseName\fR
- # main-pre
- # main-post
- .fi
- .PP
- 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.
- .SH "TEST-DEFINING DIRECTIVES"
- .PP
- Here is a more detailed explanation of the directives that may be
- used to define test functions and their containers.
- .SS "TEST FUNCTIONS"
- .nf
- # test \fItest_name\fR
- # test-signal(\fIsignal\fR) \fItest_name\fR
- # test-exit(\fIexit_code\fR) \fItest_name\fR
- # test-loop(\fIstart\fR, \fIend\fR) \fItest_name\fR
- # test-loop-signal(\fIsignal\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR
- # test-loop-exit(\fIexit_code\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR
- .fi
- .PP
- These are the most basic directives for creating a template
- for input to \fBcheckmk\fR\&. They are the only
- directives that are required: there must be at least one
- #test* directive appearing in the template, or
- \fBcheckmk\fR will fail with an error message. The
- #test* directives may be specified several times,
- each one beginning the definition of a new test function.
- .PP
- The \fItest_name\fR 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.
- .PP
- Universal Character Names (introduced in C99) are also
- allowed, of the form \\uXXXX or
- \\UXXXXXXXX, where the X\&'s
- represent hexadecimal digits.
- .PP
- It is an error to specify the same
- \fItest_name\fR in more than one
- #test* directive, regardless of whether they
- are associated with different test cases or suites.
- .PP
- See CHECKMK
- IDENTIFIERS for the list of identifiers which should be
- avoided for use as test function names.
- .SS "TEST SUITES"
- .nf
- # suite \fITestSuiteName\fR
- .fi
- .PP
- This directive specifies the name of the test suite
- (\fBSuite\fR object in the Check test
- framework) to which all future test cases (and their test
- functions) will be added.
- .PP
- The \fITestSuiteName\fR 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.
- .PP
- 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.
- .PP
- Note that a \fBSuite\fR object won't
- actually be defined by \fBcheckmk\fR 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 \fBcheckmk\fR (and would
- therefore be useless).
- .PP
- 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.
- .PP
- If you do not specify a #suite directive
- before the first #test directive,
- \fBcheckmk\fR performs the equivalent of an
- implicit #suite directive, with the string
- "Core" as the value for
- \fITestSuiteName\fR (this also implies a
- "Core" test case object). This is demonstrated
- above in BASIC EXAMPLE\&.
- .SS "TEST CASES"
- .nf
- # tcase \fITestCaseName\fR
- .fi
- .PP
- This directive specifies the name of the test case
- (\fBTCase\fR object in the Check test
- framework) to which all future test functions will be added.
- .PP
- The #tcase works very in a way very
- similar to #suite\&. The
- \fITestCaseName\fR is a text string, and
- may contain arbitrary characters; and a
- \fBTCase\fR object won't actually be defined
- unless it is followed by an associated
- #test directive.
- .PP
- 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.
- .PP
- See also the #suite directive, described
- above.
- .SH "USER CODE IN MAIN()"
- .PP
- The C \fBmain()\fR is automatically generated
- by \fBcheckmk\fR, defining the necessary
- \fBSRunner\fR\&'s, \fBSuite\fR\&'s,
- and\~\fBTCase\fR\&'s required by the
- test-defining directives specified by the user.
- .PP
- For most situations, this completely automated
- \fBmain()\fR is quite suitable as-is. However,
- there are situations where one might wish to add custom code to
- the \fBmain()\fR\&. For instance, if the user wishes
- to:
- .TP 0.2i
- \(bu
- change the test timeout value via
- \fBtcase_set_timeout()\fR,
- .TP 0.2i
- \(bu
- specify Check's "no-fork-mode" via
- \fBsrunner_set_fork_status()\fR,
- .TP 0.2i
- \(bu
- set up test fixtures for some test cases, via
- \fBtcase_add_checked_fixture()\fR
- or\~\fBtcase_add_unchecked_fixture()\fR,
- .TP 0.2i
- \(bu
- set up test logging for the suite
- runner, via \fBsrunner_set_log()\fR
- or\~\fBsrunner_set_xml()\fR, or
- .TP 0.2i
- \(bu
- perform custom wrap-up after the test suites have
- been run.
- .PP
- For these purposes, the #main-pre
- and\~#main-post directives have been
- provided.
- .SS "MAIN() PROLOGUE"
- .nf
- # main-pre
- .fi
- .PP
- The text following this directive will be placed verbatim
- into the body of the generated \fBmain()\fR
- function, just after \fBcheckmk\fR\&'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
- \fBcheckmk\fR has only just finished making its
- declarations, it is permissible, even under strict 1990 ISO C
- guidelines, to make custom variable declarations here.
- .PP
- 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.
- .PP
- #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 \fBcheckmk\fR has used
- to instantiate the \fBSRunner\fR\&'s,
- \fBSuite\fR\&'s,
- and\~\fBTCase\fR\&'s.
- .SS "CHECKMK IDENTIFIERS"
- .PP
- Pointers to \fBSuite\fR\&'s are declared
- using the pattern
- s\fIX\fR, where
- \fIX\fR 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".
- .PP
- Pointers to \fBTCase\fR\&'s are declared
- using the pattern
- tc\fIX\fR_\fIY\fR,
- where \fIX\fR corresponds to the number
- used for the name of the \fBSuite\fR that
- will contain this \fBTCase\fR; and
- \fIY\fR is a number that starts at 1 for
- each new \fBSuite\fR, and is incremented for
- each \fBTCase\fR in that
- \fBSuite\fR\&.
- .PP
- A pointer to \fBSRunner\fR 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).
- .PP
- For obvious reasons, the user should not attempt to
- declare local identifiers in \fBmain()\fR, or
- define any macros or test functions, whose names might
- conflict with the local variable names used by
- \fBcheckmk\fR\&. To summarize, these names are:
- s\fIX\fR
- tc\fIX\fR_\fIY\fR
- sr
- nf\&.
- .SS "MAIN() EPILOGUE"
- .nf
- # main-post
- .fi
- .PP
- Though it is not as useful, \fBcheckmk\fR also
- provides a #main-post directive to insert
- custom code at the end of \fBmain()\fR, 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.
- .PP
- Note that, if you make use of this directive,
- \fBcheckmk\fR will \fBnot\fR provide a
- return statement: you will need
- to provide one yourself.
- .PP
- The #main-post directive may not be
- followed by any other directives recognized by
- \fBcheckmk\fR\&.
- .SH "COMPREHENSIVE EXAMPLE"
- .PP
- 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.
- .nf
- --------------------------------------------------
- #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. */
- --------------------------------------------------
- .fi
- .PP
- Plugging this into \fBcheckmk\fR, we'll get
- output roughly like the following:
- .nf
- --------------------------------------------------
- /*
- * 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. */
- }
- --------------------------------------------------
- .fi
- .SH "AUTHOR"
- .PP
- \fBcheckmk\fR and this manual were written
- by Micah J Cowan.
- .PP
- Copyright (C) 2006, 2010 Micah J Cowan.
|