diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs index 36f3a940d0..01c98c6b0f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs +++ b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs @@ -274,9 +274,38 @@ public TProperty[] OfType() } // We don't want to allocate an array if we know that we're looking for a TestNodeStateProperty - return typeof(TestNodeStateProperty).IsAssignableFrom(typeof(TProperty)) + if (typeof(TestNodeStateProperty).IsAssignableFrom(typeof(TProperty)) || _property is null) + { + return []; + } + + // Direct linked-list walk: avoids allocating a yield-iterator state machine + // (the original code called _property.OfType() which uses yield return). + TProperty? first = default; + bool foundAny = false; + List? overflow = null; + Property? current = _property; + while (current is not null) + { + if (current.Current is TProperty match) + { + if (!foundAny) + { + first = match; + foundAny = true; + } + else + { + (overflow ??= [first!]).Add(match); + } + } + + current = current.Next; + } + + return !foundAny ? [] - : _property is null ? [] : [.. _property.OfType()]; + : overflow is not null ? [.. overflow] : [first!]; } /// diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs index 9f9a42a4de..8c6aed9105 100644 --- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs +++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Messages/PropertyBagTests.cs @@ -121,6 +121,33 @@ public void OfType_Should_Return_CorrectObject() Assert.AreEqual(PassedTestNodeStateProperty.CachedInstance, property.OfType().Single()); Assert.HasCount(2, property.OfType()); + + // No DummyProperty2 in the bag — exercises the "no match found" path in the while-loop + Assert.IsEmpty(property.OfType()); + } + + [TestMethod] + public void OfType_WithSingleMatch_ReturnsSingleItemArray() + { + PropertyBag property = new(); + DummyProperty singleProperty = new(); + property.Add(singleProperty); + property.Add(PassedTestNodeStateProperty.CachedInstance); + + DummyProperty[] result = property.OfType(); + + Assert.HasCount(1, result); + Assert.AreSame(singleProperty, result[0]); + } + + [TestMethod] + public void OfType_WithOnlyTestNodeStateProperty_ReturnsEmpty() + { + PropertyBag property = new(); + property.Add(PassedTestNodeStateProperty.CachedInstance); + + // _property is null; _testNodeStateProperty is set — exercises the new early-return path + Assert.IsEmpty(property.OfType()); } [TestMethod]