Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
Expand All @@ -18,30 +17,35 @@ internal static class RunSettingsUtilities
IgnoreWhitespace = true,
};

// The runsettings node names, historically taken from the VSTest object model's Constants type.
internal const string RunConfigurationSettingsName = "RunConfiguration";

internal const string TestRunParametersName = "TestRunParameters";

/// <summary>
/// Gets the set of user defined test run parameters from settings xml as key value pairs.
/// </summary>
/// <param name="settingsXml">The runsettings xml.</param>
/// <returns>The test run parameters.</returns>
/// <remarks>If there is no test run parameters section defined in the settingsxml a blank dictionary is returned.</remarks>
internal static Dictionary<string, object>? GetTestRunParameters(string? settingsXml)
=> GetNodeValue(settingsXml, Constants.TestRunParametersName, TestRunParameters.FromXml);
=> GetNodeValue(settingsXml, TestRunParametersName, TestRunParameters.FromXml);

/// <summary>
/// Throws if the node has an attribute.
/// </summary>
/// <param name="reader"> The reader. </param>
/// <exception cref="SettingsException"> Thrown if the node has an attribute. </exception>
/// <exception cref="InvalidRunSettingsException"> Thrown if the node has an attribute. </exception>
internal static void ThrowOnHasAttributes(XmlReader reader)
{
if (reader.HasAttributes)
{
reader.MoveToNextAttribute();
throw new SettingsException(
throw new InvalidRunSettingsException(
string.Format(
CultureInfo.CurrentCulture,
Resource.InvalidSettingsXmlAttribute,
TestPlatform.ObjectModel.Constants.RunConfigurationSettingsName,
RunConfigurationSettingsName,
reader.Name));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;

Expand Down Expand Up @@ -47,11 +47,11 @@ internal static Dictionary<string, object> FromXml(XmlReader reader)

break;
default:
throw new SettingsException(
throw new InvalidRunSettingsException(
string.Format(
CultureInfo.CurrentCulture,
Resource.InvalidSettingsXmlElement,
Constants.TestRunParametersName,
RunSettingsUtilities.TestRunParametersName,
reader.Name));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;

/// <summary>
/// Minimal, platform-agnostic <see cref="XmlReader"/> navigation helpers for reading runsettings XML.
/// These replace the equivalent helpers from the VSTest object model so the platform services layer does not
/// depend on it; the navigation semantics are unchanged.
/// </summary>
internal static class XmlReaderUtilities
{
private const string RunSettingsRootNodeName = "RunSettings";

/// <summary>
/// Advances the reader to the root element and verifies it is the <c>&lt;RunSettings&gt;</c> node.
/// </summary>
/// <param name="reader">The reader positioned before the root element.</param>
/// <exception cref="InvalidRunSettingsException">Thrown when the root element is not <c>&lt;RunSettings&gt;</c>.</exception>
internal static void ReadToRootNode(XmlReader reader)
{
reader.ReadToNextElement();

// Verify that it is a "RunSettings" node.
if (reader.Name != RunSettingsRootNodeName)
{
throw new InvalidRunSettingsException($"Could not find '{RunSettingsRootNodeName}' node in the runsettings XML. Found '<{reader.Name}>' instead.");
}
}

/// <summary>
/// Reads until the next element node (or end of document).
/// </summary>
/// <param name="reader">The reader.</param>
internal static void ReadToNextElement(this XmlReader reader)
{
while (!reader.EOF && reader.Read() && reader.NodeType != XmlNodeType.Element)
{
}
}

/// <summary>
/// Skips the current subtree and positions the reader on the next element node.
/// </summary>
/// <param name="reader">The reader.</param>
internal static void SkipToNextElement(this XmlReader reader)
{
reader.Skip();

if (reader.NodeType != XmlNodeType.Element)
{
reader.ReadToNextElement();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;

using DebuggerLaunchMode = Microsoft.VisualStudio.TestTools.UnitTesting.DebuggerLaunchMode;
using MessageLevel = Microsoft.VisualStudio.TestTools.UnitTesting.MessageLevel;
Expand Down Expand Up @@ -45,7 +45,7 @@ private static bool RunSettingsFileHasMSTestSettings(string? runSettingsXml)
}

using var stringReader = new StringReader(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);

XmlReaderUtilities.ReadToRootNode(reader);
reader.ReadToNextElement();
Expand All @@ -69,7 +69,7 @@ private static bool RunSettingsFileHasMSTestSettings(string? runSettingsXml)
}

using var stringReader = new StringReader(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);

XmlReaderUtilities.ReadToRootNode(reader);
reader.ReadToNextElement();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;

/// <summary>
/// Thrown when the runsettings XML is structurally invalid (for example a bad attribute, an unexpected element,
/// or a wrong root node). This is the platform-agnostic replacement for the settings exception the platform
/// services layer historically surfaced from the VSTest object model. It is intentionally distinct from
/// <see cref="AdapterSettingsException"/>: <see cref="AdapterSettingsException"/> is caught by the discovery
/// initialization path (reported and treated as "no tests"), whereas a structural runsettings error propagates
/// to the host, preserving the original behavior.
/// </summary>
internal sealed class InvalidRunSettingsException : Exception
{
internal InvalidRunSettingsException(string? message)
: base(message)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#if !WINDOWS_UWP

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
Expand Down Expand Up @@ -206,7 +206,7 @@ public static bool IsAppDomainCreationDisabled(string? settingsXml)
if (!StringEx.IsNullOrEmpty(settingsXml))
{
StringReader stringReader = new(settingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
var xmlDoc = new XmlDocument() { XmlResolver = null };
xmlDoc.Load(reader);

Expand Down Expand Up @@ -384,7 +384,7 @@ private void ReadAssemblyResolutionPath(XmlReader reader)
else
{
string message = string.Format(CultureInfo.CurrentCulture, Resource.InvalidSettingsXmlElement, reader.Name, "AssemblyResolution");
throw new SettingsException(message);
throw new InvalidRunSettingsException(message);
}

// Move to the next element under tag AssemblyResolution
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if NETFRAMEWORK

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
Expand All @@ -18,9 +17,22 @@ internal static class AppDomainUtilities
{
private const string ObjectModelVersionBuiltAgainst = "11.0.0.0";

private const string ObjectModelAssemblyName = "Microsoft.VisualStudio.TestPlatform.ObjectModel";

private static readonly Version DefaultVersion = new();
private static readonly Version Version45 = new("4.5");

/// <summary>
/// Resolves the loaded VSTest object-model assembly by simple name, so this AppDomain-wiring code does not
/// need a compile-time reference to it. By the time these methods run (test source host setup during
/// discovery/execution) the adapter has already loaded the object model into the current (parent) domain,
/// so its identity — including any binding redirect in effect — matches what a direct type reference resolved to.
/// </summary>
/// <returns>The object-model assembly.</returns>
private static Assembly GetObjectModelAssembly()
=> AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => string.Equals(a.GetName().Name, ObjectModelAssemblyName, StringComparison.Ordinal))
?? Assembly.Load(ObjectModelAssemblyName);

/// <summary>
/// Gets or sets the Xml Utilities instance.
/// </summary>
Expand Down Expand Up @@ -90,7 +102,7 @@ internal static string GetTargetFrameworkVersionString(string testSourcePath)

var resolutionPaths = new List<string>
{
Path.GetDirectoryName(typeof(TestCase).Assembly.Location),
Path.GetDirectoryName(GetObjectModelAssembly().Location),
Path.GetDirectoryName(testSourcePath),
};

Expand Down Expand Up @@ -157,10 +169,10 @@ internal static void SetConfigurationFile(AppDomainSetup appDomainSetup, string?
try
{
// Add redirection of the built 11.0 Object Model assembly to the current version if that is not 11.0
string currentVersionOfObjectModel = typeof(TestCase).Assembly.GetName().Version.ToString();
string currentVersionOfObjectModel = GetObjectModelAssembly().GetName().Version.ToString();
if (!string.Equals(currentVersionOfObjectModel, ObjectModelVersionBuiltAgainst, StringComparison.Ordinal))
{
AssemblyName assemblyName = typeof(TestCase).Assembly.GetName();
AssemblyName assemblyName = GetObjectModelAssembly().GetName();
byte[] configurationBytes =
XmlUtilities.AddAssemblyRedirection(
testSourceConfigFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using AwesomeAssertions;

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;

using TestFramework.ForTestingMSTest;

Expand Down Expand Up @@ -131,7 +131,7 @@ public void GetTestRunParametersThrowsWhenTRPNodeHasAttributes()
</RunSettings>
""";

new Action(() => RunSettingsUtilities.GetTestRunParameters(settingsXml)).Should().Throw<SettingsException>();
new Action(() => RunSettingsUtilities.GetTestRunParameters(settingsXml)).Should().Throw<InvalidRunSettingsException>();
}

public void GetTestRunParametersThrowsWhenTRPNodeHasNonParameterTypeChildNodes()
Expand All @@ -152,7 +152,7 @@ public void GetTestRunParametersThrowsWhenTRPNodeHasNonParameterTypeChildNodes()
</RunSettings>
""";

new Action(() => RunSettingsUtilities.GetTestRunParameters(settingsXml)).Should().Throw<SettingsException>();
new Action(() => RunSettingsUtilities.GetTestRunParameters(settingsXml)).Should().Throw<InvalidRunSettingsException>();
}

public void GetTestRunParametersIgnoresMalformedKeyValues()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

using AwesomeAssertions;

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;

using Moq;

Expand Down Expand Up @@ -202,7 +202,7 @@ public void ToSettingsShouldNotThrowExceptionWhenRunSettingsXmlUnderTagMSTestV2I
""";

StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();

MSTestAdapterSettings.ToSettings(reader);
Expand All @@ -222,12 +222,12 @@ public void ToSettingsShouldThrowExceptionWhenRunSettingsXmlIsWrong()
""";

StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();

void ShouldThrowException() => MSTestAdapterSettings.ToSettings(reader);

new Action(ShouldThrowException).Should().Throw<SettingsException>();
new Action(ShouldThrowException).Should().Throw<InvalidRunSettingsException>();
}

#endregion
Expand All @@ -242,7 +242,7 @@ public void DeploymentEnabledIsByDefaultTrueWhenNotSpecified()
</MSTestV2>
""";
StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();
var adapterSettings = MSTestAdapterSettings.ToSettings(reader);
adapterSettings.DeploymentEnabled.Should().BeTrue();
Expand All @@ -257,7 +257,7 @@ public void DeploymentEnabledShouldBeConsumedFromRunSettingsWhenSpecified()
</MSTestV2>
""";
StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();
var adapterSettings = MSTestAdapterSettings.ToSettings(reader);
adapterSettings.DeploymentEnabled.Should().BeFalse();
Expand All @@ -275,7 +275,7 @@ public void DeployTestSourceDependenciesIsEnabledByDefault()
</MSTestV2>
""";
StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();
var adapterSettings = MSTestAdapterSettings.ToSettings(reader);
adapterSettings.DeployTestSourceDependencies.Should().BeTrue();
Expand All @@ -290,7 +290,7 @@ public void DeployTestSourceDependenciesWhenFalse()
</MSTestV2>
""";
StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();
var adapterSettings = MSTestAdapterSettings.ToSettings(reader);
adapterSettings.DeployTestSourceDependencies.Should().BeFalse();
Expand All @@ -305,7 +305,7 @@ public void DeployTestSourceDependenciesWhenTrue()
</MSTestV2>
""";
StringReader stringReader = new(runSettingsXml);
var reader = XmlReader.Create(stringReader, XmlRunSettingsUtilities.ReaderSettings);
var reader = XmlReader.Create(stringReader, RunSettingsUtilities.ReaderSettings);
reader.Read();
var adapterSettings = MSTestAdapterSettings.ToSettings(reader);
adapterSettings.DeployTestSourceDependencies.Should().BeTrue();
Expand Down
Loading