diff --git a/src/Microsoft.TestPlatform.CoreUtilities/FeatureFlag/FeatureFlag.cs b/src/Microsoft.TestPlatform.CoreUtilities/FeatureFlag/FeatureFlag.cs
index 76f8ec1546..9a5506a87b 100644
--- a/src/Microsoft.TestPlatform.CoreUtilities/FeatureFlag/FeatureFlag.cs
+++ b/src/Microsoft.TestPlatform.CoreUtilities/FeatureFlag/FeatureFlag.cs
@@ -72,6 +72,8 @@ private FeatureFlag() { }
// Disable not sharing .NET Framework testhosts. Which will return behavior to sharing testhosts when they are running .NET Framework dlls, and are not disabling appdomains or running in parallel.
public const string VSTEST_DISABLE_SHARING_NETFRAMEWORK_TESTHOST = nameof(VSTEST_DISABLE_SHARING_NETFRAMEWORK_TESTHOST);
+ // Disable outputting Traits into TRX file in the Properties node.
+ public const string VSTEST_DISABLE_TRX_WRITE_PROPERTIES = nameof(VSTEST_DISABLE_TRX_WRITE_PROPERTIES);
[Obsolete("Only use this in tests.")]
internal static void Reset()
diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.CoreUtilities/Properties/AssemblyInfo.cs
index 7c61240ca3..69fa32de84 100644
--- a/src/Microsoft.TestPlatform.CoreUtilities/Properties/AssemblyInfo.cs
+++ b/src/Microsoft.TestPlatform.CoreUtilities/Properties/AssemblyInfo.cs
@@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.TestHostRuntimeProvider, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("vstest.console, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("vstest.console.arm64, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.CoreUtilities.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj
index cbe38fd2ab..a19675874c 100644
--- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj
@@ -32,7 +32,6 @@
-
@@ -49,11 +48,6 @@
-
- True
- True
- NullableHelpers.tt
-
True
True
@@ -81,13 +75,6 @@
-
-
- TextTemplatingFileGenerator
- NullableHelpers.cs
-
-
-
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/Property.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/Property.cs
new file mode 100644
index 0000000000..6061d8f78c
--- /dev/null
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/Property.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+using Microsoft.TestPlatform.Extensions.TrxLogger.XML;
+using Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger;
+
+namespace Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
+
+///
+/// Stores a string which categorizes the Test
+///
+internal sealed class Property : IXmlTestStore
+{
+ [StoreXmlSimpleField(Location = "@Key", DefaultValue = "")]
+ private readonly string _key = string.Empty;
+ [StoreXmlSimpleField(Location = "@Value", DefaultValue = "")]
+ private readonly string _value = string.Empty;
+
+ ///
+ /// Create a new item with the property set
+ ///
+ public Property(string key, string value)
+ {
+ // Treat null as empty.
+
+ _key = StripIllegalChars(key);
+ _value = StripIllegalChars(value);
+ }
+
+ ///
+ /// Gets the property for this Trait
+ ///
+ public string Trait
+ {
+ get
+ {
+ return _key;
+ }
+ }
+
+ private static string StripIllegalChars(string property)
+ {
+ string ret = property.Trim();
+ ret = ret.Replace("&", string.Empty);
+ ret = ret.Replace("|", string.Empty);
+ ret = ret.Replace("!", string.Empty);
+ ret = ret.Replace(",", string.Empty);
+ return ret;
+ }
+
+ ///
+ /// Compare the values of the items
+ ///
+ /// Value being compared to.
+ /// True if the values are the same and false otherwise.
+ public override bool Equals(object? other)
+ {
+ if (other is not Property otherItem)
+ {
+ return false;
+ }
+
+ TPDebug.Assert(_key != null, "property is null");
+ return string.Equals(_key, otherItem._key, StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Convert the property name to a hashcode
+ ///
+ /// Hashcode of the property.
+ public override int GetHashCode()
+ {
+ TPDebug.Assert(_key != null, "property is null");
+ return _key.ToUpperInvariant().GetHashCode();
+ }
+
+ ///
+ /// Convert the property name to a string
+ ///
+ /// The property.
+ public override string ToString()
+ {
+ TPDebug.Assert(_key != null, "property is null");
+ return _key;
+ }
+
+ ///
+ /// Saves the class under the XmlElement.
+ ///
+ /// XmlElement element
+ /// XmlTestStoreParameters parameters
+ public void Save(System.Xml.XmlElement element, XmlTestStoreParameters? parameters)
+ {
+ new XmlPersistence().SaveSingleFields(element, this, parameters);
+ }
+}
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/PropertyCollection.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/PropertyCollection.cs
new file mode 100644
index 0000000000..037b086d00
--- /dev/null
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/PropertyCollection.cs
@@ -0,0 +1,135 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+using Microsoft.TestPlatform.Extensions.TrxLogger.Utility;
+using Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger;
+
+namespace Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
+
+///
+/// A collection of strings which categorize the test.
+///
+internal sealed class PropertyCollection : EqtBaseCollection
+{
+ ///
+ /// Creates an empty PropertyCollection.
+ ///
+ public PropertyCollection()
+ {
+ }
+
+ ///
+ /// Adds the property.
+ ///
+ /// Key to be added.
+ /// Value to be added.
+ public void Add(string key, string value)
+ {
+ Add(new Property(key, value));
+ }
+
+ ///
+ /// Adds the property.
+ ///
+ /// Property to be added.
+ public override void Add(Property item)
+ {
+ EqtAssert.ParameterNotNull(item, nameof(item));
+
+ // Don't add empty items.
+ if (!item.Trait.IsNullOrEmpty())
+ {
+ base.Add(item);
+ }
+ }
+
+ ///
+ /// Convert the PropertyCollection to a string.
+ /// each item is surrounded by a comma (,)
+ ///
+ ///
+ public override string ToString()
+ {
+ StringBuilder returnString = new();
+ if (Count > 0)
+ {
+ returnString.Append(',');
+ foreach (Property item in this)
+ {
+ returnString.Append(item.Trait);
+ returnString.Append(',');
+ }
+ }
+
+ return returnString.ToString();
+ }
+
+ ///
+ /// Convert the PropertyCollection to an array of strings.
+ ///
+ /// Array of strings containing the test categories.
+ public string[] ToArray()
+ {
+ string[] result = new string[Count];
+
+ int i = 0;
+ foreach (Property item in this)
+ {
+ result[i++] = item.Trait;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Compare the collection items
+ ///
+ /// other collection
+ /// true if the collections contain the same items
+ public override bool Equals(object? obj)
+ {
+ bool result = false;
+
+ if (obj is not PropertyCollection other)
+ {
+ // Other object is not a TraitItemCollection.
+ result = false;
+ }
+ else if (ReferenceEquals(this, other))
+ {
+ // The other object is the same object as this one.
+ result = true;
+ }
+ else if (Count != other.Count)
+ {
+ // The count of categories in the other object does not
+ // match this one, so they are not equal.
+ result = false;
+ }
+ else
+ {
+ // Check each item and return on the first mismatch.
+ foreach (Property item in this)
+ {
+ if (!other.Contains(item))
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Return the hash code of this collection
+ ///
+ /// The hashcode.
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+}
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs
index 32c9c69cf2..6bd68d9d79 100644
--- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs
@@ -32,6 +32,7 @@ internal abstract class TestElement : ITestElement, IXmlTestStore
protected TestExecId _executionId;
protected TestExecId _parentExecutionId;
protected TestCategoryItemCollection _testCategories;
+ protected PropertyCollection _properties;
protected WorkItemCollection _workItems;
protected TestListCategoryId _catId;
@@ -46,6 +47,7 @@ public TestElement(Guid id, string name, string adapter)
_executionId = TestExecId.Empty;
_parentExecutionId = TestExecId.Empty;
_testCategories = new TestCategoryItemCollection();
+ _properties = new PropertyCollection();
_workItems = new WorkItemCollection();
_isRunnable = true;
_catId = TestListCategoryId.Uncategorized;
@@ -185,6 +187,21 @@ public WorkItemCollection WorkItems
}
}
+
+ ///
+ /// Gets or sets the test traits.
+ ///
+ public PropertyCollection Traits
+ {
+ get { return _properties; }
+
+ set
+ {
+ EqtAssert.ParameterNotNull(value, "value");
+ _properties = value;
+ }
+ }
+
///
/// Gets the adapter name.
///
@@ -245,6 +262,7 @@ public virtual void Save(System.Xml.XmlElement element, XmlTestStoreParameters?
h.SaveSimpleField(element, "@priority", _priority, DefaultPriority);
h.SaveSimpleField(element, "Owners/Owner/@name", _owner, string.Empty);
h.SaveObject(_testCategories, element, "TestCategory", parameters);
+ h.SaveObject(_properties, element, "Properties", parameters);
if (_executionId != null)
h.SaveGuid(element, "Execution/@id", _executionId.Id);
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs
index 5967dbb202..37ea65ac8e 100644
--- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs
@@ -14,6 +14,7 @@
using Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
using TrxLoggerResources = Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.Resources.TrxResource;
using TrxObjectModel = Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
@@ -76,6 +77,14 @@ public static ITestElement ToTestElement(
testElement.WorkItems.Add(workItem);
}
+ if (!FeatureFlag.Instance.IsSet(nameof(FeatureFlag.VSTEST_DISABLE_TRX_WRITE_PROPERTIES)))
+ {
+ foreach (var trait in rockSteadyTestCase.Traits.Where(t => t.Name is not "Owner" and not "Priority"))
+ {
+ testElement.Traits.Add(new Property(trait.Name, trait.Value));
+ }
+ }
+
return testElement;
}