1/* Self tests for gdb_environ for GDB, the GNU debugger. 2 3 Copyright (C) 2017-2020 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 25static const char gdb_selftest_env_var[] = "GDB_SELFTEST_ENVIRON"; 26 27static bool 28set_contains (const std::set<std::string> &set, std::string key) 29{ 30 return set.find (key) != set.end (); 31} 32 33namespace selftests { 34namespace gdb_environ_tests { 35 36/* Test if the vector is initialized in a correct way. */ 37 38static void 39test_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 55static void 56test_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 72static void 73test_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 93static void 94test_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 121static void 122test_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 144static void 145test_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 161static void 162test_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 187static void 188test_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 213static void 214test_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 240static void 241test_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 268static void 269run_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 301void _initialize_environ_selftests (); 302void 303_initialize_environ_selftests () 304{ 305 selftests::register_test ("gdb_environ", 306 selftests::gdb_environ_tests::run_tests); 307} 308