Skip to content

Commit 7b0086f

Browse files
Crispin Dent-Youngcdentyou
authored andcommitted
Support arbitrary tagging and selection of testcases.
A testcase can optionally have a list of tags associated with it. Srunner can be run with an optional include list of tags and an optional exclude list of tags. These will have the effect of filtering testcases that would otherwise be run.
1 parent 7ca2b6d commit 7b0086f

11 files changed

Lines changed: 1057 additions & 20 deletions

doc/check.texi

Lines changed: 101 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,8 @@ easier for the developer to write, run, and analyze tests.
974974
* Test Fixtures::
975975
* Multiple Suites in one SRunner::
976976
* Selective Running of Tests::
977+
* Selecting Tests by Suite or Test Case::
978+
* Selecting Tests Based on Arbitrary Tags::
977979
* Testing Signal Handling and Exit Values::
978980
* Looping Tests::
979981
* Test Timeouts::
@@ -1302,19 +1304,105 @@ srunner_add_suite (sr, make_pack_suite ());
13021304
@end example
13031305

13041306
@node Selective Running of Tests, Testing Signal Handling and Exit Values, Multiple Suites in one SRunner, Advanced Features
1307+
13051308
@section Selective Running of Tests
13061309

1310+
After adding a couple of suites and some test cases in each, it is
1311+
sometimes practical to be able to run only one suite, or one specific
1312+
test case, without recompiling the test code. Check provides two ways
1313+
to accomplish this, either by specifying a suite or test case by name
1314+
or by assigning tags to test cases and specifying one or more tags to
1315+
run.
1316+
1317+
@menu
1318+
* Selecting Tests by Suite or Test Case::
1319+
* Selecting Tests Based on Arbitrary Tags::
1320+
@end menu
1321+
1322+
@node Selecting Tests by Suite or Test Case, Selecting Tests Based on Arbitrary Tags, Selective Running of Tests, Selective Running of Tests
1323+
@subsection Selecting Tests by Suite or Test Case
1324+
13071325
@vindex CK_RUN_SUITE
13081326
@vindex CK_RUN_CASE
1309-
After adding a couple of suites and some test cases in each, it is
1310-
sometimes practical to be able to run only one suite, or one
1311-
specific test case, without recompiling the test code. There are
1312-
two environment variables available that offers this ability,
1313-
@code{CK_RUN_SUITE} and @code{CK_RUN_CASE}. Just set the value to
1314-
the name of the suite and/or test case you want to run. These
1315-
environment variables can also be a good integration tool for
1316-
running specific tests from within another tool, e.g. an IDE.
1317-
1327+
1328+
There are two environment variables available that offer this
1329+
ability, @code{CK_RUN_SUITE} and @code{CK_RUN_CASE}. Just set the
1330+
value to the name of the suite and/or test case you want to run. These
1331+
environment variables can also be a good integration tool for running
1332+
specific tests from within another tool, e.g. an IDE.
1333+
1334+
@node Selecting Tests Based on Arbitrary Tags, ,Selecting Tests by Suite or Test Case, Selective Running of Tests
1335+
@subsection Selecting Tests Based on Arbitrary Tags
1336+
1337+
@vindex CK_INCLUDE_TAGS
1338+
@vindex CK_EXCLUDE_TAGS
1339+
1340+
It can be useful to dynamically include or exclude groups of tests to
1341+
be run based on criteria other than the suite or test case name. For
1342+
example, one or more tags can be assigned to test cases. The tags
1343+
could indicate if a test runs for a long time, so such tests could be
1344+
excluded in order to run quicker tests for a sanity
1345+
check. Alternately, tags may be used to indicate which functional
1346+
areas test cover. Tests can then be run that include all test cases
1347+
for a given set of functional areas.
1348+
1349+
In Check, a tag is a string of characters without white space. One or
1350+
more tags can be assigned to a test case by using the
1351+
@code{tcase_set_tags} function. This function accepts a string, and
1352+
multiple tags can be specified by delimiting them with spaces. For
1353+
example:
1354+
1355+
@example
1356+
@verbatim
1357+
Suite *s;
1358+
1359+
TCase *red, *blue, *purple, *yellow, *black;
1360+
1361+
s = suite_create("Check Tag Filtering");
1362+
1363+
red = tcase_create("Red");
1364+
tcase_set_tags(red, "Red");
1365+
suite_add_tcase (s, red);
1366+
tcase_add_test(red, red_test1);
1367+
1368+
blue = tcase_create("Blue");
1369+
tcase_set_tags(blue, "Blue");
1370+
suite_add_tcase (s, blue);
1371+
tcase_add_test(blue, blue_test1);
1372+
1373+
purple = tcase_create("Purple");
1374+
tcase_set_tags(purple, "Red Blue");
1375+
suite_add_tcase (s, purple);
1376+
tcase_add_test(purple, purple_test1);
1377+
1378+
@end verbatim
1379+
@end example
1380+
1381+
Once test cases are tagged they may be selectively run in one of two ways:
1382+
1383+
a) Using Environment Variables
1384+
1385+
There are two environment variables available for selecting test cases
1386+
based on tags: @code{CK_INCLUDE_TAGS} and
1387+
@code{CK_EXCLUDE_TAGS}. These can be set to a space separated list of
1388+
tag names. If @code{CK_INCLUDE_TAGS} is set then test cases which
1389+
include at least one tag in common with @code{CK_INCLUDE_TAGS} will be
1390+
run. If @code{CK_EXCLUDE_TAGS} is set then test cases with one tag in
1391+
common with @code{CK_EXCLUDE_TAGS} will not be run. In cases where
1392+
both @code{CK_INCLUDE_TAGS} and @code{CK_EXCLUDE_TAGS} match a tag for
1393+
a test case the test will be excluded.
1394+
1395+
Both @code{CK_INCLUDE_TAGS} and @code{CK_EXCLUDE_TAGS} can be
1396+
specified in conjunction with @code{CK_RUN_SUITE} or even
1397+
@code{CK_RUN_CASE} in which case they will have the effect of further
1398+
narrowing the selection.
1399+
1400+
b) Programmatically
1401+
1402+
The @code{srunner_run_tagged} function allows one to specify which
1403+
tags to run or exclude from a suite runner. This can be used to
1404+
programmatically control which test cases may run.
1405+
13181406
@node Testing Signal Handling and Exit Values, Looping Tests, Selective Running of Tests, Advanced Features
13191407
@section Testing Signal Handling and Exit Values
13201408

@@ -1975,6 +2063,10 @@ CK_RUN_CASE: Name of a test case, runs only that test. See section @ref{Selectiv
19752063

19762064
CK_RUN_SUITE: Name of a test suite, runs only that suite. See section @ref{Selective Running of Tests}.
19772065

2066+
CK_INCLUDE_TAGS: String of space separated tags, runs only test cases associated with at least one of the tags, See section @ref{Selecting Tests Based on Arbitrary Tags}.
2067+
2068+
CK_EXCLUDE_TAGS: String of space separated tags, runs only test cases not associated with any of the tags, See section @ref{Selecting Tests Based on Arbitrary Tags}.
2069+
19782070
CK_VERBOSITY: How much output to emit, accepts: ``silent'', ``minimal'', ``normal'', ``subunit'', or ``verbose''. See section @ref{SRunner Output}.
19792071

19802072
CK_FORK: Set to ``no'' to disable using fork() to run unit tests in their own process. This is useful for debugging segmentation faults. See section @ref{No Fork Mode}.

src/check.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ static void suite_free(Suite * s)
103103
free(s);
104104
}
105105

106+
106107
TCase *tcase_create(const char *name)
107108
{
108109
char *env;
@@ -149,10 +150,49 @@ TCase *tcase_create(const char *name)
149150
tc->ch_sflst = check_list_create();
150151
tc->unch_tflst = check_list_create();
151152
tc->ch_tflst = check_list_create();
153+
tc->tags = check_list_create();
152154

153155
return tc;
154156
}
155157

158+
/*
159+
* Helper function to create a list of tags from
160+
* a space separated string.
161+
*/
162+
List *tag_string_to_list(const char *tags_string)
163+
{
164+
List *list;
165+
char *tags;
166+
char *tag;
167+
168+
list = check_list_create();
169+
170+
if (NULL == tags_string)
171+
{
172+
return list;
173+
}
174+
175+
tags = strdup(tags_string);
176+
tag = strtok(tags, " ");
177+
while (tag)
178+
{
179+
check_list_add_end(list, strdup(tag));
180+
tag = strtok(NULL, " ");
181+
}
182+
free(tags);
183+
return list;
184+
}
185+
186+
void tcase_set_tags(TCase * tc, const char *tags_orig)
187+
{
188+
/* replace any pre-existing list */
189+
if (tc->tags)
190+
{
191+
check_list_apply(tc->tags, free);
192+
check_list_free(tc->tags);
193+
}
194+
tc->tags = tag_string_to_list(tags_orig);
195+
}
156196

157197
static void tcase_free(TCase * tc)
158198
{
@@ -161,15 +201,40 @@ static void tcase_free(TCase * tc)
161201
check_list_apply(tc->ch_sflst, free);
162202
check_list_apply(tc->unch_tflst, free);
163203
check_list_apply(tc->ch_tflst, free);
204+
check_list_apply(tc->tags, free);
164205
check_list_free(tc->tflst);
165206
check_list_free(tc->unch_sflst);
166207
check_list_free(tc->ch_sflst);
167208
check_list_free(tc->unch_tflst);
168209
check_list_free(tc->ch_tflst);
169-
210+
check_list_free(tc->tags);
170211
free(tc);
171212
}
172213

214+
unsigned int tcase_matching_tag(TCase *tc, List *check_for)
215+
{
216+
217+
if (NULL == check_for)
218+
{
219+
return 0;
220+
}
221+
222+
for(check_list_front(check_for); !check_list_at_end(check_for);
223+
check_list_advance(check_for))
224+
{
225+
for(check_list_front(tc->tags); !check_list_at_end(tc->tags);
226+
check_list_advance(tc->tags))
227+
{
228+
if (0 == strcmp((const char *)check_list_val(tc->tags),
229+
(const char *)check_list_val(check_for)))
230+
{
231+
return 1;
232+
}
233+
}
234+
}
235+
return 0;
236+
}
237+
173238
void suite_add_tcase(Suite * s, TCase * tc)
174239
{
175240
if(s == NULL || tc == NULL || check_list_contains(s->tclst, tc))

src/check.h.in

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ CK_DLL_EXP void CK_EXPORT suite_add_tcase(Suite * s, TCase * tc);
172172
* */
173173
CK_DLL_EXP TCase *CK_EXPORT tcase_create(const char *name);
174174

175+
/**
176+
* Associate a test case with certain tags.
177+
* Replaces any existing tags with the new set.
178+
*
179+
* @param tc the test case
180+
*
181+
* @param tags string containing arbitrary tags separated by spaces.
182+
* This will be copied. Passing NULL clears all tags.
183+
*
184+
* @since 0.11.0
185+
* */
186+
CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc,
187+
const char *tags);
175188
/**
176189
* Add a test function to a test case
177190
*
@@ -955,8 +968,9 @@ CK_DLL_EXP void CK_EXPORT srunner_free(SRunner * sr);
955968
* In addition to running all suites, if the suite runner has been
956969
* configured to output to a log, that is also performed.
957970
*
958-
* Note that if the CK_RUN_CASE and/or CK_RUN_SUITE environment variables
959-
* are defined, then only the named suite and/or test case is run.
971+
* Note that if the CK_RUN_CASE, CK_RUN_SUITE, CK_INCLUDE_TAGS and/or
972+
* CK_EXCLUDE_TAGS environment variables are defined, then only the
973+
* named suites or test cases will run.
960974
*
961975
* @param sr suite runner to run all suites from
962976
* @param print_mode the verbosity in which to report results to stdout
@@ -974,9 +988,22 @@ CK_DLL_EXP void CK_EXPORT srunner_run_all(SRunner * sr,
974988
* suite runner has been configured to output to a log, that is also
975989
* performed.
976990
*
991+
* Note that if the sname and tcname parameters are passed as null
992+
* then the function will fallback to using the environment variables
993+
* CK_RUN_SUITE and CK_RUN_CASE respectively in order to select the
994+
* suite/cases.
995+
*
996+
* Similarly if the CK_INCLUDE_TAGS and/or CK_EXCLUDE_TAGS environment
997+
* variables are defined then these will further filter the test cases
998+
* (see srunner_run_tagged, below).
999+
*
9771000
* @param sr suite runner where the given suite or test case must be
978-
* @param sname suite name to run. A NULL means "any suite".
979-
* @param tcname test case name to run. A NULL means "any test case"
1001+
* @param sname suite name to run. A NULL means use the value of the
1002+
* environment variable CK_RUN_SUITE if set, otherwise run "any/every
1003+
* suite".
1004+
* @param tcname test case name to run. A NULL means use the value of
1005+
* the environment variable CK_RUN_CASE if set, otherwise run
1006+
* "any/every case".
9801007
* @param print_mode the verbosity in which to report results to stdout
9811008
*
9821009
* @since 0.9.9
@@ -986,6 +1013,46 @@ CK_DLL_EXP void CK_EXPORT srunner_run(SRunner * sr, const char *sname,
9861013
enum print_output print_mode);
9871014

9881015

1016+
/**
1017+
* Run a specific suite or test case or testcases with specific tags
1018+
* from a suite runner, printing results to stdout as specified by the
1019+
* print_mode.
1020+
*
1021+
* In addition to running any applicable suites or test cases, if the
1022+
* suite runner has been configured to output to a log, that is also
1023+
* performed.
1024+
*
1025+
* Note that if sname, tcname, include_tags, exclude_tags parameters
1026+
* are passed as NULL then if the environment variables CK_RUN_SUITE,
1027+
* CK_RUN_CASE, CK_INCLUDE_TAGS, CK_EXCLUDE_TAGS are defined then these
1028+
* values will be used instead.
1029+
*
1030+
* @param sr suite runner where the given suite or test case must be
1031+
* @param sname suite name to run. A NULL means use the value of the
1032+
* environment variable CK_RUN_SUITE if set, otherwise run "any/every
1033+
* suite".
1034+
* @param tcname test case name to run. A NULL means use the value of
1035+
* the environment variable CK_RUN_CASE if set, otherwise run
1036+
* "any/every case".
1037+
* @param include_tags space separate list of tags. Only run test
1038+
* cases that share one of these tags. A NULL means use the value of
1039+
* the environment variable CK_INCLUDE_TAGS if set, otherwise run
1040+
* "any/every test case".
1041+
* @param exclude_tags space separate list of tags. Only run test
1042+
* cases that do not share one of these tags even if they are selected
1043+
* by an included tag. A NULL means use the value of the environment
1044+
* variable CK_EXCLUDE_TAGS if set, otherwise run "any/every test
1045+
* case".
1046+
* @param print_mode the verbosity in which to report results to stdout
1047+
*
1048+
* @since 0.11.0
1049+
*/
1050+
CK_DLL_EXP void CK_EXPORT srunner_run_tagged(SRunner * sr, const char *sname,
1051+
const char *tcname,
1052+
const char *include_tags,
1053+
const char *exclude_tags,
1054+
enum print_output print_mode);
1055+
9891056
/**
9901057
* Retrieve the number of failed tests executed by a suite runner.
9911058
*

src/check_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct TCase
6565
List *unch_tflst;
6666
List *ch_sflst;
6767
List *ch_tflst;
68+
List *tags;
6869
};
6970

7071
typedef struct TestStats
@@ -134,4 +135,7 @@ enum fork_status cur_fork_status(void);
134135

135136
clockid_t check_get_clockid(void);
136137

138+
unsigned int tcase_matching_tag(TCase *tc, List *check_for);
139+
List *tag_string_to_list(const char *tags_string);
140+
137141
#endif /* CHECK_IMPL_H */

0 commit comments

Comments
 (0)