From e4be2d26efd39f08eec4624ceba30047857a2dba 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 1/2] 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 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs index a24f169e6c..ff9b2830e6 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs @@ -524,6 +524,7 @@ private SynchronizedStringBuilder GetTestContextMessagesStringBuilder() /// A fresh context suitable for one folded data-driven iteration. internal TestContextImplementation CloneForDataDrivenIteration() { +<<<<<<< HEAD // Pass testMethod: null and testClassFullName: null because the relevant labels // (including TestNameLabel / FullyQualifiedTestClassNameLabel and anything merged from // AssemblyInitialize / ClassInitialize) are already in _properties. In that branch the @@ -531,6 +532,16 @@ internal TestContextImplementation CloneForDataDrivenIteration() // directly gives the clone an isolated property bag without an extra intermediate copy: // per-iteration mutations to the clone's property bag won't leak back to this instance // nor to subsequent iterations. +======= + // 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. +>>>>>>> perf: skip intermediate Dictionary alloc in CloneForDataDrivenIteration 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 From 32927a98de14eb0cd97c9e50b5349c14f87bd021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Sun, 5 Jul 2026 21:45:16 +0200 Subject: [PATCH 2/2] Apply suggestion from @Evangelink --- .../Services/TestContextImplementation.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs index ff9b2830e6..c3bd509f26 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestContextImplementation.cs @@ -524,15 +524,6 @@ private SynchronizedStringBuilder GetTestContextMessagesStringBuilder() /// A fresh context suitable for one folded data-driven iteration. internal TestContextImplementation CloneForDataDrivenIteration() { -<<<<<<< HEAD - // Pass testMethod: null and testClassFullName: null because the relevant labels - // (including TestNameLabel / FullyQualifiedTestClassNameLabel and anything merged from - // AssemblyInitialize / ClassInitialize) are already in _properties. In that branch the - // constructor takes a shallow copy of the passed dictionary, so passing _properties - // directly gives the clone an isolated property bag without an extra intermediate copy: - // per-iteration mutations to the clone's property bag won't leak back to this instance - // nor to subsequent iterations. -======= // 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 @@ -541,7 +532,6 @@ internal TestContextImplementation CloneForDataDrivenIteration() // 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. ->>>>>>> perf: skip intermediate Dictionary alloc in CloneForDataDrivenIteration 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