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 */
126139static void bs_test_tcode_init (void );
127140static 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. */
139157static 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);
9301016static void _bs_test_context_setup_ok (bs_test_t * test_ptr );
9311017static void _bs_test_context_setup_fail (bs_test_t * test_ptr );
9321018static 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. */
9351022static 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