Skip to content

Commit c2a8ca7

Browse files
authored
libbase: Adds bs_test_setenv, and means to restore the env on test teardown. (#82)
1 parent 1250ee2 commit c2a8ca7

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

include/libbase/test.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,24 @@ const char *bs_test_temp_path(
276276
const char *fname_fmt_ptr,
277277
...) __ARG_PRINTF__(2, 3);
278278

279+
/**
280+
* Sets an environment variable in the process.
281+
*
282+
* This will first backup the current value of the environment variable, then
283+
* call getenv(3) to change it. Upon test teardown, the original value of the
284+
* environment variable is kept.
285+
* Repeated calls to @ref bs_test_setenv will not overwrite the backup stored
286+
* during the first call.
287+
*
288+
* @param test_ptr
289+
* @param name_ptr
290+
* @param value_fmt_ptr
291+
*/
292+
void bs_test_setenv(
293+
bs_test_t *test_ptr,
294+
const char *name_ptr,
295+
const char *value_fmt_ptr, ...) __ARG_PRINTF__(3, 4);
296+
279297
/* == Verification macros ================================================== */
280298

281299
/**

src/test.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <fnmatch.h>
2424
#include <libbase/arg.h>
2525
#include <libbase/assert.h>
26+
#include <libbase/avltree.h>
2627
#include <libbase/def.h>
2728
#include <libbase/dllist.h>
2829
#include <libbase/file.h>
@@ -53,6 +54,8 @@ struct _bs_test_t {
5354
const bs_test_set_t *set_ptr;
5455
/** Test environment. */
5556
const struct bs_test_env *env_ptr;
57+
/** Tree holding environment variables and original values. */
58+
bs_avltree_t *env_tree_ptr;
5659

5760
/** Return value of @ref bs_test_set_t::setup. */
5861
void *setup_context_ptr;
@@ -122,6 +125,16 @@ struct bs_test_env {
122125
char *data_dir_ptr;
123126
};
124127

128+
/** Node holding environment variable. */
129+
struct bs_test_env_node {
130+
/** Tree node. */
131+
bs_avltree_node_t avlnode;
132+
/** Name of the environment variable. */
133+
char *name_ptr;
134+
/** Value originally held by this environment variable. */
135+
char *value_ptr;
136+
};
137+
125138
/* Other helpers */
126139
static void bs_test_tcode_init(void);
127140
static int bs_test_putc(int c);
@@ -135,6 +148,11 @@ static int bs_test_set(const bs_test_set_t *set_ptr,
135148
const struct bs_test_env *env_ptr,
136149
bs_dllist_t *failed_tests_ptr);
137150

151+
static int _bs_test_env_node_cmp(
152+
const bs_avltree_node_t *node_ptr,
153+
const void *key_ptr);
154+
static void _bs_test_env_node_destroy(bs_avltree_node_t *node_ptr);
155+
138156
/* Testcase helpers. */
139157
static bool bs_test_case_prepare(bs_test_t *test_ptr,
140158
const bs_test_set_t *set_ptr,
@@ -546,6 +564,36 @@ const char *bs_test_temp_path(
546564
return NULL;
547565
}
548566

567+
/* ------------------------------------------------------------------------- */
568+
void bs_test_setenv(
569+
bs_test_t *test_ptr,
570+
const char *name_ptr,
571+
const char *value_fmt_ptr, ...)
572+
{
573+
if (NULL == bs_avltree_lookup(test_ptr->env_tree_ptr, name_ptr)) {
574+
struct bs_test_env_node *node_ptr = BS_ASSERT_NOTNULL(
575+
logged_calloc(1, sizeof(struct bs_test_env_node)));
576+
node_ptr->name_ptr = BS_ASSERT_NOTNULL(logged_strdup(name_ptr));
577+
char *old_value_ptr = getenv(name_ptr);
578+
if (NULL != old_value_ptr) {
579+
node_ptr->value_ptr = BS_ASSERT_NOTNULL(
580+
logged_strdup(old_value_ptr));
581+
}
582+
BS_ASSERT(bs_avltree_insert(
583+
test_ptr->env_tree_ptr,
584+
node_ptr->name_ptr,
585+
&node_ptr->avlnode,
586+
false));
587+
}
588+
589+
va_list ap;
590+
va_start(ap, value_fmt_ptr);
591+
char *value_ptr = BS_ASSERT_NOTNULL(bs_vstrdupf(value_fmt_ptr, ap));
592+
va_end(ap);
593+
setenv(name_ptr, value_ptr, 1);
594+
free(value_ptr);
595+
}
596+
549597
/* == Static (Local) Functions ============================================= */
550598

551599
/* ------------------------------------------------------------------------- */
@@ -749,6 +797,33 @@ int bs_test_set(const bs_test_set_t *set_ptr,
749797
return set_report.failed;
750798
}
751799

800+
/* ------------------------------------------------------------------------- */
801+
int _bs_test_env_node_cmp(
802+
const bs_avltree_node_t *avlnode_ptr,
803+
const void *key_ptr)
804+
{
805+
struct bs_test_env_node *node_ptr = BS_CONTAINER_OF(
806+
avlnode_ptr, struct bs_test_env_node, avlnode);
807+
return strcmp(node_ptr->name_ptr, key_ptr);
808+
}
809+
810+
/* ------------------------------------------------------------------------- */
811+
void _bs_test_env_node_destroy(bs_avltree_node_t *avlnode_ptr)
812+
{
813+
struct bs_test_env_node *node_ptr = BS_CONTAINER_OF(
814+
avlnode_ptr, struct bs_test_env_node, avlnode);
815+
if (NULL != node_ptr->name_ptr) {
816+
if (NULL != node_ptr->value_ptr) {
817+
setenv(node_ptr->name_ptr, node_ptr->value_ptr, 1);
818+
} else {
819+
unsetenv(node_ptr->name_ptr);
820+
}
821+
free(node_ptr->name_ptr);
822+
}
823+
if (NULL != node_ptr->value_ptr) free(node_ptr->value_ptr);
824+
free(node_ptr);
825+
}
826+
752827
/* ------------------------------------------------------------------------- */
753828
/**
754829
* Prepares test_ptr for this test case.
@@ -767,8 +842,14 @@ bool bs_test_case_prepare(bs_test_t *test_ptr,
767842
.case_idx = case_idx,
768843
.case_ptr = set_ptr->cases_ptr + case_idx,
769844
.failed = false,
845+
.env_tree_ptr = bs_avltree_create(
846+
_bs_test_env_node_cmp, _bs_test_env_node_destroy)
770847
};
771848

849+
if (NULL == test_ptr->env_tree_ptr) {
850+
BS_TEST_FAIL(test_ptr, "Failed bs_avltree_create(...)");
851+
}
852+
772853
if (set_ptr->setup) {
773854
test_ptr->setup_context_ptr = set_ptr->setup();
774855
if (NULL == test_ptr->setup_context_ptr) {
@@ -807,6 +888,11 @@ void bs_test_case_report(bs_test_t *test_ptr,
807888
free(test_ptr->test_path_ptr);
808889
}
809890

891+
if (NULL != test_ptr->env_tree_ptr) {
892+
bs_avltree_destroy(test_ptr->env_tree_ptr);
893+
test_ptr->env_tree_ptr = NULL;
894+
}
895+
810896
void *p;
811897
while (NULL != (p = bs_ptr_stack_pop(&test_ptr->allocated_ptrs))) {
812898
free(p);
@@ -930,6 +1016,7 @@ static void _bs_test_eq_neq_tests(bs_test_t *test_ptr);
9301016
static void _bs_test_context_setup_ok(bs_test_t *test_ptr);
9311017
static void _bs_test_context_setup_fail(bs_test_t *test_ptr);
9321018
static void _bs_test_temp_path(bs_test_t *test_ptr);
1019+
static void _bs_test_set_env(bs_test_t *test_ptr);
9331020

9341021
/** Unit test cases. */
9351022
static const bs_test_case_t bs_test_test_cases[] = {
@@ -938,6 +1025,7 @@ static const bs_test_case_t bs_test_test_cases[] = {
9381025
{ true, "context_setup_ok", _bs_test_context_setup_ok },
9391026
{ true, "context_setup_fail", _bs_test_context_setup_fail },
9401027
{ true, "temp_path", _bs_test_temp_path },
1028+
{ true, "set_env", _bs_test_set_env },
9411029
BS_TEST_CASE_SENTINEL()
9421030
};
9431031

@@ -1067,5 +1155,40 @@ void _bs_test_temp_path(bs_test_t *test_ptr)
10671155
BS_TEST_VERIFY_TRUE(test_ptr, bs_file_realpath_is(tmp_path, S_IFDIR));
10681156
}
10691157

1158+
/* ------------------------------------------------------------------------- */
1159+
/** Set and verify an env variable. Used in @ref _bs_test_set_env. */
1160+
void _bs_test_set_and_verify_env(bs_test_t *test_ptr)
1161+
{
1162+
bs_test_setenv(test_ptr, "VAR", "value");
1163+
char *value_ptr = getenv("VAR");
1164+
BS_TEST_VERIFY_NEQ_OR_RETURN(test_ptr, NULL, value_ptr);
1165+
BS_TEST_VERIFY_STREQ(test_ptr, "value", value_ptr);
1166+
}
1167+
1168+
/** Use environment variables, and ensure they're cleared on teardown. */
1169+
void _bs_test_set_env(bs_test_t *test_ptr)
1170+
{
1171+
static const bs_test_case_t cases [] = {
1172+
{ true, "set_and_verify_env", _bs_test_set_and_verify_env },
1173+
BS_TEST_CASE_SENTINEL()
1174+
};
1175+
static const bs_test_set_t set = BS_TEST_SET(true, "env", cases);
1176+
static const bs_test_set_t *sets[] = { &set, NULL };
1177+
1178+
char *old_value_ptr = getenv("VAR");
1179+
if (NULL != old_value_ptr) {
1180+
old_value_ptr = BS_ASSERT_NOTNULL(strdup(old_value_ptr));
1181+
}
1182+
BS_TEST_VERIFY_EQ(test_ptr, 0, bs_test_sets(sets, 0, NULL, NULL));
1183+
1184+
char *new_value_ptr = getenv("VAR");
1185+
if (NULL != old_value_ptr) {
1186+
BS_TEST_VERIFY_STREQ(test_ptr, old_value_ptr, new_value_ptr);
1187+
free(old_value_ptr);
1188+
} else {
1189+
BS_TEST_VERIFY_EQ(test_ptr, NULL, new_value_ptr);
1190+
}
1191+
}
1192+
10701193
/** @endcond */
10711194
/* == End of test.c ======================================================== */

0 commit comments

Comments
 (0)