diff --git a/src/Adapter/MSTest.TestAdapter/InternalAPI/InternalAPI.Unshipped.txt b/src/Adapter/MSTest.TestAdapter/InternalAPI/InternalAPI.Unshipped.txt index af599cf7c5..da16710179 100644 --- a/src/Adapter/MSTest.TestAdapter/InternalAPI/InternalAPI.Unshipped.txt +++ b/src/Adapter/MSTest.TestAdapter/InternalAPI/InternalAPI.Unshipped.txt @@ -1,4 +1,10 @@ #nullable enable +Microsoft.Testing.Extensions.RunSettingsProviderHelper Microsoft.VisualStudio.TestTools.UnitTesting.PlatformServicesConfigurationAdapter Microsoft.VisualStudio.TestTools.UnitTesting.PlatformServicesConfigurationAdapter.PlatformServicesConfigurationAdapter(Microsoft.Testing.Platform.Configurations.IConfiguration! configuration) -> void Microsoft.VisualStudio.TestTools.UnitTesting.PlatformServicesConfigurationAdapter.this[string! key].get -> string? +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.ApplyEnvironmentVariables(System.Xml.Linq.XDocument! runSettings, Microsoft.Testing.Platform.Extensions.TestHostControllers.IEnvironmentVariables! environmentVariables) -> void +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.CanReadFile(Microsoft.Testing.Platform.Helpers.IFileSystem! fileSystem, string! filePath) -> bool +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.FindInvalidTestParameter(string![]! arguments) -> string? +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.HasEnvironmentVariables(System.Xml.Linq.XDocument! runSettings) -> bool +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.TryLoadRunSettingsAsync(Microsoft.Testing.Platform.CommandLine.ICommandLineOptions! commandLineOptions, Microsoft.Testing.Platform.Helpers.IFileSystem! fileSystem, Microsoft.Testing.Platform.Helpers.IEnvironment! environment, string! runSettingsOptionName) -> System.Threading.Tasks.Task! diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj index 94c5dc9364..e1a597c420 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj @@ -111,6 +111,8 @@ + + diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsCommandLineOptionsProvider.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsCommandLineOptionsProvider.cs index bccf259cf4..e304f86b0a 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsCommandLineOptionsProvider.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsCommandLineOptionsProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #if !WINDOWS_UWP +using Microsoft.Testing.Extensions; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions; using Microsoft.Testing.Platform.Extensions.CommandLine; @@ -38,22 +39,9 @@ public override Task ValidateOptionArgumentsAsync(CommandLineO return !_fileSystem.ExistFile(filePath) ? ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, PlatformAdapterResources.RunsettingsFileDoesNotExist, filePath)) - : !CanReadFile(filePath) + : !RunSettingsProviderHelper.CanReadFile(_fileSystem, filePath) ? ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, PlatformAdapterResources.RunsettingsFileCannotBeRead, filePath)) : ValidationResult.ValidTask; } - - private bool CanReadFile(string filePath) - { - try - { - using IFileStream stream = _fileSystem.NewFileStream(filePath, FileMode.Open, FileAccess.Read); - return true; - } - catch (IOException) - { - return false; - } - } } #endif diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsEnvironmentVariableProvider.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsEnvironmentVariableProvider.cs index c1ae378e91..75b7d41a8d 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsEnvironmentVariableProvider.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettingsEnvironmentVariableProvider.cs @@ -2,12 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #if !WINDOWS_UWP +using Microsoft.Testing.Extensions; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions; using Microsoft.Testing.Platform.Extensions.TestHostControllers; using IEnvironment = Microsoft.Testing.Platform.Helpers.IEnvironment; -using IFileStream = Microsoft.Testing.Platform.Helpers.IFileStream; using IFileSystem = Microsoft.Testing.Platform.Helpers.IFileSystem; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.TestingPlatformAdapter; @@ -44,59 +44,18 @@ public MSTestRunSettingsEnvironmentVariableProvider(IExtension extension, IComma public async Task IsEnabledAsync() { - string? runSettingsFilePath = null; - string? runSettingsContent = null; + _runSettings = await RunSettingsProviderHelper.TryLoadRunSettingsAsync( + _commandLineOptions, + _fileSystem, + _environment, + MSTestRunSettingsCommandLineOptionsProvider.RunSettingsOptionName).ConfigureAwait(false); - if (_commandLineOptions.TryGetOptionArgumentList(MSTestRunSettingsCommandLineOptionsProvider.RunSettingsOptionName, out string[]? runsettings) - && runsettings.Length > 0 - && _fileSystem.ExistFile(runsettings[0])) - { - runSettingsFilePath = runsettings[0]; - } - - if (runSettingsFilePath is null) - { - runSettingsContent = _environment.GetEnvironmentVariable("TESTINGPLATFORM_EXPERIMENTAL_VSTEST_RUNSETTINGS"); - } - - if (runSettingsFilePath is null && string.IsNullOrEmpty(runSettingsContent)) - { - string? envVarFilePath = _environment.GetEnvironmentVariable("TESTINGPLATFORM_VSTESTBRIDGE_RUNSETTINGS_FILE"); - if (!string.IsNullOrEmpty(envVarFilePath) && _fileSystem.ExistFile(envVarFilePath!)) - { - runSettingsFilePath = envVarFilePath; - } - } - - if (runSettingsFilePath is not null) - { - using IFileStream fileStream = _fileSystem.NewFileStream(runSettingsFilePath, FileMode.Open, FileAccess.Read); -#if NETCOREAPP - _runSettings = await XDocument.LoadAsync(fileStream.Stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false); -#else - using StreamReader streamReader = new(fileStream.Stream); - _runSettings = XDocument.Parse(await streamReader.ReadToEndAsync().ConfigureAwait(false)); -#endif - } - else if (!string.IsNullOrEmpty(runSettingsContent)) - { - _runSettings = XDocument.Parse(runSettingsContent); - } - else - { - return false; - } - - return _runSettings.Element("RunSettings")?.Element("RunConfiguration")?.Element("EnvironmentVariables") is not null; + return _runSettings is not null && RunSettingsProviderHelper.HasEnvironmentVariables(_runSettings); } public Task UpdateAsync(IEnvironmentVariables environmentVariables) { - foreach (XElement element in _runSettings!.Element("RunSettings")!.Element("RunConfiguration")!.Element("EnvironmentVariables")!.Elements()) - { - environmentVariables.SetVariable(new(element.Name.ToString(), element.Value, true, true)); - } - + RunSettingsProviderHelper.ApplyEnvironmentVariables(_runSettings!, environmentVariables); return Task.CompletedTask; } diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestTestRunParametersCommandLineOptionsProvider.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestTestRunParametersCommandLineOptionsProvider.cs index bbff73830f..261b2e236b 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestTestRunParametersCommandLineOptionsProvider.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestTestRunParametersCommandLineOptionsProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #if !WINDOWS_UWP +using Microsoft.Testing.Extensions; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions; using Microsoft.Testing.Platform.Extensions.CommandLine; @@ -26,7 +27,7 @@ public MSTestTestRunParametersCommandLineOptionsProvider(IExtension extension) public override Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments) { - string? invalidArgument = arguments.FirstOrDefault(argument => !argument.Contains('=')); + string? invalidArgument = RunSettingsProviderHelper.FindInvalidTestParameter(arguments); return invalidArgument is not null ? ValidationResult.InvalidTask(string.Format(CultureInfo.CurrentCulture, PlatformAdapterResources.TestRunParameterOptionArgumentIsNotParameter, invalidArgument)) : ValidationResult.ValidTask; diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs index 00dbcfee1d..9dfdba30ff 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/RunSettingsCommandLineOptionsProvider.cs @@ -41,7 +41,7 @@ public override Task ValidateOptionArgumentsAsync(CommandLineO } // Even if the file exists, we want to validate we can open/read it. - if (!CanReadFile(filePath)) + if (!RunSettingsProviderHelper.CanReadFile(_fileSystem, filePath)) { return ValidationResult.InvalidTask(string.Format(CultureInfo.InvariantCulture, ExtensionResources.RunsettingsFileCannotBeRead, filePath)); } @@ -49,17 +49,4 @@ public override Task ValidateOptionArgumentsAsync(CommandLineO // No problem found return ValidationResult.ValidTask; } - - private bool CanReadFile(string filePath) - { - try - { - using IFileStream stream = _fileSystem.NewFileStream(filePath, FileMode.Open, FileAccess.Read); - return true; - } - catch (IOException) - { - return false; - } - } } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs index 034796db44..7aa2fdfb05 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/CommandLine/TestRunParametersCommandLineOptionsProvider.cs @@ -24,14 +24,9 @@ public TestRunParametersCommandLineOptionsProvider(IExtension extension) /// public override Task ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments) { - foreach (string argument in arguments) - { - if (!argument.Contains('=')) - { - return ValidationResult.InvalidTask(string.Format(CultureInfo.CurrentCulture, ExtensionResources.TestRunParameterOptionArgumentIsNotParameter, argument)); - } - } - - return ValidationResult.ValidTask; + string? invalidArgument = RunSettingsProviderHelper.FindInvalidTestParameter(arguments); + return invalidArgument is not null + ? ValidationResult.InvalidTask(string.Format(CultureInfo.CurrentCulture, ExtensionResources.TestRunParameterOptionArgumentIsNotParameter, invalidArgument)) + : ValidationResult.ValidTask; } } diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/InternalAPI.Unshipped.txt b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/InternalAPI.Unshipped.txt index 7dc5c58110..1981f188c1 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/InternalAPI.Unshipped.txt +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/InternalAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Microsoft.Testing.Extensions.RunSettingsProviderHelper +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.ApplyEnvironmentVariables(System.Xml.Linq.XDocument! runSettings, Microsoft.Testing.Platform.Extensions.TestHostControllers.IEnvironmentVariables! environmentVariables) -> void +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.CanReadFile(Microsoft.Testing.Platform.Helpers.IFileSystem! fileSystem, string! filePath) -> bool +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.FindInvalidTestParameter(string![]! arguments) -> string? +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.HasEnvironmentVariables(System.Xml.Linq.XDocument! runSettings) -> bool +static Microsoft.Testing.Extensions.RunSettingsProviderHelper.TryLoadRunSettingsAsync(Microsoft.Testing.Platform.CommandLine.ICommandLineOptions! commandLineOptions, Microsoft.Testing.Platform.Helpers.IFileSystem! fileSystem, Microsoft.Testing.Platform.Helpers.IEnvironment! environment, string! runSettingsOptionName) -> System.Threading.Tasks.Task! diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj index b4a2dd8862..965c85bcc5 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj @@ -9,6 +9,8 @@ + + diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs index 31cacda715..79420a63fe 100644 --- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/TestHostControllers/RunSettingsEnvironmentVariableProvider.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Extensions.VSTestBridge.CommandLine; -using Microsoft.Testing.Platform; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions; using Microsoft.Testing.Platform.Extensions.TestHostControllers; @@ -36,66 +35,18 @@ public RunSettingsEnvironmentVariableProvider(IExtension extension, ICommandLine public async Task IsEnabledAsync() { - string? runSettingsFilePath = null; - string? runSettingsContent = null; + _runSettings = await RunSettingsProviderHelper.TryLoadRunSettingsAsync( + _commandLineOptions, + _fileSystem, + _environment, + RunSettingsCommandLineOptionsProvider.RunSettingsOptionName).ConfigureAwait(false); - // Try to get runsettings from command line - if (_commandLineOptions.TryGetOptionArgumentList(RunSettingsCommandLineOptionsProvider.RunSettingsOptionName, out string[]? runsettings) - && runsettings.Length > 0) - { - if (_fileSystem.ExistFile(runsettings[0])) - { - runSettingsFilePath = runsettings[0]; - } - } - - // If not from command line, try environment variable with content - if (runSettingsFilePath is null) - { - runSettingsContent = _environment.GetEnvironmentVariable("TESTINGPLATFORM_EXPERIMENTAL_VSTEST_RUNSETTINGS"); - } - - // If not from content env var, try environment variable with file path - if (runSettingsFilePath is null && RoslynString.IsNullOrEmpty(runSettingsContent)) - { - string? envVarFilePath = _environment.GetEnvironmentVariable("TESTINGPLATFORM_VSTESTBRIDGE_RUNSETTINGS_FILE"); - if (!RoslynString.IsNullOrEmpty(envVarFilePath) && _fileSystem.ExistFile(envVarFilePath)) - { - runSettingsFilePath = envVarFilePath; - } - } - - // If we have a file path, read from file - if (runSettingsFilePath is not null) - { - using IFileStream fileStream = _fileSystem.NewFileStream(runSettingsFilePath, FileMode.Open, FileAccess.Read); -#if NETCOREAPP - _runSettings = await XDocument.LoadAsync(fileStream.Stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false); -#else - using StreamReader streamReader = new(fileStream.Stream); - _runSettings = XDocument.Parse(await streamReader.ReadToEndAsync().ConfigureAwait(false)); -#endif - } - else if (!RoslynString.IsNullOrEmpty(runSettingsContent)) - { - // If we have content, parse it directly - _runSettings = XDocument.Parse(runSettingsContent); - } - else - { - return false; - } - - return _runSettings.Element("RunSettings")?.Element("RunConfiguration")?.Element("EnvironmentVariables") is not null; + return _runSettings is not null && RunSettingsProviderHelper.HasEnvironmentVariables(_runSettings); } public Task UpdateAsync(IEnvironmentVariables environmentVariables) { - foreach (XElement element in _runSettings!.Element("RunSettings")!.Element("RunConfiguration")!.Element("EnvironmentVariables")!.Elements()) - { - environmentVariables.SetVariable(new(element.Name.ToString(), element.Value, true, true)); - } - + RunSettingsProviderHelper.ApplyEnvironmentVariables(_runSettings!, environmentVariables); return Task.CompletedTask; } diff --git a/src/Platform/SharedExtensionHelpers/RunSettingsProviderHelper.cs b/src/Platform/SharedExtensionHelpers/RunSettingsProviderHelper.cs new file mode 100644 index 0000000000..ee67189ca8 --- /dev/null +++ b/src/Platform/SharedExtensionHelpers/RunSettingsProviderHelper.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if !WINDOWS_UWP +using Microsoft.Testing.Platform.CommandLine; +using Microsoft.Testing.Platform.Extensions.TestHostControllers; +using Microsoft.Testing.Platform.Helpers; + +namespace Microsoft.Testing.Extensions; + +/// +/// Resource-independent logic shared by the VSTest bridge and the MSTest adapter's native Microsoft.Testing.Platform +/// integration for the --settings (.runsettings) and --test-parameter (TestRunParameters) providers. +/// The per-package concerns (resource strings, option registration, UWP guards) stay in the provider classes; only +/// the shared logic lives here. +/// +[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "The shared helper is linked into projects that are allowed to use MTP APIs")] +internal static class RunSettingsProviderHelper +{ + /// + /// Attempts to open the file for reading to validate it can be read (independently of its existence check). + /// + internal static bool CanReadFile(IFileSystem fileSystem, string filePath) + { + try + { + using IFileStream stream = fileSystem.NewFileStream(filePath, FileMode.Open, FileAccess.Read); + return true; + } + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) + { + return false; + } + } + + /// + /// Resolves and parses the .runsettings from (in order) the command-line option, the + /// TESTINGPLATFORM_EXPERIMENTAL_VSTEST_RUNSETTINGS content environment variable, or the + /// TESTINGPLATFORM_VSTESTBRIDGE_RUNSETTINGS_FILE file-path environment variable. Returns the parsed + /// , or when no runsettings could be resolved. + /// + internal static async Task TryLoadRunSettingsAsync( + ICommandLineOptions commandLineOptions, + IFileSystem fileSystem, + IEnvironment environment, + string runSettingsOptionName) + { + string? runSettingsFilePath = null; + string? runSettingsContent = null; + + // Try to get runsettings from command line. + if (commandLineOptions.TryGetOptionArgumentList(runSettingsOptionName, out string[]? runsettings) + && runsettings.Length > 0 + && fileSystem.ExistFile(runsettings[0])) + { + runSettingsFilePath = runsettings[0]; + } + + // If not from command line, try environment variable with content. + if (runSettingsFilePath is null) + { + runSettingsContent = environment.GetEnvironmentVariable("TESTINGPLATFORM_EXPERIMENTAL_VSTEST_RUNSETTINGS"); + } + + // If not from content env var, try environment variable with file path. + if (runSettingsFilePath is null && string.IsNullOrEmpty(runSettingsContent)) + { + string? envVarFilePath = environment.GetEnvironmentVariable("TESTINGPLATFORM_VSTESTBRIDGE_RUNSETTINGS_FILE"); + if (!string.IsNullOrEmpty(envVarFilePath) && fileSystem.ExistFile(envVarFilePath!)) + { + runSettingsFilePath = envVarFilePath; + } + } + + // If we have a file path, read from file. + if (runSettingsFilePath is not null) + { + using IFileStream fileStream = fileSystem.NewFileStream(runSettingsFilePath, FileMode.Open, FileAccess.Read); +#if NETCOREAPP + return await XDocument.LoadAsync(fileStream.Stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false); +#else + using StreamReader streamReader = new(fileStream.Stream); + return XDocument.Parse(await streamReader.ReadToEndAsync().ConfigureAwait(false)); +#endif + } + + // If we have content, parse it directly. + return !string.IsNullOrEmpty(runSettingsContent) + ? XDocument.Parse(runSettingsContent!) + : null; + } + + /// + /// Returns a value indicating whether the runsettings declares a <EnvironmentVariables> section. + /// + internal static bool HasEnvironmentVariables(XDocument runSettings) + => runSettings.Element("RunSettings")?.Element("RunConfiguration")?.Element("EnvironmentVariables") is not null; + + /// + /// Applies every <EnvironmentVariables> entry from the runsettings to the test host. + /// + internal static void ApplyEnvironmentVariables(XDocument runSettings, IEnvironmentVariables environmentVariables) + { + foreach (XElement element in runSettings.Element("RunSettings")!.Element("RunConfiguration")!.Element("EnvironmentVariables")!.Elements()) + { + environmentVariables.SetVariable(new(element.Name.ToString(), element.Value, true, true)); + } + } + + /// + /// Returns the first argument that is not a name=value pair (i.e. does not contain '='), or + /// when all arguments are valid. + /// + internal static string? FindInvalidTestParameter(string[] arguments) + => arguments.FirstOrDefault(argument => !argument.Contains('=')); +} +#endif diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs index 8788c56af4..052ee79a02 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/CommandLine/RunSettingsCommandLineOptionsProviderTests.cs @@ -53,6 +53,26 @@ public async Task RunSettingsOption_WhenFileCannotBeOpen_IsNotValid() Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, ExtensionResources.RunsettingsFileCannotBeRead, filePath), result.ErrorMessage); } + [TestMethod] + public async Task RunSettingsOption_WhenFileCannotBeReadDueToPermissions_IsNotValid() + { + // Arrange + const string filePath = "file"; + var fileSystem = new Mock(MockBehavior.Strict); + fileSystem.Setup(fs => fs.ExistFile(filePath)).Returns(true); + fileSystem.Setup(fs => fs.NewFileStream(filePath, FileMode.Open, FileAccess.Read)).Throws(new UnauthorizedAccessException()); + + var provider = new RunSettingsCommandLineOptionsProvider(new TestExtension(), fileSystem.Object); + CommandLineOption option = provider.GetCommandLineOptions().Single(); + + // Act + ValidationResult result = await provider.ValidateOptionArgumentsAsync(option, [filePath]); + + // Assert + Assert.IsFalse(result.IsValid); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, ExtensionResources.RunsettingsFileCannotBeRead, filePath), result.ErrorMessage); + } + [TestMethod] public async Task RunSettingsOption_WhenFileExistsAndCanBeOpen_IsValid() {