A Discrete-Event Network Simulator
API
environment-variable-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 Lawrence Livermore National Laboratory
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
18  */
19 
20 #include "ns3/environment-variable.h"
21 #include "ns3/test.h"
22 
23 #include <cstdlib> // getenv
24 
25 namespace ns3
26 {
27 
28 namespace tests
29 {
30 
47 class EnvVarTestCase : public TestCase
48 {
49  public:
52 
54  ~EnvVarTestCase() override;
55 
56  private:
58  void DoRun() override;
59 
62 
65 
71  void SetVariable(const std::string& where, const std::string& value);
72 
77  void UnsetVariable(const std::string& where);
78 
86  void Check(const std::string& where, const std::string& envValue, KeyValueStore expect);
87 
94  void SetAndCheck(const std::string& where, const std::string& envValue, KeyValueStore expect);
95 
102  void CheckGet(const std::string& where, const std::string& key, KeyFoundType expect);
103 
112  void SetCheckAndGet(const std::string& where,
113  const std::string& envValue,
114  KeyValueStore expectDict,
115  const std::string& key,
116  KeyFoundType expectValue);
117 
119  const std::string m_delimiter{"|"};
120 
122  const std::string m_variable{"NS_ENVVAR_TEST"};
123 
124 }; // class EnvVarTestCase
125 
127  : TestCase("environment-variable-cache")
128 {
129 }
130 
132 {
133  UnsetVariable("destructor");
134 }
135 
136 void
137 EnvVarTestCase::SetVariable(const std::string& where, const std::string& value)
138 {
140  bool ok = EnvironmentVariable::Set(m_variable, value);
141  NS_TEST_EXPECT_MSG_EQ(ok, true, where << ": failed to set variable");
142 
143  // Double check
144  const char* envCstr = std::getenv(m_variable.c_str());
145  NS_TEST_EXPECT_MSG_NE(envCstr, nullptr, where << ": failed to retrieve variable just set");
146  NS_TEST_EXPECT_MSG_EQ(envCstr, value, where << ": failed to retrieve value just set");
147 }
148 
149 void
150 EnvVarTestCase::UnsetVariable(const std::string& where)
151 {
153  bool ok = EnvironmentVariable::Unset(where);
154  NS_TEST_EXPECT_MSG_EQ(ok, true, where << ": failed to unset variable");
155 }
156 
157 void
158 EnvVarTestCase::Check(const std::string& where, const std::string& envValue, KeyValueStore expect)
159 {
161 
162  // Print the expect and which ones were found in dict
163  std::cout << "\n"
164  << where << " variable: '" << envValue << "', expect[" << expect.size() << "]"
165  << ", dict[" << dict.size() << "]\n";
166 
167  NS_TEST_EXPECT_MSG_EQ(dict.size(), expect.size(), where << ": unequal dictionary sizes");
168 
169  std::size_t i{0};
170  for (const auto& kv : expect)
171  {
172  std::cout << " [" << i++ << "] '" << kv.first << "'\t'" << kv.second << "'";
173 
174  auto loc = dict.find(kv.first);
175  bool found = loc != dict.end();
176  std::cout << (found ? "\tfound" : "\tNOT FOUND");
177  NS_TEST_EXPECT_MSG_EQ(found, true, where << ": expected key not found: " << kv.second);
178 
179  if (found)
180  {
181  bool match = kv.second == loc->second;
182  if (match)
183  {
184  std::cout << ", match";
185  }
186  else
187  {
188  std::cout << ", NO MATCH: '" << loc->second << "'";
189  }
190  NS_TEST_EXPECT_MSG_EQ(kv.second, loc->second, where << ": key found, value mismatch");
191  }
192  std::cout << "\n";
193  ++i;
194  }
195 
196  // Now just check dict for unexpected values
197  i = 0;
198  bool first{true};
199  for (const auto& kv : dict)
200  {
201  bool found = expect.find(kv.first) != expect.end();
202  if (!found)
203  {
204  std::cout << (first ? "Unexpected keys:" : "");
205  first = false;
206  std::cout << " [" << i << "] '" << kv.first << "'\t'" << kv.second << "'"
207  << " unexpected key, value\n";
208  }
209  ++i;
210  }
211 }
212 
213 void
214 EnvVarTestCase::SetAndCheck(const std::string& where,
215  const std::string& envValue,
216  KeyValueStore expect)
217 {
218  SetVariable(where, envValue);
219  Check(where, envValue, expect);
220 }
221 
222 void
223 EnvVarTestCase::CheckGet(const std::string& where, const std::string& key, KeyFoundType expect)
224 {
225  auto [found, value] = EnvironmentVariable::Get(m_variable, key, m_delimiter);
226  NS_TEST_EXPECT_MSG_EQ(found,
227  expect.first,
228  where << ": key '" << key << "' " << (expect.first ? "not " : "")
229  << "found unexpectedly");
230  NS_TEST_EXPECT_MSG_EQ(value,
231  expect.second,
232  where << ": incorrect value for key '" << key << "'");
233 }
234 
235 void
236 EnvVarTestCase::SetCheckAndGet(const std::string& where,
237  const std::string& envValue,
238  KeyValueStore expectDict,
239  const std::string& key,
240  KeyFoundType expectValue)
241 {
242  SetAndCheck(where, envValue, expectDict);
243  CheckGet(where, key, expectValue);
244 }
245 
246 void
248 {
249  // Environment variable not set.
250  UnsetVariable("unset");
251  Check("unset", "", {});
252  auto [found, value] = EnvironmentVariable::Get(m_variable);
253  NS_TEST_EXPECT_MSG_EQ(found, false, "unset: variable found when not set");
254  NS_TEST_EXPECT_MSG_EQ(value.empty(), true, "unset: non-empty value from unset variable");
255 
256  // Variable set but empty
257 #ifndef __WIN32__
258  // Windows doesn't support environment variables with empty values
259  SetCheckAndGet("empty", "", {}, "", {true, ""});
260 #endif
261 
262  // Key not in variable
263  SetCheckAndGet("no-key",
264  "not|the|right=value",
265  {{"not", ""}, {"the", ""}, {"right", "value"}},
266  "key",
267  {false, ""});
268 
269  // Key only (no delimiter): "key"
270  SetCheckAndGet("key-only", "key", {{"key", ""}}, "key", {true, ""});
271 
272  // Extra delimiter: ":key", "key:"
273  SetCheckAndGet("front-|", "|key", {{"key", ""}}, "key", {true, ""});
274  SetCheckAndGet("back-|", "key|", {{"key", ""}}, "key", {true, ""});
275 
276  // Double delimiter: "||key", "key||"
277  SetCheckAndGet("front-||", "||key", {{"key", ""}}, "key", {true, ""});
278  SetCheckAndGet("back-||", "key||", {{"key", ""}}, "key", {true, ""});
279 
280  // Two keys: "key1|key2"
281  SetCheckAndGet("two keys", "key1|key2", {{"key1", ""}, {"key2", ""}}, "key1", {true, ""});
282  CheckGet("two keys", "key2", {true, ""});
283 
284  // Extra/double delimiters| "||key1|key2", "|key1|key2", "key1||key2", "key1|key2|",
285  // "key1|key2||"
286  SetCheckAndGet("||two keys", "||key1|key2", {{"key1", ""}, {"key2", ""}}, "key1", {true, ""});
287  CheckGet("||two keys", "key2", {true, ""});
288  SetCheckAndGet("two keys||", "key1|key2||", {{"key1", ""}, {"key2", ""}}, "key1", {true, ""});
289  CheckGet("two keys||", "key2", {true, ""});
290 
291  // Key=value: "key=value"
292  SetCheckAndGet("key-val", "key=value", {{"key", "value"}}, "key", {true, "value"});
293 
294  // Mixed key-only, key=value| "key1|key2=|key3|key4=value"
295  SetCheckAndGet("mixed",
296  "key1|key2=value|key3|key4=value",
297  {{"key1", ""}, {"key2", "value"}, {"key3", ""}, {"key4", "value"}},
298  "key1",
299  {true, ""});
300  CheckGet("mixed", "key2", {true, "value"});
301  CheckGet("mixed", "key3", {true, ""});
302  CheckGet("mixed", "key4", {true, "value"});
303 
304  // Empty/missing value| "key="
305  SetCheckAndGet("key=", "key=", {{"key", ""}}, "key", {true, ""});
306 
307  // Extra `=`| "key==value"
308  SetCheckAndGet("key==", "key==", {{"key", "="}}, "key", {true, "="});
309 
310  // Finish last line of verbose output
311  std::cout << std::endl;
312 }
313 
320 {
321  public:
323 };
324 
326  : TestSuite("environment-variables")
327 {
329 }
330 
336 
337 } // namespace tests
338 
339 } // namespace ns3
std::unordered_map< std::string, std::string > KeyValueStore
Key, value store type.
static KeyFoundType Get(const std::string &envvar, const std::string &key="", const std::string &delim=";")
Get the value corresponding to a key from an environment variable.
static bool Unset(const std::string &variable)
Unset an environment variable.
std::pair< bool, std::string > KeyFoundType
Result of a key lookup.
static void Clear()
Clear the instance, forcing all new lookups.
static bool Set(const std::string &variable, const std::string &value)
Set an environment variable.
static std::shared_ptr< Dictionary > GetDictionary(const std::string &envvar, const std::string &delim=";")
Get the dictionary for a particular environment variable.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
void SetVariable(const std::string &where, const std::string &value)
Set the test environment variable.
void CheckGet(const std::string &where, const std::string &key, KeyFoundType expect)
Check the result from a Get.
const std::string m_delimiter
Always use a non-default delimiter.
const std::string m_variable
Test environment variable name.
void Check(const std::string &where, const std::string &envValue, KeyValueStore expect)
Read envValue and check that it contains only the key,value pairs from expect.
void SetAndCheck(const std::string &where, const std::string &envValue, KeyValueStore expect)
Set and Check the variable.
EnvironmentVariable::Dictionary::KeyValueStore KeyValueStore
The key,value store.
EnvironmentVariable::KeyFoundType KeyFoundType
The return type from EnvironmentVariable::Get()
void UnsetVariable(const std::string &where)
Unset the test environment variable.
void SetCheckAndGet(const std::string &where, const std::string &envValue, KeyValueStore expectDict, const std::string &key, KeyFoundType expectValue)
Set, Check, and Get a variable.
Environment variable handling test suite.
static EnvironmentVariableTestSuite g_EnvironmentVariableTestSuite
Static variable for test initialization.
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition: test.h:666
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:251
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.