Skip to content

Commit

Permalink
Support arbitrary tagging and selection of testcases.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Crispin Dent-Young committed Jun 29, 2016
1 parent a9cd88e commit ecb56d7
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 7 deletions.
67 changes: 66 additions & 1 deletion src/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ static void suite_free(Suite * s)
free(s);
}


TCase *tcase_create(const char *name)
{
char *env;
Expand Down Expand Up @@ -149,10 +150,49 @@ TCase *tcase_create(const char *name)
tc->ch_sflst = check_list_create();
tc->unch_tflst = check_list_create();
tc->ch_tflst = check_list_create();
tc->tags = check_list_create();

return tc;
}

/*
* Helper function to create a list of tags from
* a space separated string.
*/
List *tag_string_to_list(const char *tags_string)
{
List *list;
char *tags;
char *tag;

list = check_list_create();

if (NULL == tags_string)
{
return list;
}

tags = strdup(tags_string);
tag = strtok(tags, " ");
while (tag)
{
check_list_add_end(list, strdup(tag));
tag = strtok(NULL, " ");
}
free(tags);
return list;
}

void tcase_set_tags(TCase * tc, const char *tags_orig)
{
/* replace any pre-existing list */
if (tc->tags)
{
check_list_apply(tc->tags, free);
check_list_free(tc->tags);
}
tc->tags = tag_string_to_list(tags_orig);
}

static void tcase_free(TCase * tc)
{
Expand All @@ -161,15 +201,40 @@ static void tcase_free(TCase * tc)
check_list_apply(tc->ch_sflst, free);
check_list_apply(tc->unch_tflst, free);
check_list_apply(tc->ch_tflst, free);
check_list_apply(tc->tags, free);
check_list_free(tc->tflst);
check_list_free(tc->unch_sflst);
check_list_free(tc->ch_sflst);
check_list_free(tc->unch_tflst);
check_list_free(tc->ch_tflst);

check_list_free(tc->tags);
free(tc);
}

unsigned int tcase_matching_tag(TCase *tc, List *check_for)
{

if (NULL == check_for)
{
return 0;
}

for(check_list_front(check_for); !check_list_at_end(check_for);
check_list_advance(check_for))
{
for(check_list_front(tc->tags); !check_list_at_end(tc->tags);
check_list_advance(tc->tags))
{
if (0 == strcmp((const char *)check_list_val(tc->tags),
(const char *)check_list_val(check_for)))
{
return 1;
}
}
}
return 0;
}

void suite_add_tcase(Suite * s, TCase * tc)
{
if(s == NULL || tc == NULL || check_list_contains(s->tclst, tc))
Expand Down
40 changes: 40 additions & 0 deletions src/check.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@ CK_DLL_EXP void CK_EXPORT suite_add_tcase(Suite * s, TCase * tc);
* */
CK_DLL_EXP TCase *CK_EXPORT tcase_create(const char *name);

/**
* Associate a test case with certain tags.
* Replaces any existing tags with the new set.
*
* @param tc the test case
*
* @param tags string containing arbitrary tags separated by spaces.
* This will be copied. Passing NULL clears all tags.
*
* @since 0.11.0
* */
CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc,
const char *tags);
/**
* Add a test function to a test case
*
Expand Down Expand Up @@ -986,6 +999,33 @@ CK_DLL_EXP void CK_EXPORT srunner_run(SRunner * sr, const char *sname,
enum print_output print_mode);


/**
* Run a specific suite or test case or testcases with specific tags
* from a suite runner, printing results to stdout as specified by the
* print_mode.
*
* In addition to running any applicable suites or test cases, if the
* suite runner has been configured to output to a log, that is also
* performed.
*
* @param sr suite runner where the given suite or test case must be
* @param sname suite name to run. A NULL means "any suite".
* @param tcname test case name to run. A NULL means "any test case"
* @param include_tags space separate list of tags. Only run test cases
* that share one of these tags. A NULL means "any test case".
* @param exclude_tags space separate list of tags. Only run test cases
* that do not share one of these tags. A NULL means "any test case".
* Overrides any include criteria.
* @param print_mode the verbosity in which to report results to stdout
*
* @since 0.11.0
*/
CK_DLL_EXP void CK_EXPORT srunner_run_tagged(SRunner * sr, const char *sname,
const char *tcname,
const char *include_tags,
const char *exclude_tags,
enum print_output print_mode);

/**
* Retrieve the number of failed tests executed by a suite runner.
*
Expand Down
5 changes: 5 additions & 0 deletions src/check_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ struct TCase
List *unch_tflst;
List *ch_sflst;
List *ch_tflst;
unsigned int num_tags;
List *tags;
};

typedef struct TestStats
Expand Down Expand Up @@ -134,4 +136,7 @@ enum fork_status cur_fork_status(void);

clockid_t check_get_clockid(void);

unsigned int tcase_matching_tag(TCase *tc, List *check_for);
List *tag_string_to_list(const char *tags_string);

#endif /* CHECK_IMPL_H */
48 changes: 44 additions & 4 deletions src/check_run.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ static void srunner_run_init(SRunner * sr, enum print_output print_mode);
static void srunner_run_end(SRunner * sr, enum print_output print_mode);
static void srunner_iterate_suites(SRunner * sr,
const char *sname, const char *tcname,
const char *include_tags,
const char *exclude_tags,
enum print_output print_mode);
static void srunner_iterate_tcase_tfuns(SRunner * sr, TCase * tc);
static void srunner_add_failure(SRunner * sr, TestResult * tf);
Expand Down Expand Up @@ -160,15 +162,22 @@ static void srunner_run_end(SRunner * sr,

static void srunner_iterate_suites(SRunner * sr,
const char *sname, const char *tcname,
const char *include_tags,
const char *exclude_tags,
enum print_output CK_ATTRIBUTE_UNUSED
print_mode)
{
List *include_tag_lst;
List *exclude_tag_lst;
List *slst;
List *tcl;
TCase *tc;

slst = sr->slst;

include_tag_lst = tag_string_to_list(include_tags);
exclude_tag_lst = tag_string_to_list(exclude_tags);

for(check_list_front(slst); !check_list_at_end(slst);
check_list_advance(slst))
{
Expand All @@ -191,12 +200,31 @@ static void srunner_iterate_suites(SRunner * sr,
{
continue;
}
if (include_tags != NULL)
{
if (!tcase_matching_tag(tc, include_tag_lst))
{
continue;
}
}
if (exclude_tags != NULL)
{
if (tcase_matching_tag(tc, exclude_tag_lst))
{
continue;
}
}

srunner_run_tcase(sr, tc);
}

log_suite_end(sr, s);
}

check_list_apply(include_tag_lst, free);
check_list_apply(exclude_tag_lst, free);
check_list_free(include_tag_lst);
check_list_free(exclude_tag_lst);
}

static void srunner_iterate_tcase_tfuns(SRunner * sr, TCase * tc)
Expand Down Expand Up @@ -741,8 +769,9 @@ void srunner_run_all(SRunner * sr, enum print_output print_mode)
print_mode);
}

void srunner_run(SRunner * sr, const char *sname, const char *tcname,
enum print_output print_mode)
void srunner_run_tagged(SRunner * sr, const char *sname, const char *tcname,
const char *include_tags, const char *exclude_tags,
enum print_output print_mode)
{
#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
static struct sigaction sigalarm_old_action;
Expand All @@ -756,7 +785,11 @@ void srunner_run(SRunner * sr, const char *sname, const char *tcname,
if(!tcname)
tcname = getenv("CK_RUN_CASE");
if(!sname)
sname = getenv("CK_RUN_SUITE");
sname = getenv("CK_RUN_SUITE");
if(!include_tags)
include_tags = getenv("CK_INCLUDE_TAGS");
if(!exclude_tags)
exclude_tags = getenv("CK_EXCLUDE_TAGS");

if(sr == NULL)
return;
Expand All @@ -779,7 +812,8 @@ void srunner_run(SRunner * sr, const char *sname, const char *tcname,
sigaction(SIGTERM, &sigterm_new_action, &sigterm_old_action);
#endif /* HAVE_SIGACTION && HAVE_FORK */
srunner_run_init(sr, print_mode);
srunner_iterate_suites(sr, sname, tcname, print_mode);
srunner_iterate_suites(sr, sname, tcname, include_tags, exclude_tags,
print_mode);
srunner_run_end(sr, print_mode);
#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
sigaction(SIGALRM, &sigalarm_old_action, NULL);
Expand All @@ -788,6 +822,12 @@ void srunner_run(SRunner * sr, const char *sname, const char *tcname,
#endif /* HAVE_SIGACTION && HAVE_FORK */
}

void srunner_run(SRunner * sr, const char *sname, const char *tcname,
enum print_output print_mode)
{
srunner_run_tagged(sr, sname, tcname, NULL, NULL, print_mode);
}

pid_t check_fork(void)
{
#if defined(HAVE_FORK) && HAVE_FORK==1
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ set(CHECK_CHECK_SOURCES
check_check_pack.c
check_check_selective.c
check_check_sub.c
check_check_tags.c
check_list.c)
set(CHECK_CHECK_HEADERS check_check.h)
add_executable(check_check ${CHECK_CHECK_HEADERS} ${CHECK_CHECK_SOURCES})
Expand Down
5 changes: 4 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ check_check_export_SOURCES = \
check_check_master.c \
check_check_log.c \
check_check_fork.c \
check_check_tags.c \
check_check_export_main.c
check_check_export_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la

Expand All @@ -57,7 +58,8 @@ check_check_SOURCES = \
check_check_fixture.c \
check_check_pack.c \
check_check_exit.c \
check_check_selective.c \
check_check_selective.c \
check_check_tags.c \
check_check_main.c
check_check_LDADD = $(top_builddir)/src/libcheckinternal.la $(top_builddir)/lib/libcompat.la

Expand All @@ -67,6 +69,7 @@ check_mem_leaks_SOURCES = \
check_check_fork.c \
check_check_exit.c \
check_check_selective.c \
check_check_tags.c \
check_check_sub.c \
check_check_master.c
check_mem_leaks_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la
Expand Down
1 change: 1 addition & 0 deletions tests/check_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Suite *make_fixture_suite(void);
Suite *make_pack_suite(void);
Suite *make_exit_suite(void);
Suite *make_selective_suite(void);
Suite *make_tag_suite(void);

extern int master_tests_lineno[];
void init_master_tests_lineno(int num_master_tests);
Expand Down
1 change: 1 addition & 0 deletions tests/check_check_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ int main (void)
srunner_add_suite(sr, make_fork_suite());
srunner_add_suite(sr, make_fixture_suite());
srunner_add_suite(sr, make_pack_suite());
srunner_add_suite(sr, make_tag_suite());

#if defined(HAVE_FORK) && HAVE_FORK==1
srunner_add_suite(sr, make_exit_suite());
Expand Down
2 changes: 1 addition & 1 deletion tests/check_mem_leaks.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ int main ()
#if defined(HAVE_FORK) && HAVE_FORK==1
srunner_add_suite(sr, make_exit_suite());
#endif

srunner_add_suite(sr, make_tag_suite());
srunner_add_suite(sr, make_selective_suite());

/*
Expand Down

0 comments on commit ecb56d7

Please sign in to comment.