1 /* Self tests for gdb_environ for GDB, the GNU debugger. 2 3 Copyright (C) 2017-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "gdbsupport/selftest.h" 22 #include "gdbsupport/environ.h" 23 #include "diagnostics.h" 24 25 static const char gdb_selftest_env_var[] = "GDB_SELFTEST_ENVIRON"; 26 27 static bool 28 set_contains (const std::set<std::string> &set, std::string key) 29 { 30 return set.find (key) != set.end (); 31 } 32 33 namespace selftests { 34 namespace gdb_environ_tests { 35 36 /* Test if the vector is initialized in a correct way. */ 37 38 static void 39 test_vector_initialization () 40 { 41 gdb_environ env; 42 43 /* When the vector is initialized, there should always be one NULL 44 element in it. */ 45 SELF_CHECK (env.envp ()[0] == NULL); 46 SELF_CHECK (env.user_set_env ().size () == 0); 47 SELF_CHECK (env.user_unset_env ().size () == 0); 48 49 /* Make sure that there is no other element. */ 50 SELF_CHECK (env.get ("PWD") == NULL); 51 } 52 53 /* Test initialization using the host's environ. */ 54 55 static void 56 test_init_from_host_environ () 57 { 58 /* Initialize the environment vector using the host's environ. */ 59 gdb_environ env = gdb_environ::from_host_environ (); 60 61 /* The user-set and user-unset lists must be empty. */ 62 SELF_CHECK (env.user_set_env ().size () == 0); 63 SELF_CHECK (env.user_unset_env ().size () == 0); 64 65 /* Our test environment variable should be present at the 66 vector. */ 67 SELF_CHECK (strcmp (env.get (gdb_selftest_env_var), "1") == 0); 68 } 69 70 /* Test reinitialization using the host's environ. */ 71 72 static void 73 test_reinit_from_host_environ () 74 { 75 /* Reinitialize our environ vector using the host environ. We 76 should be able to see one (and only one) instance of the test 77 variable. */ 78 gdb_environ env = gdb_environ::from_host_environ (); 79 env = gdb_environ::from_host_environ (); 80 char **envp = env.envp (); 81 int num_found = 0; 82 83 for (size_t i = 0; envp[i] != NULL; ++i) 84 if (strcmp (envp[i], "GDB_SELFTEST_ENVIRON=1") == 0) 85 ++num_found; 86 SELF_CHECK (num_found == 1); 87 } 88 89 /* Test the case when we set a variable A, then set a variable B, 90 then unset A, and make sure that we cannot find A in the environ 91 vector, but can still find B. */ 92 93 static void 94 test_set_A_unset_B_unset_A_cannot_find_A_can_find_B () 95 { 96 gdb_environ env; 97 98 env.set ("GDB_SELFTEST_ENVIRON_1", "aaa"); 99 SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_1"), "aaa") == 0); 100 /* User-set environ var list must contain one element. */ 101 SELF_CHECK (env.user_set_env ().size () == 1); 102 SELF_CHECK (set_contains (env.user_set_env (), 103 std::string ("GDB_SELFTEST_ENVIRON_1=aaa"))); 104 105 env.set ("GDB_SELFTEST_ENVIRON_2", "bbb"); 106 SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_2"), "bbb") == 0); 107 108 env.unset ("GDB_SELFTEST_ENVIRON_1"); 109 SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON_1") == NULL); 110 SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_2"), "bbb") == 0); 111 112 /* The user-set environ var list must contain only one element 113 now. */ 114 SELF_CHECK (set_contains (env.user_set_env (), 115 std::string ("GDB_SELFTEST_ENVIRON_2=bbb"))); 116 SELF_CHECK (env.user_set_env ().size () == 1); 117 } 118 119 /* Check if unset followed by a set in an empty vector works. */ 120 121 static void 122 test_unset_set_empty_vector () 123 { 124 gdb_environ env; 125 126 env.set ("PWD", "test"); 127 SELF_CHECK (strcmp (env.get ("PWD"), "test") == 0); 128 SELF_CHECK (set_contains (env.user_set_env (), std::string ("PWD=test"))); 129 SELF_CHECK (env.user_unset_env ().size () == 0); 130 /* The second element must be NULL. */ 131 SELF_CHECK (env.envp ()[1] == NULL); 132 SELF_CHECK (env.user_set_env ().size () == 1); 133 env.unset ("PWD"); 134 SELF_CHECK (env.envp ()[0] == NULL); 135 SELF_CHECK (env.user_set_env ().size () == 0); 136 SELF_CHECK (env.user_unset_env ().size () == 1); 137 SELF_CHECK (set_contains (env.user_unset_env (), std::string ("PWD"))); 138 } 139 140 /* When we clear our environ vector, there should be only one 141 element on it (NULL), and we shouldn't be able to get our test 142 variable. */ 143 144 static void 145 test_vector_clear () 146 { 147 gdb_environ env; 148 149 env.set (gdb_selftest_env_var, "1"); 150 151 env.clear (); 152 SELF_CHECK (env.envp ()[0] == NULL); 153 SELF_CHECK (env.user_set_env ().size () == 0); 154 SELF_CHECK (env.user_unset_env ().size () == 0); 155 SELF_CHECK (env.get (gdb_selftest_env_var) == NULL); 156 } 157 158 /* Test that after a std::move the moved-from object is left at a 159 valid state (i.e., its only element is NULL). */ 160 161 static void 162 test_std_move () 163 { 164 gdb_environ env; 165 gdb_environ env2; 166 167 env.set ("A", "1"); 168 SELF_CHECK (strcmp (env.get ("A"), "1") == 0); 169 SELF_CHECK (set_contains (env.user_set_env (), std::string ("A=1"))); 170 SELF_CHECK (env.user_set_env ().size () == 1); 171 172 env2 = std::move (env); 173 SELF_CHECK (env.envp ()[0] == NULL); 174 SELF_CHECK (strcmp (env2.get ("A"), "1") == 0); 175 SELF_CHECK (env2.envp ()[1] == NULL); 176 SELF_CHECK (env.user_set_env ().size () == 0); 177 SELF_CHECK (set_contains (env2.user_set_env (), std::string ("A=1"))); 178 SELF_CHECK (env2.user_set_env ().size () == 1); 179 env.set ("B", "2"); 180 SELF_CHECK (strcmp (env.get ("B"), "2") == 0); 181 SELF_CHECK (env.envp ()[1] == NULL); 182 } 183 184 /* Test that the move constructor leaves everything at a valid 185 state. */ 186 187 static void 188 test_move_constructor () 189 { 190 gdb_environ env; 191 192 env.set ("A", "1"); 193 SELF_CHECK (strcmp (env.get ("A"), "1") == 0); 194 SELF_CHECK (set_contains (env.user_set_env (), std::string ("A=1"))); 195 196 gdb_environ env2 = std::move (env); 197 SELF_CHECK (env.envp ()[0] == NULL); 198 SELF_CHECK (env.user_set_env ().size () == 0); 199 SELF_CHECK (strcmp (env2.get ("A"), "1") == 0); 200 SELF_CHECK (env2.envp ()[1] == NULL); 201 SELF_CHECK (set_contains (env2.user_set_env (), std::string ("A=1"))); 202 SELF_CHECK (env2.user_set_env ().size () == 1); 203 204 env.set ("B", "2"); 205 SELF_CHECK (strcmp (env.get ("B"), "2") == 0); 206 SELF_CHECK (env.envp ()[1] == NULL); 207 SELF_CHECK (set_contains (env.user_set_env (), std::string ("B=2"))); 208 SELF_CHECK (env.user_set_env ().size () == 1); 209 } 210 211 /* Test that self-moving works. */ 212 213 static void 214 test_self_move () 215 { 216 gdb_environ env; 217 218 /* Test self-move. */ 219 env.set ("A", "1"); 220 SELF_CHECK (strcmp (env.get ("A"), "1") == 0); 221 SELF_CHECK (set_contains (env.user_set_env (), std::string ("A=1"))); 222 SELF_CHECK (env.user_set_env ().size () == 1); 223 224 /* Some compilers warn about moving to self, but that's precisely what we want 225 to test here, so turn this warning off. */ 226 DIAGNOSTIC_PUSH 227 DIAGNOSTIC_IGNORE_SELF_MOVE 228 env = std::move (env); 229 DIAGNOSTIC_POP 230 231 SELF_CHECK (strcmp (env.get ("A"), "1") == 0); 232 SELF_CHECK (strcmp (env.envp ()[0], "A=1") == 0); 233 SELF_CHECK (env.envp ()[1] == NULL); 234 SELF_CHECK (set_contains (env.user_set_env (), std::string ("A=1"))); 235 SELF_CHECK (env.user_set_env ().size () == 1); 236 } 237 238 /* Test if set/unset/reset works. */ 239 240 static void 241 test_set_unset_reset () 242 { 243 gdb_environ env = gdb_environ::from_host_environ (); 244 245 /* Our test variable should already be present in the host's environment. */ 246 SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON") != NULL); 247 248 /* Set our test variable to another value. */ 249 env.set ("GDB_SELFTEST_ENVIRON", "test"); 250 SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON"), "test") == 0); 251 SELF_CHECK (env.user_set_env ().size () == 1); 252 SELF_CHECK (env.user_unset_env ().size () == 0); 253 254 /* And unset our test variable. The variable still exists in the 255 host's environment, but doesn't exist in our vector. */ 256 env.unset ("GDB_SELFTEST_ENVIRON"); 257 SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON") == NULL); 258 SELF_CHECK (env.user_set_env ().size () == 0); 259 SELF_CHECK (env.user_unset_env ().size () == 1); 260 SELF_CHECK (set_contains (env.user_unset_env (), 261 std::string ("GDB_SELFTEST_ENVIRON"))); 262 263 /* Re-set the test variable. */ 264 env.set ("GDB_SELFTEST_ENVIRON", "1"); 265 SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON"), "1") == 0); 266 } 267 268 static void 269 run_tests () 270 { 271 /* Set a test environment variable. */ 272 if (setenv ("GDB_SELFTEST_ENVIRON", "1", 1) != 0) 273 error (_("Could not set environment variable for testing.")); 274 275 test_vector_initialization (); 276 277 test_unset_set_empty_vector (); 278 279 test_init_from_host_environ (); 280 281 test_set_unset_reset (); 282 283 test_vector_clear (); 284 285 test_reinit_from_host_environ (); 286 287 /* Get rid of our test variable. We won't need it anymore. */ 288 unsetenv ("GDB_SELFTEST_ENVIRON"); 289 290 test_set_A_unset_B_unset_A_cannot_find_A_can_find_B (); 291 292 test_std_move (); 293 294 test_move_constructor (); 295 296 test_self_move (); 297 } 298 } /* namespace gdb_environ */ 299 } /* namespace selftests */ 300 301 void _initialize_environ_selftests (); 302 void 303 _initialize_environ_selftests () 304 { 305 selftests::register_test ("gdb_environ", 306 selftests::gdb_environ_tests::run_tests); 307 } 308