From e2f54305790c5d0504a024dcd1eaff7bbb4cd016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Sun, 5 Jul 2026 21:36:08 +0200 Subject: [PATCH] perf: skip intermediate Dictionary alloc in CloneForDataDrivenIteration The constructor's null/null branch already copies the supplied properties into a fresh Dictionary via the [with(properties)] spread, so the intermediate snapshot Dictionary was redundant. Pass _properties directly, saving one heap allocation and one O(n) copy per data-driven test iteration while preserving all isolation invariants. Fixes #9634 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Services/TestContextImplementation.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs index 5efc98a041..c3bd509f26 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs @@ -524,16 +524,15 @@ private SynchronizedStringBuilder GetTestContextMessagesStringBuilder() /// A fresh context suitable for one folded data-driven iteration. internal TestContextImplementation CloneForDataDrivenIteration() { - // Take a shallow snapshot of the current property bag so that the clone starts with - // the same properties (including TestNameLabel / FullyQualifiedTestClassNameLabel and - // anything merged from AssemblyInitialize / ClassInitialize) but is otherwise isolated. - // Per-iteration mutations to the clone's property bag won't leak back to this instance - // nor to subsequent iterations. - var snapshot = new Dictionary(_properties); - - // Pass testMethod: null and testClassFullName: null because the relevant labels are - // already in the snapshot. The constructor will copy the snapshot as-is. - var clone = new TestContextImplementation(testMethod: null, testClassFullName: null, snapshot, _messageLogger, _testRunCancellationToken); + // Pass _properties directly and testMethod: null / testClassFullName: null because the + // relevant labels (including TestNameLabel / FullyQualifiedTestClassNameLabel and anything + // merged from AssemblyInitialize / ClassInitialize) are already in the property bag. The + // constructor's null/null branch copies the supplied properties into a fresh dictionary + // via the [with(properties)] spread, so no intermediate snapshot allocation is needed and + // isolation is preserved: per-iteration mutations to the clone's property bag won't leak + // back to this instance nor to subsequent iterations, and mutations to this instance after + // clone creation won't leak into the clone. + var clone = new TestContextImplementation(testMethod: null, testClassFullName: null, _properties, _messageLogger, _testRunCancellationToken); // Preserve TestRunCount so user code that observes it (e.g. retry-aware tests) sees // the same value it would see in the unfolded path. TestRunCount represents the