1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections; 6 using System.Collections.Generic; 7 using System.IO; 8 using System.Linq; 9 using System.Runtime.InteropServices; 10 using Xunit; 11 12 namespace System.Tests 13 { 14 public partial class GetEnvironmentVariable 15 { 16 [Fact] InvalidArguments_ThrowsExceptions()17 public void InvalidArguments_ThrowsExceptions() 18 { 19 AssertExtensions.Throws<ArgumentNullException>("variable", () => Environment.GetEnvironmentVariable(null)); 20 AssertExtensions.Throws<ArgumentNullException>("variable", () => Environment.SetEnvironmentVariable(null, "test")); 21 AssertExtensions.Throws<ArgumentException>("variable", () => Environment.SetEnvironmentVariable("", "test")); 22 23 AssertExtensions.Throws<ArgumentException>("variable", () => Environment.SetEnvironmentVariable("", "test", EnvironmentVariableTarget.Machine)); 24 AssertExtensions.Throws<ArgumentNullException>("variable", () => Environment.SetEnvironmentVariable(null, "test", EnvironmentVariableTarget.User)); 25 AssertExtensions.Throws<ArgumentNullException>("variable", () => Environment.GetEnvironmentVariable(null, EnvironmentVariableTarget.Process)); 26 AssertExtensions.Throws<ArgumentOutOfRangeException, ArgumentException>("target", null, () => Environment.GetEnvironmentVariable("test", (EnvironmentVariableTarget)42)); 27 AssertExtensions.Throws<ArgumentOutOfRangeException, ArgumentException>("target", null, () => Environment.SetEnvironmentVariable("test", "test", (EnvironmentVariableTarget)(-1))); 28 AssertExtensions.Throws<ArgumentOutOfRangeException, ArgumentException>("target", null, () => Environment.GetEnvironmentVariables((EnvironmentVariableTarget)(3))); 29 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && System.Tests.SetEnvironmentVariable.IsSupportedTarget(EnvironmentVariableTarget.User)) 30 { 31 AssertExtensions.Throws<ArgumentException>("variable", null, () => Environment.SetEnvironmentVariable(new string('s', 256), "value", EnvironmentVariableTarget.User)); 32 } 33 } 34 35 [Fact] EmptyVariableReturnsNull()36 public void EmptyVariableReturnsNull() 37 { 38 Assert.Null(Environment.GetEnvironmentVariable(String.Empty)); 39 } 40 41 [Fact] 42 [PlatformSpecific(TestPlatforms.Windows)] // GetEnvironmentVariable by design doesn't respect changes via setenv RandomLongVariableNameCanRoundTrip()43 public void RandomLongVariableNameCanRoundTrip() 44 { 45 // NOTE: The limit of 32766 characters enforced by desktop 46 // SetEnvironmentVariable is antiquated. I was 47 // able to create ~1GB names and values on my Windows 8.1 box. On 48 // desktop, GetEnvironmentVariable throws OOM during its attempt to 49 // demand huge EnvironmentPermission well before that. Also, the old 50 // test for long name case wasn't very good: it just checked that an 51 // arbitrary long name > 32766 characters returned null (not found), but 52 // that had nothing to do with the limit, the variable was simply not 53 // found! 54 55 string variable = "LongVariable_" + new string('@', 33000); 56 const string value = "TestValue"; 57 58 try 59 { 60 SetEnvironmentVariableWithPInvoke(variable, value); 61 62 Assert.Equal(value, Environment.GetEnvironmentVariable(variable)); 63 } 64 finally 65 { 66 SetEnvironmentVariableWithPInvoke(variable, null); 67 } 68 } 69 70 [Fact] RandomVariableThatDoesNotExistReturnsNull()71 public void RandomVariableThatDoesNotExistReturnsNull() 72 { 73 string variable = "TestVariable_SurelyThisDoesNotExist"; 74 Assert.Null(Environment.GetEnvironmentVariable(variable)); 75 } 76 77 [Fact] VariableNamesAreCaseInsensitiveAsAppropriate()78 public void VariableNamesAreCaseInsensitiveAsAppropriate() 79 { 80 string value = "TestValue"; 81 82 try 83 { 84 Environment.SetEnvironmentVariable("ThisIsATestEnvironmentVariable", value); 85 86 Assert.Equal(value, Environment.GetEnvironmentVariable("ThisIsATestEnvironmentVariable")); 87 88 if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 89 { 90 value = null; 91 } 92 93 Assert.Equal(value, Environment.GetEnvironmentVariable("thisisatestenvironmentvariable")); 94 Assert.Equal(value, Environment.GetEnvironmentVariable("THISISATESTENVIRONMENTVARIABLE")); 95 Assert.Equal(value, Environment.GetEnvironmentVariable("ThISISATeSTENVIRoNMEnTVaRIABLE")); 96 } 97 finally 98 { 99 Environment.SetEnvironmentVariable("ThisIsATestEnvironmentVariable", null); 100 } 101 } 102 103 [Fact] CanGetAllVariablesIndividually()104 public void CanGetAllVariablesIndividually() 105 { 106 Random r = new Random(); 107 string envVar1 = "TestVariable_CanGetVariablesIndividually_" + r.Next().ToString(); 108 string envVar2 = "TestVariable_CanGetVariablesIndividually_" + r.Next().ToString(); 109 110 try 111 { 112 Environment.SetEnvironmentVariable(envVar1, envVar1); 113 Environment.SetEnvironmentVariable(envVar2, envVar2); 114 115 IDictionary envBlock = Environment.GetEnvironmentVariables(); 116 117 // Make sure the environment variables we set are part of the dictionary returned. 118 Assert.True(envBlock.Contains(envVar1)); 119 Assert.True(envBlock.Contains(envVar1)); 120 121 // Make sure the values match the expected ones. 122 Assert.Equal(envVar1, envBlock[envVar1]); 123 Assert.Equal(envVar2, envBlock[envVar2]); 124 125 // Make sure we can read the individual variables as well 126 Assert.Equal(envVar1, Environment.GetEnvironmentVariable(envVar1)); 127 Assert.Equal(envVar2, Environment.GetEnvironmentVariable(envVar2)); 128 } 129 finally 130 { 131 // Clear the variables we just set 132 Environment.SetEnvironmentVariable(envVar1, null); 133 Environment.SetEnvironmentVariable(envVar2, null); 134 } 135 } 136 137 [Fact] EnumerateYieldsDictionaryEntryFromIEnumerable()138 public void EnumerateYieldsDictionaryEntryFromIEnumerable() 139 { 140 // GetEnvironmentVariables has always yielded DictionaryEntry from IEnumerable 141 IDictionary vars = Environment.GetEnvironmentVariables(); 142 IEnumerator enumerator = ((IEnumerable)vars).GetEnumerator(); 143 if (enumerator.MoveNext()) 144 { 145 Assert.IsType<DictionaryEntry>(enumerator.Current); 146 } 147 else 148 { 149 Assert.Throws<InvalidOperationException>(() => enumerator.Current); 150 } 151 } 152 153 [Fact] GetEnumerator_IDictionaryEnumerator_YieldsDictionaryEntries()154 public void GetEnumerator_IDictionaryEnumerator_YieldsDictionaryEntries() 155 { 156 // GetEnvironmentVariables has always yielded DictionaryEntry from IDictionaryEnumerator 157 IDictionary vars = Environment.GetEnvironmentVariables(); 158 IDictionaryEnumerator enumerator = vars.GetEnumerator(); 159 if (enumerator.MoveNext()) 160 { 161 Assert.IsType<DictionaryEntry>(enumerator.Current); 162 } 163 else 164 { 165 Assert.Throws<InvalidOperationException>(() => enumerator.Current); 166 } 167 } 168 169 [Theory] 170 [InlineData(null)] 171 [MemberData(nameof(EnvironmentTests.EnvironmentVariableTargets), MemberType = typeof(EnvironmentTests))] 172 [ActiveIssue("https://github.com/dotnet/corefx/issues/23003", TargetFrameworkMonikers.NetFramework)] 173 public void GetEnumerator_LinqOverDictionaryEntries_Success(EnvironmentVariableTarget? target) 174 { 175 IDictionary envVars = target != null ? 176 Environment.GetEnvironmentVariables(target.Value) : 177 Environment.GetEnvironmentVariables(); 178 179 Assert.IsType<Hashtable>(envVars); 180 181 foreach (KeyValuePair<string, string> envVar in envVars.Cast<DictionaryEntry>().Select(de => new KeyValuePair<string, string>((string)de.Key, (string)de.Value))) 182 { 183 Assert.NotNull(envVar.Key); 184 } 185 } 186 EnvironmentVariablesAreHashtable()187 public void EnvironmentVariablesAreHashtable() 188 { 189 // On NetFX, the type returned was always Hashtable 190 Assert.IsType<Hashtable>(Environment.GetEnvironmentVariables()); 191 } 192 193 [Theory] 194 [MemberData(nameof(EnvironmentTests.EnvironmentVariableTargets), MemberType = typeof(EnvironmentTests))] EnvironmentVariablesAreHashtable(EnvironmentVariableTarget target)195 public void EnvironmentVariablesAreHashtable(EnvironmentVariableTarget target) 196 { 197 // On NetFX, the type returned was always Hashtable 198 Assert.IsType<Hashtable>(Environment.GetEnvironmentVariables(target)); 199 } 200 201 [Theory] 202 [MemberData(nameof(EnvironmentTests.EnvironmentVariableTargets), MemberType = typeof(EnvironmentTests))] EnumerateYieldsDictionaryEntryFromIEnumerable(EnvironmentVariableTarget target)203 public void EnumerateYieldsDictionaryEntryFromIEnumerable(EnvironmentVariableTarget target) 204 { 205 // GetEnvironmentVariables has always yielded DictionaryEntry from IEnumerable 206 IDictionary vars = Environment.GetEnvironmentVariables(target); 207 IEnumerator enumerator = ((IEnumerable)vars).GetEnumerator(); 208 if (enumerator.MoveNext()) 209 { 210 Assert.IsType<DictionaryEntry>(enumerator.Current); 211 } 212 else 213 { 214 Assert.Throws<InvalidOperationException>(() => enumerator.Current); 215 } 216 } 217 218 [Theory] 219 [MemberData(nameof(EnvironmentTests.EnvironmentVariableTargets), MemberType = typeof(EnvironmentTests))] EnumerateEnvironmentVariables(EnvironmentVariableTarget target)220 public void EnumerateEnvironmentVariables(EnvironmentVariableTarget target) 221 { 222 bool lookForSetValue = (target == EnvironmentVariableTarget.Process) || 223 // On the Project N corelib, it doesn't attempt to set machine/user environment variables; 224 // it just returns silently. So don't try. 225 (PlatformDetection.IsWindowsAndElevated && !PlatformDetection.IsNetNative); 226 227 228 string key = $"EnumerateEnvironmentVariables ({target})"; 229 string value = Path.GetRandomFileName(); 230 231 try 232 { 233 if (lookForSetValue) 234 { 235 Environment.SetEnvironmentVariable(key, value, target); 236 Assert.Equal(value, Environment.GetEnvironmentVariable(key, target)); 237 } 238 239 IDictionary results = Environment.GetEnvironmentVariables(target); 240 241 // Ensure we can walk through the results 242 IDictionaryEnumerator enumerator = results.GetEnumerator(); 243 while (enumerator.MoveNext()) 244 { 245 Assert.NotNull(enumerator.Entry); 246 } 247 248 if (lookForSetValue) 249 { 250 // Ensure that we got our flagged value out 251 Assert.Equal(value, results[key]); 252 } 253 } 254 finally 255 { 256 if (lookForSetValue) 257 { 258 Environment.SetEnvironmentVariable(key, null, target); 259 Assert.Null(Environment.GetEnvironmentVariable(key, target)); 260 } 261 } 262 } 263 SetEnvironmentVariableWithPInvoke(string name, string value)264 private static void SetEnvironmentVariableWithPInvoke(string name, string value) 265 { 266 bool success = 267 #if !Unix 268 SetEnvironmentVariable(name, value); 269 #else 270 (value != null ? setenv(name, value, 1) : unsetenv(name)) == 0; 271 #endif 272 Assert.True(success); 273 } 274 275 [DllImport("kernel32.dll", EntryPoint = "SetEnvironmentVariableW" , CharSet = CharSet.Unicode, SetLastError = true)] SetEnvironmentVariable(string lpName, string lpValue)276 private static extern bool SetEnvironmentVariable(string lpName, string lpValue); 277 278 #if Unix 279 [DllImport("libc")] setenv(string name, string value, int overwrite)280 private static extern int setenv(string name, string value, int overwrite); 281 282 [DllImport("libc")] unsetenv(string name)283 private static extern int unsetenv(string name); 284 #endif 285 } 286 } 287