diff --git a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs index a45aab12165a51..04b27885d4d385 100644 --- a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs +++ b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs @@ -18,8 +18,10 @@ public abstract class FileCleanupTestBase : IDisposable protected static bool IsProcessElevated => s_isElevated.Value; /// Initialize the test class base. This creates the associated test directory. - protected FileCleanupTestBase() + protected FileCleanupTestBase(string tempDirectory = null) { + tempDirectory ??= Path.GetTempPath(); + // Use a unique test directory per test class. The test directory lives in the user's temp directory, // and includes both the name of the test class and a random string. The test class name is included // so that it can be easily correlated if necessary, and the random string to helps avoid conflicts if @@ -31,7 +33,7 @@ protected FileCleanupTestBase() string failure = string.Empty; for (int i = 0; i <= 2; i++) { - TestDirectory = Path.Combine(Path.GetTempPath(), GetType().Name + "_" + Path.GetRandomFileName()); + TestDirectory = Path.Combine(tempDirectory, GetType().Name + "_" + Path.GetRandomFileName()); try { Directory.CreateDirectory(TestDirectory); diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs index a92612ca0b0f4f..66646d1b3bbd99 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigPaths.cs @@ -92,7 +92,28 @@ private ClientConfigPaths(string exePath, bool includeUserConfig) } } - if (!string.IsNullOrEmpty(ApplicationUri)) + string externalConfigPath = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE") as string; + if (!string.IsNullOrEmpty(externalConfigPath)) + { + if (Uri.IsWellFormedUriString(externalConfigPath, UriKind.Absolute)) + { + Uri externalConfigUri = new Uri(externalConfigPath, UriKind.Absolute); + if (externalConfigUri.IsFile) + { + ApplicationConfigUri = externalConfigUri.LocalPath; + } + } + else + { + if (!Path.IsPathRooted(externalConfigPath)) + { + externalConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, externalConfigPath); + } + + ApplicationConfigUri = Path.GetFullPath(externalConfigPath); + } + } + else if (!string.IsNullOrEmpty(ApplicationUri)) { string applicationPath = ApplicationUri; if (isSingleFile) diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj index 94670bcb997dfe..816d4ca00292ed 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj @@ -65,6 +65,7 @@ + diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs new file mode 100644 index 00000000000000..a802cccb393f5f --- /dev/null +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ConfigurationPathTests.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Configuration; +using System.IO; +using System.Runtime.CompilerServices; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.ConfigurationTests +{ + public class ConfigurationPathTests : FileCleanupTestBase + { + public ConfigurationPathTests() : base(AppDomain.CurrentDomain.BaseDirectory) // We do not want the files go to temporary directory as that will not test the relative paths correctly + { + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void CustomAppConfigIsUsedWhenSpecifiedAsRelativePath() + { + const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified"; + string expectedSettingValue = Guid.NewGuid().ToString(); + string configFilePath = Path.Combine(GetTestDirectoryName(), CreateAppConfigFileWithSetting(SettingName, expectedSettingValue)); + + RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => { + // We change directory so that if product tries to read from the current directory which usually happens to be same as BaseDirectory the test will fail + Environment.CurrentDirectory = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..")); + AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath); + Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]); + }, configFilePath, expectedSettingValue).Dispose(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void CustomAppConfigIsUsedWhenSpecifiedAsAbsolutePath() + { + const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified"; + string expectedSettingValue = Guid.NewGuid().ToString(); + string configFilePath = Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, expectedSettingValue)); + + RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => { + AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath); + Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]); + }, configFilePath, expectedSettingValue).Dispose(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void CustomAppConfigIsUsedWhenSpecifiedAsAbsoluteUri() + { + const string SettingName = "test_CustomAppConfigIsUsedWhenSpecified"; + string expectedSettingValue = Guid.NewGuid().ToString(); + string configFilePath = new Uri(Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, expectedSettingValue))).ToString(); + + RemoteExecutor.Invoke((string configFilePath, string expectedSettingValue) => { + AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath); + Assert.Equal(expectedSettingValue, ConfigurationManager.AppSettings[SettingName]); + }, configFilePath, expectedSettingValue).Dispose(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void NoErrorWhenCustomAppConfigIsSpecifiedAndItDoesNotExist() + { + RemoteExecutor.Invoke(() => + { + AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "non-existing-file.config"); + Assert.Null(ConfigurationManager.AppSettings["AnySetting"]); + }).Dispose(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void MalformedAppConfigCausesException() + { + const string SettingName = "AnySetting"; + + // Following will cause malformed config file + string configFilePath = Path.Combine(TestDirectory, CreateAppConfigFileWithSetting(SettingName, "\"")); + + RemoteExecutor.Invoke((string configFilePath) => { + AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFilePath); + Assert.Throws(() => ConfigurationManager.AppSettings[SettingName]); + }, configFilePath).Dispose(); + } + + private string GetTestDirectoryName() + { + string dir = TestDirectory; + if (dir.EndsWith("\\") || dir.EndsWith("/")) + dir = dir.Substring(0, dir.Length - 1); + + return Path.GetFileName(dir); + } + + private string CreateAppConfigFileWithSetting(string key, string rawUnquotedValue, [CallerMemberName] string memberName = null, [CallerLineNumber] int lineNumber = 0) + { + string fileName = GetTestFileName(null, memberName, lineNumber) + ".config"; + File.WriteAllText(Path.Combine(TestDirectory, fileName), + @$" + + + + +"); + return fileName; + } + } +}