Skip to content

perf: use FrozenSet/FrozenDictionary for read-only static lookups#6099

Merged
thomhurst merged 1 commit into
mainfrom
perf/issue-6047-frozen-collections
May 28, 2026
Merged

perf: use FrozenSet/FrozenDictionary for read-only static lookups#6099
thomhurst merged 1 commit into
mainfrom
perf/issue-6047-frozen-collections

Conversation

@thomhurst
Copy link
Copy Markdown
Owner

What

Converts three read-only static collections — populated once and read-many inside hot per-test / per-assembly loops — to FrozenSet/FrozenDictionary (System.Collections.Frozen, net8+) for faster lookups:

  1. TUnit.Core/Discovery/ObjectGraphDiscoverer.csSkipTypes (HashSet<Type>), queried via Contains in ShouldSkipType during per-test object-graph traversal.
  2. TUnit.Engine/Discovery/ReflectionTestDataCollector.csExcludedAssemblyNames (HashSet<string>), one Contains per assembly during reflection discovery.
  3. TUnit.Core/Helpers/TupleFactory.csTypedFactories (Dictionary<Type, Func<...>>), TryGetValue per tuple-arg conversion. Now built into a temp dictionary in the static ctor, then frozen.

Why

All three are read-only after initialization and queried in hot paths. FrozenSet/FrozenDictionary trade slightly higher build cost (one-time, at static init) for faster steady-state lookups.

netstandard2.0 guarding

FrozenSet/FrozenDictionary do not exist on netstandard2.0, and both TUnit.Core and TUnit.Engine multi-target netstandard2.0;net8.0;net9.0;net10.0. Every conversion is guarded with #if NET8_0_OR_GREATER: net8+ uses the frozen type, netstandard2.0 keeps the original HashSet/Dictionary. The using System.Collections.Frozen; is likewise guarded. All fields are private/internal static — no public API surface change, no source-gen output change.

Validation

  • dotnet build of both projects across all four TFMs: 0 warnings, 0 errors.
  • Verified netstandard2.0 compiles explicitly (-f netstandard2.0).
  • AOT-compatible (frozen collections are AOT-safe; no new reflection).

Closes #6047

Convert three read-only static collections queried in hot per-test/per-assembly
loops to FrozenSet/FrozenDictionary on net8+ for faster lookups:

- ObjectGraphDiscoverer.SkipTypes (HashSet<Type>)
- ReflectionTestDataCollector.ExcludedAssemblyNames (HashSet<string>)
- TupleFactory.TypedFactories (Dictionary<Type, Func<...>>)

Frozen collections are net8+ only, so usage is guarded with #if NET8_0_OR_GREATER;
netstandard2.0 retains the existing HashSet/Dictionary. All four TFMs build clean.

Closes #6047
@codacy-production
Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 4 complexity

Metric Results
Complexity 4

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Summary: No correctness issues found. This is a clean, well-structured performance PR.


What the PR does

Converts three static read-only collections — all populated once at startup then queried in hot loops — to FrozenSet/FrozenDictionary on .NET 8+, keeping the original mutable types on netstandard2.0 behind #if NET8_0_OR_GREATER guards.


Correctness analysis

Static-constructor initialization safety (TupleFactory.cs): TypedFactories is declared without an initializer under the FrozenDictionary branch, meaning it's null until the static constructor assigns it. The CLR guarantees the static constructor completes before any member of a static class can be accessed, so there is no observable window where TypedFactories is null.

Comparer semantics preserved: ToFrozenSet() called on a new HashSet<T> (default comparer) and ToFrozenDictionary called on a default Dictionary<Type, ...> both preserve the source's comparer (EqualityComparer<Type>.Default for Type keys, ordinal case-sensitive for string keys). No change in lookup behaviour.

netstandard2.0 guard correctness: Both TUnit.Core and TUnit.Engine inherit Library.props which sets TargetFrameworks=netstandard2.0;net8.0;net9.0;net10.0. The #if NET8_0_OR_GREATER guards are necessary and correct — System.Collections.Frozen does not exist on netstandard2.0.

RegisterFactory refactor: The method is private in a public static (implicitly sealed) class; no external or reflection-based callers exist in the codebase. All six call sites in the static constructor correctly pass the new factories parameter.

AOT compatibility: FrozenSet/FrozenDictionary are BCL types with full AOT support. No new reflection is introduced.


One minor style note

In TupleFactory.cs line 36:

// Current (valid, but uncommon)
TypedFactories = System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary(factories);

// More idiomatic extension-method form
TypedFactories = factories.ToFrozenDictionary();

Both compile and behave identically — FrozenDictionary.ToFrozenDictionary(source) is simply the explicit static invocation of the same extension method. The extension method form is the conventional pattern used everywhere else in the PR (ToFrozenSet()) and in the .NET docs. Not a bug, just a consistency nit.


Verdict

✅ Changes are correct, the #if guards handle all four TFMs properly, and the performance rationale is sound. The one minor item above (static vs. extension method call style) is a nit that doesn't affect correctness.

@thomhurst thomhurst merged commit 27248d7 into main May 28, 2026
14 checks passed
@thomhurst thomhurst deleted the perf/issue-6047-frozen-collections branch May 28, 2026 21:02
This was referenced May 29, 2026
github-actions Bot pushed a commit to BenjaminMichaelis/TrxLib that referenced this pull request Jun 2, 2026
Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.45.29 to
1.48.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.48.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.6 -->

## What's Changed
### Other Changes
* fix(sourcegen): fully-qualify Linq calls in params array binding
(#​6140) by @​thomhurst in thomhurst/TUnit#6141
### Dependencies
* chore(deps): update tunit to 1.48.0 by @​thomhurst in
thomhurst/TUnit#6135
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6137
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6138
* chore(deps): update verify to 31.19.0 by @​thomhurst in
thomhurst/TUnit#6139


**Full Changelog**:
thomhurst/TUnit@v1.48.0...v1.48.6

## 1.48.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.0 -->

## What's Changed
### Other Changes
* feat(html-report): baked-in C# syntax highlighting on Source tab by
@​slang25 in thomhurst/TUnit#6132
* feat(analyzers): suppress VSTHRD200 on test and hook methods by
@​thomhurst in thomhurst/TUnit#6123
* fix(source-gen): correct source location for cross-project inherited
tests by @​slang25 in thomhurst/TUnit#6133
* feat(assertions): add WasCalled to tunit mocks assertions by
@​robertcoltheart in thomhurst/TUnit#6126
* feat(arguments): bind array values to a single array test parameter by
@​thomhurst in thomhurst/TUnit#6122
* fix: populate retry/flaky attempt history in HTML report (#​6119) by
@​thomhurst in thomhurst/TUnit#6124
### Dependencies
* chore(deps): update tunit to 1.47.0 by @​thomhurst in
thomhurst/TUnit#6115
* chore(deps): update dependency
microsoft.visualstudio.threading.analyzers to 17.14.15 by @​thomhurst in
thomhurst/TUnit#6134


**Full Changelog**:
thomhurst/TUnit@v1.47.0...v1.48.0

## 1.47.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.47.0 -->

## What's Changed
### Other Changes
* perf(engine): hoist GetParameters and dict-dedup AfterTestDiscovery
hooks by @​thomhurst in thomhurst/TUnit#6062
* perf(engine): hoist GetParameters and drop LINQ in reflection
discovery by @​thomhurst in thomhurst/TUnit#6063
* perf(engine): cache treenode filter path on TestMetadata by
@​thomhurst in thomhurst/TUnit#6064
* perf: use is T pattern in ReflectionExtensions.HasAttribute fallback
(#​6060) by @​thomhurst in thomhurst/TUnit#6066
* perf: replace OrderBy().ToArray() with Array.Sort in
ConstraintKeyScheduler by @​thomhurst in
thomhurst/TUnit#6067
* perf: pool HashSet in WaitingTestIndex.GetCandidatesForReleasedKeys by
@​thomhurst in thomhurst/TUnit#6069
* perf: collapse OfType chains in JUnitXmlWriter (#​6052) by @​thomhurst
in thomhurst/TUnit#6070
* perf(engine): avoid closure allocation in
AfterHookPairTracker.GetOrCreateAfterAssemblyTask (#​6041) by
@​thomhurst in thomhurst/TUnit#6071
* perf: avoid closure allocation in
BeforeHookTaskCache.GetOrCreateBeforeAssemblyTask (#​6040) by
@​thomhurst in thomhurst/TUnit#6073
* perf: use TryAdd in TestDependencyResolver dependency dedupe by
@​thomhurst in thomhurst/TUnit#6068
* perf: replace LINQ Any with foreach in TestGenericTypeResolver
(#​6044) by @​thomhurst in thomhurst/TUnit#6072
* perf: avoid Cast<object>().FirstOrDefault() iterator alloc in
CastHelper (#​6029) by @​thomhurst in
thomhurst/TUnit#6074
* perf(engine): avoid string round-trip when building nested type names
(#​6049) by @​thomhurst in thomhurst/TUnit#6075
* perf(engine): replace Select+ToArray with manual Type[] build (#​6043)
by @​thomhurst in thomhurst/TUnit#6076
* perf(core): replace OfType().FirstOrDefault()/.Any() with foreach in
ClassConstructorHelper by @​thomhurst in
thomhurst/TUnit#6078
* perf(engine): avoid FirstOrDefault iterator alloc in
TestGenericTypeResolver by @​thomhurst in
thomhurst/TUnit#6079
* perf(engine): use SearchValues<char> for reporter filename
sanitization by @​thomhurst in
thomhurst/TUnit#6090
* perf: dedupe TestDataFormatter.FormatArguments with pooled
StringBuilder by @​thomhurst in
thomhurst/TUnit#6088
* perf(engine): use MemoryExtensions.Split for path parsing in
MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6085
* perf(engine): use CollectionsMarshal.GetValueRefOrAddDefault for
dictionary index builds by @​thomhurst in
thomhurst/TUnit#6086
* perf(engine): replace LINQ Where closure with inline filter in
MetadataDependencyExpander BFS by @​thomhurst in
thomhurst/TUnit#6084
* perf(engine): pool StringBuilder in DisplayNameBuilder.FormatArguments
by @​thomhurst in thomhurst/TUnit#6082
* Preserve specialized chaining after null assertions by @​thomhurst in
thomhurst/TUnit#6008
* perf: use EnumerateLines for line splitting in HtmlReportGenerator by
@​thomhurst in thomhurst/TUnit#6089
* perf: collapse Replace chain in TestNameFormatter.BuildTestId by
@​thomhurst in thomhurst/TUnit#6083
* perf: use OrdinalIgnoreCase Contains in HtmlReportGenerator span
mapping by @​thomhurst in thomhurst/TUnit#6093
* perf(assertions): avoid eager interpolated-string alloc in assertion
source ctors by @​thomhurst in
thomhurst/TUnit#6091
* perf: optimize TestNameFormatter argument and bool formatting by
@​thomhurst in thomhurst/TUnit#6095
* perf: use FrozenSet/FrozenDictionary for read-only static lookups by
@​thomhurst in thomhurst/TUnit#6099
* perf: avoid GetCustomAttributes() + LINQ chain for per-property
attribute scans by @​thomhurst in
thomhurst/TUnit#6098
* perf(engine): replace magic-string RequiredAttribute match with type
check in ConstructorHelper by @​thomhurst in
thomhurst/TUnit#6087
* perf(core): replace Select+Func factory chain in DataSourceHelpers by
@​thomhurst in thomhurst/TUnit#6081
* perf: replace LINQ dependency extraction with manual loop by
@​thomhurst in thomhurst/TUnit#6096
* perf(core): avoid string[] alloc in ArgumentFormatter.FormatArguments
by @​thomhurst in thomhurst/TUnit#6080
* perf: use [GeneratedRegex] in MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6094
* perf: dedupe GetSimpleTypeName into shared TypeNameFormatter by
@​thomhurst in thomhurst/TUnit#6097
* fix: remove GitVersion MSBuild task, pin local builds to 99.99.99
(#​6077) by @​thomhurst in thomhurst/TUnit#6101
* HTML Report: source link + code snippet on Source tab (#​5993) by
@​thomhurst in thomhurst/TUnit#6100
* perf(sourcegen): Single-pass attribute classification by @​thomhurst
in thomhurst/TUnit#6111
* perf(core): eliminate per-test allocations in TestDetails/HookMethod
by @​thomhurst in thomhurst/TUnit#6109
* perf: hoist char[] alloc in FsCheckPropertyTestExecutor to static
SearchValues by @​thomhurst in
thomhurst/TUnit#6108
* perf(core): de-LINQ data-source expansion by @​thomhurst in
thomhurst/TUnit#6110
* perf: avoid LINQ chains in TestDependency equality and
MethodDataSourceAttribute method matching by @​thomhurst in
thomhurst/TUnit#6092
* perf(engine): reduce allocations in reflection-mode
discovery/execution by @​thomhurst in
thomhurst/TUnit#6113
* perf(assertions): allocation-free passing path (TUnit.Assertions) by
@​thomhurst in thomhurst/TUnit#6112
### Dependencies
 ... (truncated)

## 1.46.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.46.0 -->

## What's Changed
### Other Changes
* docs: add Rider VSTest conflict troubleshooting by @​smolchanovsky in
thomhurst/TUnit#5989
* Populate generated test metadata with full source spans by @​Copilot
in thomhurst/TUnit#5991
* Add devcontainer configuration by @​Copilot in
thomhurst/TUnit#5995
* fix: treenode filter pre-filter rejects parenthesised segments
(#​6026) by @​thomhurst in thomhurst/TUnit#6027
* fix(engine): isolate per-session state under MTP server-mode
concurrency (#​6001) by @​thomhurst in
thomhurst/TUnit#6025
### Dependencies
* chore(deps): update dependency stackexchange.redis to 2.13.10 by
@​thomhurst in thomhurst/TUnit#5985
* chore(deps): update tunit to 1.45.29 by @​thomhurst in
thomhurst/TUnit#5986
* chore(deps): update dependency mockolate to 3.2.1 by @​thomhurst in
thomhurst/TUnit#5987
* chore(deps): update dependency microsoft.playwright to 1.60.0 by
@​thomhurst in thomhurst/TUnit#5988
* chore(deps): update dependency messagepack to 3.1.6 by @​thomhurst in
thomhurst/TUnit#5992
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5998
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5997
* chore(deps): update verify to 31.17.0 by @​thomhurst in
thomhurst/TUnit#6000
* chore(deps): update verify to 31.18.0 by @​thomhurst in
thomhurst/TUnit#6013
* chore(deps): update dependency microsoft.net.test.sdk to 18.6.0 by
@​thomhurst in thomhurst/TUnit#6016
* chore(deps): update dependency dompurify to v3.4.6 by @​thomhurst in
thomhurst/TUnit#6015
* chore(deps): update dependency dompurify to v3.4.7 by @​thomhurst in
thomhurst/TUnit#6019
* chore(deps): update dependency npgsql to 10.0.3 by @​thomhurst in
thomhurst/TUnit#6020
* chore(deps): update dependency stackexchange.redis to 2.13.17 by
@​thomhurst in thomhurst/TUnit#6021
* chore(deps): update dependency npgsql.entityframeworkcore.postgresql
to 10.0.2 by @​thomhurst in thomhurst/TUnit#6022

## New Contributors
* @​smolchanovsky made their first contribution in
thomhurst/TUnit#5989

**Full Changelog**:
thomhurst/TUnit@v1.45.29...v1.46.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.45.29...v1.48.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit&package-manager=nuget&previous-version=1.45.29&new-version=1.48.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to BenjaminMichaelis/DotnetTemplates that referenced this pull request Jun 2, 2026
Updated
[Microsoft.Testing.Extensions.CodeCoverage](https://github.com/microsoft/codecoverage)
from 18.6.2 to 18.7.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Testing.Extensions.CodeCoverage's
releases](https://github.com/microsoft/codecoverage/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/microsoft/codecoverage/commits).
</details>

Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.44.39 to
1.48.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.48.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.6 -->

## What's Changed
### Other Changes
* fix(sourcegen): fully-qualify Linq calls in params array binding
(#​6140) by @​thomhurst in thomhurst/TUnit#6141
### Dependencies
* chore(deps): update tunit to 1.48.0 by @​thomhurst in
thomhurst/TUnit#6135
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6137
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6138
* chore(deps): update verify to 31.19.0 by @​thomhurst in
thomhurst/TUnit#6139


**Full Changelog**:
thomhurst/TUnit@v1.48.0...v1.48.6

## 1.48.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.0 -->

## What's Changed
### Other Changes
* feat(html-report): baked-in C# syntax highlighting on Source tab by
@​slang25 in thomhurst/TUnit#6132
* feat(analyzers): suppress VSTHRD200 on test and hook methods by
@​thomhurst in thomhurst/TUnit#6123
* fix(source-gen): correct source location for cross-project inherited
tests by @​slang25 in thomhurst/TUnit#6133
* feat(assertions): add WasCalled to tunit mocks assertions by
@​robertcoltheart in thomhurst/TUnit#6126
* feat(arguments): bind array values to a single array test parameter by
@​thomhurst in thomhurst/TUnit#6122
* fix: populate retry/flaky attempt history in HTML report (#​6119) by
@​thomhurst in thomhurst/TUnit#6124
### Dependencies
* chore(deps): update tunit to 1.47.0 by @​thomhurst in
thomhurst/TUnit#6115
* chore(deps): update dependency
microsoft.visualstudio.threading.analyzers to 17.14.15 by @​thomhurst in
thomhurst/TUnit#6134


**Full Changelog**:
thomhurst/TUnit@v1.47.0...v1.48.0

## 1.47.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.47.0 -->

## What's Changed
### Other Changes
* perf(engine): hoist GetParameters and dict-dedup AfterTestDiscovery
hooks by @​thomhurst in thomhurst/TUnit#6062
* perf(engine): hoist GetParameters and drop LINQ in reflection
discovery by @​thomhurst in thomhurst/TUnit#6063
* perf(engine): cache treenode filter path on TestMetadata by
@​thomhurst in thomhurst/TUnit#6064
* perf: use is T pattern in ReflectionExtensions.HasAttribute fallback
(#​6060) by @​thomhurst in thomhurst/TUnit#6066
* perf: replace OrderBy().ToArray() with Array.Sort in
ConstraintKeyScheduler by @​thomhurst in
thomhurst/TUnit#6067
* perf: pool HashSet in WaitingTestIndex.GetCandidatesForReleasedKeys by
@​thomhurst in thomhurst/TUnit#6069
* perf: collapse OfType chains in JUnitXmlWriter (#​6052) by @​thomhurst
in thomhurst/TUnit#6070
* perf(engine): avoid closure allocation in
AfterHookPairTracker.GetOrCreateAfterAssemblyTask (#​6041) by
@​thomhurst in thomhurst/TUnit#6071
* perf: avoid closure allocation in
BeforeHookTaskCache.GetOrCreateBeforeAssemblyTask (#​6040) by
@​thomhurst in thomhurst/TUnit#6073
* perf: use TryAdd in TestDependencyResolver dependency dedupe by
@​thomhurst in thomhurst/TUnit#6068
* perf: replace LINQ Any with foreach in TestGenericTypeResolver
(#​6044) by @​thomhurst in thomhurst/TUnit#6072
* perf: avoid Cast<object>().FirstOrDefault() iterator alloc in
CastHelper (#​6029) by @​thomhurst in
thomhurst/TUnit#6074
* perf(engine): avoid string round-trip when building nested type names
(#​6049) by @​thomhurst in thomhurst/TUnit#6075
* perf(engine): replace Select+ToArray with manual Type[] build (#​6043)
by @​thomhurst in thomhurst/TUnit#6076
* perf(core): replace OfType().FirstOrDefault()/.Any() with foreach in
ClassConstructorHelper by @​thomhurst in
thomhurst/TUnit#6078
* perf(engine): avoid FirstOrDefault iterator alloc in
TestGenericTypeResolver by @​thomhurst in
thomhurst/TUnit#6079
* perf(engine): use SearchValues<char> for reporter filename
sanitization by @​thomhurst in
thomhurst/TUnit#6090
* perf: dedupe TestDataFormatter.FormatArguments with pooled
StringBuilder by @​thomhurst in
thomhurst/TUnit#6088
* perf(engine): use MemoryExtensions.Split for path parsing in
MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6085
* perf(engine): use CollectionsMarshal.GetValueRefOrAddDefault for
dictionary index builds by @​thomhurst in
thomhurst/TUnit#6086
* perf(engine): replace LINQ Where closure with inline filter in
MetadataDependencyExpander BFS by @​thomhurst in
thomhurst/TUnit#6084
* perf(engine): pool StringBuilder in DisplayNameBuilder.FormatArguments
by @​thomhurst in thomhurst/TUnit#6082
* Preserve specialized chaining after null assertions by @​thomhurst in
thomhurst/TUnit#6008
* perf: use EnumerateLines for line splitting in HtmlReportGenerator by
@​thomhurst in thomhurst/TUnit#6089
* perf: collapse Replace chain in TestNameFormatter.BuildTestId by
@​thomhurst in thomhurst/TUnit#6083
* perf: use OrdinalIgnoreCase Contains in HtmlReportGenerator span
mapping by @​thomhurst in thomhurst/TUnit#6093
* perf(assertions): avoid eager interpolated-string alloc in assertion
source ctors by @​thomhurst in
thomhurst/TUnit#6091
* perf: optimize TestNameFormatter argument and bool formatting by
@​thomhurst in thomhurst/TUnit#6095
* perf: use FrozenSet/FrozenDictionary for read-only static lookups by
@​thomhurst in thomhurst/TUnit#6099
* perf: avoid GetCustomAttributes() + LINQ chain for per-property
attribute scans by @​thomhurst in
thomhurst/TUnit#6098
* perf(engine): replace magic-string RequiredAttribute match with type
check in ConstructorHelper by @​thomhurst in
thomhurst/TUnit#6087
* perf(core): replace Select+Func factory chain in DataSourceHelpers by
@​thomhurst in thomhurst/TUnit#6081
* perf: replace LINQ dependency extraction with manual loop by
@​thomhurst in thomhurst/TUnit#6096
* perf(core): avoid string[] alloc in ArgumentFormatter.FormatArguments
by @​thomhurst in thomhurst/TUnit#6080
* perf: use [GeneratedRegex] in MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6094
* perf: dedupe GetSimpleTypeName into shared TypeNameFormatter by
@​thomhurst in thomhurst/TUnit#6097
* fix: remove GitVersion MSBuild task, pin local builds to 99.99.99
(#​6077) by @​thomhurst in thomhurst/TUnit#6101
* HTML Report: source link + code snippet on Source tab (#​5993) by
@​thomhurst in thomhurst/TUnit#6100
* perf(sourcegen): Single-pass attribute classification by @​thomhurst
in thomhurst/TUnit#6111
* perf(core): eliminate per-test allocations in TestDetails/HookMethod
by @​thomhurst in thomhurst/TUnit#6109
* perf: hoist char[] alloc in FsCheckPropertyTestExecutor to static
SearchValues by @​thomhurst in
thomhurst/TUnit#6108
* perf(core): de-LINQ data-source expansion by @​thomhurst in
thomhurst/TUnit#6110
* perf: avoid LINQ chains in TestDependency equality and
MethodDataSourceAttribute method matching by @​thomhurst in
thomhurst/TUnit#6092
* perf(engine): reduce allocations in reflection-mode
discovery/execution by @​thomhurst in
thomhurst/TUnit#6113
* perf(assertions): allocation-free passing path (TUnit.Assertions) by
@​thomhurst in thomhurst/TUnit#6112
### Dependencies
 ... (truncated)

## 1.46.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.46.0 -->

## What's Changed
### Other Changes
* docs: add Rider VSTest conflict troubleshooting by @​smolchanovsky in
thomhurst/TUnit#5989
* Populate generated test metadata with full source spans by @​Copilot
in thomhurst/TUnit#5991
* Add devcontainer configuration by @​Copilot in
thomhurst/TUnit#5995
* fix: treenode filter pre-filter rejects parenthesised segments
(#​6026) by @​thomhurst in thomhurst/TUnit#6027
* fix(engine): isolate per-session state under MTP server-mode
concurrency (#​6001) by @​thomhurst in
thomhurst/TUnit#6025
### Dependencies
* chore(deps): update dependency stackexchange.redis to 2.13.10 by
@​thomhurst in thomhurst/TUnit#5985
* chore(deps): update tunit to 1.45.29 by @​thomhurst in
thomhurst/TUnit#5986
* chore(deps): update dependency mockolate to 3.2.1 by @​thomhurst in
thomhurst/TUnit#5987
* chore(deps): update dependency microsoft.playwright to 1.60.0 by
@​thomhurst in thomhurst/TUnit#5988
* chore(deps): update dependency messagepack to 3.1.6 by @​thomhurst in
thomhurst/TUnit#5992
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5998
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5997
* chore(deps): update verify to 31.17.0 by @​thomhurst in
thomhurst/TUnit#6000
* chore(deps): update verify to 31.18.0 by @​thomhurst in
thomhurst/TUnit#6013
* chore(deps): update dependency microsoft.net.test.sdk to 18.6.0 by
@​thomhurst in thomhurst/TUnit#6016
* chore(deps): update dependency dompurify to v3.4.6 by @​thomhurst in
thomhurst/TUnit#6015
* chore(deps): update dependency dompurify to v3.4.7 by @​thomhurst in
thomhurst/TUnit#6019
* chore(deps): update dependency npgsql to 10.0.3 by @​thomhurst in
thomhurst/TUnit#6020
* chore(deps): update dependency stackexchange.redis to 2.13.17 by
@​thomhurst in thomhurst/TUnit#6021
* chore(deps): update dependency npgsql.entityframeworkcore.postgresql
to 10.0.2 by @​thomhurst in thomhurst/TUnit#6022

## New Contributors
* @​smolchanovsky made their first contribution in
thomhurst/TUnit#5989

**Full Changelog**:
thomhurst/TUnit@v1.45.29...v1.46.0

## 1.45.29

<!-- Release notes generated using configuration in .github/release.yml
at v1.45.29 -->

## What's Changed
### Other Changes
* Fix shared fixture lifetime for reused discovery instances by
@​thomhurst in thomhurst/TUnit#5983
* Preserve override accessibility in generated mocks by @​thomhurst in
thomhurst/TUnit#5984
### Dependencies
* chore(deps): update tunit to 1.45.22 by @​thomhurst in
thomhurst/TUnit#5974
* chore(deps): update dependency messagepack to 3.1.5 by @​thomhurst in
thomhurst/TUnit#5978
* chore(deps): update aspire to 13.3.5 by @​thomhurst in
thomhurst/TUnit#5980


**Full Changelog**:
thomhurst/TUnit@v1.45.22...v1.45.29

## 1.45.22

<!-- Release notes generated using configuration in .github/release.yml
at v1.45.22 -->

## What's Changed
### Other Changes
* Remove ".NET" from Aspire references by @​antmdvs in
thomhurst/TUnit#5968
* Fix chained mock setup behavior by @​thomhurst in
thomhurst/TUnit#5973
### Dependencies
* chore(deps): update tunit to 1.45.8 by @​thomhurst in
thomhurst/TUnit#5958
* chore(deps): update dependency nunit to 4.6.1 by @​thomhurst in
thomhurst/TUnit#5961
* chore(deps): update dependency testcontainers.postgresql to 4.12.0 by
@​thomhurst in thomhurst/TUnit#5963
* chore(deps): update dependency testcontainers.redis to 4.12.0 by
@​thomhurst in thomhurst/TUnit#5965
* chore(deps): update dependency testcontainers.kafka to 4.12.0 by
@​thomhurst in thomhurst/TUnit#5962
* chore(deps): update aspire to 13.3.4 by @​thomhurst in
thomhurst/TUnit#5966
* chore(deps): bump webpack-dev-server from 5.2.2 to 5.2.4 in /docs by
@​dependabot[bot] in thomhurst/TUnit#5964

## New Contributors
* @​antmdvs made their first contribution in
thomhurst/TUnit#5968

**Full Changelog**:
thomhurst/TUnit@v1.45.8...v1.45.22

## 1.45.8

<!-- Release notes generated using configuration in .github/release.yml
at v1.45.8 -->

## What's Changed
### Other Changes
* fix(aspire): route CreateHttpClient through IHttpClientFactory by
@​thomhurst in thomhurst/TUnit#5957
### Dependencies
* chore(deps): update tunit to 1.45.0 by @​thomhurst in
thomhurst/TUnit#5949
* chore(deps): update dependency dompurify to v3.4.5 by @​thomhurst in
thomhurst/TUnit#5951
* chore(deps): update dependency
microsoft.testing.extensions.codecoverage to 18.7.0 by @​thomhurst in
thomhurst/TUnit#5953
* chore(deps): update dependency coverlet.collector to 10.0.1 by
@​thomhurst in thomhurst/TUnit#5952
* chore(deps): update dependency polyfill to 10.6.0 by @​thomhurst in
thomhurst/TUnit#5955
* chore(deps): update dependency polyfill to 10.6.0 by @​thomhurst in
thomhurst/TUnit#5954


**Full Changelog**:
thomhurst/TUnit@v1.45.0...v1.45.8

## 1.45.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.45.0 -->

## What's Changed
### Other Changes
* fix(generator): place CallerArgumentExpression before params in
[GenerateAssertion] emit by @​JohnVerheij in
thomhurst/TUnit#5940
* fix(sourcegen): drop covariant TActual when [GenerateAssertion] method
has its own type parameters by @​JohnVerheij in
thomhurst/TUnit#5935
* feat(assertions): add CancellationToken overload to WaitsFor and
Eventually by @​JohnVerheij in
thomhurst/TUnit#5938
* fix(html-report): extract categories using MTP Key=name convention by
@​thomhurst in thomhurst/TUnit#5946
* feat(html-report): rewrite as split-pane design template by
@​thomhurst in thomhurst/TUnit#5947
### Dependencies
* chore(deps): update microsoft.testing to 2.2.3 by @​thomhurst in
thomhurst/TUnit#5927
* chore(deps): update mstest to 4.2.3 by @​thomhurst in
thomhurst/TUnit#5928
* chore(deps): update tunit to 1.44.39 by @​thomhurst in
thomhurst/TUnit#5929
* chore(deps): update aspire to 13.3.3 by @​thomhurst in
thomhurst/TUnit#5933
* chore(deps): update dependency dompurify to v3.4.4 by @​thomhurst in
thomhurst/TUnit#5944
* chore(deps): update dependency qs to v6.15.2 by @​thomhurst in
thomhurst/TUnit#5941


**Full Changelog**:
thomhurst/TUnit@v1.44.39...v1.45.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.44.39...v1.48.6).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
intellitect-bot pushed a commit to IntelliTect/EssentialCSharp.Web that referenced this pull request Jun 2, 2026
Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.45.29 to
1.48.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.48.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.6 -->

## What's Changed
### Other Changes
* fix(sourcegen): fully-qualify Linq calls in params array binding
(#​6140) by @​thomhurst in thomhurst/TUnit#6141
### Dependencies
* chore(deps): update tunit to 1.48.0 by @​thomhurst in
thomhurst/TUnit#6135
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6137
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6138
* chore(deps): update verify to 31.19.0 by @​thomhurst in
thomhurst/TUnit#6139


**Full Changelog**:
thomhurst/TUnit@v1.48.0...v1.48.6

## 1.48.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.0 -->

## What's Changed
### Other Changes
* feat(html-report): baked-in C# syntax highlighting on Source tab by
@​slang25 in thomhurst/TUnit#6132
* feat(analyzers): suppress VSTHRD200 on test and hook methods by
@​thomhurst in thomhurst/TUnit#6123
* fix(source-gen): correct source location for cross-project inherited
tests by @​slang25 in thomhurst/TUnit#6133
* feat(assertions): add WasCalled to tunit mocks assertions by
@​robertcoltheart in thomhurst/TUnit#6126
* feat(arguments): bind array values to a single array test parameter by
@​thomhurst in thomhurst/TUnit#6122
* fix: populate retry/flaky attempt history in HTML report (#​6119) by
@​thomhurst in thomhurst/TUnit#6124
### Dependencies
* chore(deps): update tunit to 1.47.0 by @​thomhurst in
thomhurst/TUnit#6115
* chore(deps): update dependency
microsoft.visualstudio.threading.analyzers to 17.14.15 by @​thomhurst in
thomhurst/TUnit#6134


**Full Changelog**:
thomhurst/TUnit@v1.47.0...v1.48.0

## 1.47.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.47.0 -->

## What's Changed
### Other Changes
* perf(engine): hoist GetParameters and dict-dedup AfterTestDiscovery
hooks by @​thomhurst in thomhurst/TUnit#6062
* perf(engine): hoist GetParameters and drop LINQ in reflection
discovery by @​thomhurst in thomhurst/TUnit#6063
* perf(engine): cache treenode filter path on TestMetadata by
@​thomhurst in thomhurst/TUnit#6064
* perf: use is T pattern in ReflectionExtensions.HasAttribute fallback
(#​6060) by @​thomhurst in thomhurst/TUnit#6066
* perf: replace OrderBy().ToArray() with Array.Sort in
ConstraintKeyScheduler by @​thomhurst in
thomhurst/TUnit#6067
* perf: pool HashSet in WaitingTestIndex.GetCandidatesForReleasedKeys by
@​thomhurst in thomhurst/TUnit#6069
* perf: collapse OfType chains in JUnitXmlWriter (#​6052) by @​thomhurst
in thomhurst/TUnit#6070
* perf(engine): avoid closure allocation in
AfterHookPairTracker.GetOrCreateAfterAssemblyTask (#​6041) by
@​thomhurst in thomhurst/TUnit#6071
* perf: avoid closure allocation in
BeforeHookTaskCache.GetOrCreateBeforeAssemblyTask (#​6040) by
@​thomhurst in thomhurst/TUnit#6073
* perf: use TryAdd in TestDependencyResolver dependency dedupe by
@​thomhurst in thomhurst/TUnit#6068
* perf: replace LINQ Any with foreach in TestGenericTypeResolver
(#​6044) by @​thomhurst in thomhurst/TUnit#6072
* perf: avoid Cast<object>().FirstOrDefault() iterator alloc in
CastHelper (#​6029) by @​thomhurst in
thomhurst/TUnit#6074
* perf(engine): avoid string round-trip when building nested type names
(#​6049) by @​thomhurst in thomhurst/TUnit#6075
* perf(engine): replace Select+ToArray with manual Type[] build (#​6043)
by @​thomhurst in thomhurst/TUnit#6076
* perf(core): replace OfType().FirstOrDefault()/.Any() with foreach in
ClassConstructorHelper by @​thomhurst in
thomhurst/TUnit#6078
* perf(engine): avoid FirstOrDefault iterator alloc in
TestGenericTypeResolver by @​thomhurst in
thomhurst/TUnit#6079
* perf(engine): use SearchValues<char> for reporter filename
sanitization by @​thomhurst in
thomhurst/TUnit#6090
* perf: dedupe TestDataFormatter.FormatArguments with pooled
StringBuilder by @​thomhurst in
thomhurst/TUnit#6088
* perf(engine): use MemoryExtensions.Split for path parsing in
MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6085
* perf(engine): use CollectionsMarshal.GetValueRefOrAddDefault for
dictionary index builds by @​thomhurst in
thomhurst/TUnit#6086
* perf(engine): replace LINQ Where closure with inline filter in
MetadataDependencyExpander BFS by @​thomhurst in
thomhurst/TUnit#6084
* perf(engine): pool StringBuilder in DisplayNameBuilder.FormatArguments
by @​thomhurst in thomhurst/TUnit#6082
* Preserve specialized chaining after null assertions by @​thomhurst in
thomhurst/TUnit#6008
* perf: use EnumerateLines for line splitting in HtmlReportGenerator by
@​thomhurst in thomhurst/TUnit#6089
* perf: collapse Replace chain in TestNameFormatter.BuildTestId by
@​thomhurst in thomhurst/TUnit#6083
* perf: use OrdinalIgnoreCase Contains in HtmlReportGenerator span
mapping by @​thomhurst in thomhurst/TUnit#6093
* perf(assertions): avoid eager interpolated-string alloc in assertion
source ctors by @​thomhurst in
thomhurst/TUnit#6091
* perf: optimize TestNameFormatter argument and bool formatting by
@​thomhurst in thomhurst/TUnit#6095
* perf: use FrozenSet/FrozenDictionary for read-only static lookups by
@​thomhurst in thomhurst/TUnit#6099
* perf: avoid GetCustomAttributes() + LINQ chain for per-property
attribute scans by @​thomhurst in
thomhurst/TUnit#6098
* perf(engine): replace magic-string RequiredAttribute match with type
check in ConstructorHelper by @​thomhurst in
thomhurst/TUnit#6087
* perf(core): replace Select+Func factory chain in DataSourceHelpers by
@​thomhurst in thomhurst/TUnit#6081
* perf: replace LINQ dependency extraction with manual loop by
@​thomhurst in thomhurst/TUnit#6096
* perf(core): avoid string[] alloc in ArgumentFormatter.FormatArguments
by @​thomhurst in thomhurst/TUnit#6080
* perf: use [GeneratedRegex] in MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6094
* perf: dedupe GetSimpleTypeName into shared TypeNameFormatter by
@​thomhurst in thomhurst/TUnit#6097
* fix: remove GitVersion MSBuild task, pin local builds to 99.99.99
(#​6077) by @​thomhurst in thomhurst/TUnit#6101
* HTML Report: source link + code snippet on Source tab (#​5993) by
@​thomhurst in thomhurst/TUnit#6100
* perf(sourcegen): Single-pass attribute classification by @​thomhurst
in thomhurst/TUnit#6111
* perf(core): eliminate per-test allocations in TestDetails/HookMethod
by @​thomhurst in thomhurst/TUnit#6109
* perf: hoist char[] alloc in FsCheckPropertyTestExecutor to static
SearchValues by @​thomhurst in
thomhurst/TUnit#6108
* perf(core): de-LINQ data-source expansion by @​thomhurst in
thomhurst/TUnit#6110
* perf: avoid LINQ chains in TestDependency equality and
MethodDataSourceAttribute method matching by @​thomhurst in
thomhurst/TUnit#6092
* perf(engine): reduce allocations in reflection-mode
discovery/execution by @​thomhurst in
thomhurst/TUnit#6113
* perf(assertions): allocation-free passing path (TUnit.Assertions) by
@​thomhurst in thomhurst/TUnit#6112
### Dependencies
 ... (truncated)

## 1.46.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.46.0 -->

## What's Changed
### Other Changes
* docs: add Rider VSTest conflict troubleshooting by @​smolchanovsky in
thomhurst/TUnit#5989
* Populate generated test metadata with full source spans by @​Copilot
in thomhurst/TUnit#5991
* Add devcontainer configuration by @​Copilot in
thomhurst/TUnit#5995
* fix: treenode filter pre-filter rejects parenthesised segments
(#​6026) by @​thomhurst in thomhurst/TUnit#6027
* fix(engine): isolate per-session state under MTP server-mode
concurrency (#​6001) by @​thomhurst in
thomhurst/TUnit#6025
### Dependencies
* chore(deps): update dependency stackexchange.redis to 2.13.10 by
@​thomhurst in thomhurst/TUnit#5985
* chore(deps): update tunit to 1.45.29 by @​thomhurst in
thomhurst/TUnit#5986
* chore(deps): update dependency mockolate to 3.2.1 by @​thomhurst in
thomhurst/TUnit#5987
* chore(deps): update dependency microsoft.playwright to 1.60.0 by
@​thomhurst in thomhurst/TUnit#5988
* chore(deps): update dependency messagepack to 3.1.6 by @​thomhurst in
thomhurst/TUnit#5992
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5998
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5997
* chore(deps): update verify to 31.17.0 by @​thomhurst in
thomhurst/TUnit#6000
* chore(deps): update verify to 31.18.0 by @​thomhurst in
thomhurst/TUnit#6013
* chore(deps): update dependency microsoft.net.test.sdk to 18.6.0 by
@​thomhurst in thomhurst/TUnit#6016
* chore(deps): update dependency dompurify to v3.4.6 by @​thomhurst in
thomhurst/TUnit#6015
* chore(deps): update dependency dompurify to v3.4.7 by @​thomhurst in
thomhurst/TUnit#6019
* chore(deps): update dependency npgsql to 10.0.3 by @​thomhurst in
thomhurst/TUnit#6020
* chore(deps): update dependency stackexchange.redis to 2.13.17 by
@​thomhurst in thomhurst/TUnit#6021
* chore(deps): update dependency npgsql.entityframeworkcore.postgresql
to 10.0.2 by @​thomhurst in thomhurst/TUnit#6022

## New Contributors
* @​smolchanovsky made their first contribution in
thomhurst/TUnit#5989

**Full Changelog**:
thomhurst/TUnit@v1.45.29...v1.46.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.45.29...v1.48.6).
</details>

Updated [TUnit.AspNetCore](https://github.com/thomhurst/TUnit) from
1.45.29 to 1.48.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit.AspNetCore's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.48.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.6 -->

## What's Changed
### Other Changes
* fix(sourcegen): fully-qualify Linq calls in params array binding
(#​6140) by @​thomhurst in thomhurst/TUnit#6141
### Dependencies
* chore(deps): update tunit to 1.48.0 by @​thomhurst in
thomhurst/TUnit#6135
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6137
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6138
* chore(deps): update verify to 31.19.0 by @​thomhurst in
thomhurst/TUnit#6139


**Full Changelog**:
thomhurst/TUnit@v1.48.0...v1.48.6

## 1.48.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.0 -->

## What's Changed
### Other Changes
* feat(html-report): baked-in C# syntax highlighting on Source tab by
@​slang25 in thomhurst/TUnit#6132
* feat(analyzers): suppress VSTHRD200 on test and hook methods by
@​thomhurst in thomhurst/TUnit#6123
* fix(source-gen): correct source location for cross-project inherited
tests by @​slang25 in thomhurst/TUnit#6133
* feat(assertions): add WasCalled to tunit mocks assertions by
@​robertcoltheart in thomhurst/TUnit#6126
* feat(arguments): bind array values to a single array test parameter by
@​thomhurst in thomhurst/TUnit#6122
* fix: populate retry/flaky attempt history in HTML report (#​6119) by
@​thomhurst in thomhurst/TUnit#6124
### Dependencies
* chore(deps): update tunit to 1.47.0 by @​thomhurst in
thomhurst/TUnit#6115
* chore(deps): update dependency
microsoft.visualstudio.threading.analyzers to 17.14.15 by @​thomhurst in
thomhurst/TUnit#6134


**Full Changelog**:
thomhurst/TUnit@v1.47.0...v1.48.0

## 1.47.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.47.0 -->

## What's Changed
### Other Changes
* perf(engine): hoist GetParameters and dict-dedup AfterTestDiscovery
hooks by @​thomhurst in thomhurst/TUnit#6062
* perf(engine): hoist GetParameters and drop LINQ in reflection
discovery by @​thomhurst in thomhurst/TUnit#6063
* perf(engine): cache treenode filter path on TestMetadata by
@​thomhurst in thomhurst/TUnit#6064
* perf: use is T pattern in ReflectionExtensions.HasAttribute fallback
(#​6060) by @​thomhurst in thomhurst/TUnit#6066
* perf: replace OrderBy().ToArray() with Array.Sort in
ConstraintKeyScheduler by @​thomhurst in
thomhurst/TUnit#6067
* perf: pool HashSet in WaitingTestIndex.GetCandidatesForReleasedKeys by
@​thomhurst in thomhurst/TUnit#6069
* perf: collapse OfType chains in JUnitXmlWriter (#​6052) by @​thomhurst
in thomhurst/TUnit#6070
* perf(engine): avoid closure allocation in
AfterHookPairTracker.GetOrCreateAfterAssemblyTask (#​6041) by
@​thomhurst in thomhurst/TUnit#6071
* perf: avoid closure allocation in
BeforeHookTaskCache.GetOrCreateBeforeAssemblyTask (#​6040) by
@​thomhurst in thomhurst/TUnit#6073
* perf: use TryAdd in TestDependencyResolver dependency dedupe by
@​thomhurst in thomhurst/TUnit#6068
* perf: replace LINQ Any with foreach in TestGenericTypeResolver
(#​6044) by @​thomhurst in thomhurst/TUnit#6072
* perf: avoid Cast<object>().FirstOrDefault() iterator alloc in
CastHelper (#​6029) by @​thomhurst in
thomhurst/TUnit#6074
* perf(engine): avoid string round-trip when building nested type names
(#​6049) by @​thomhurst in thomhurst/TUnit#6075
* perf(engine): replace Select+ToArray with manual Type[] build (#​6043)
by @​thomhurst in thomhurst/TUnit#6076
* perf(core): replace OfType().FirstOrDefault()/.Any() with foreach in
ClassConstructorHelper by @​thomhurst in
thomhurst/TUnit#6078
* perf(engine): avoid FirstOrDefault iterator alloc in
TestGenericTypeResolver by @​thomhurst in
thomhurst/TUnit#6079
* perf(engine): use SearchValues<char> for reporter filename
sanitization by @​thomhurst in
thomhurst/TUnit#6090
* perf: dedupe TestDataFormatter.FormatArguments with pooled
StringBuilder by @​thomhurst in
thomhurst/TUnit#6088
* perf(engine): use MemoryExtensions.Split for path parsing in
MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6085
* perf(engine): use CollectionsMarshal.GetValueRefOrAddDefault for
dictionary index builds by @​thomhurst in
thomhurst/TUnit#6086
* perf(engine): replace LINQ Where closure with inline filter in
MetadataDependencyExpander BFS by @​thomhurst in
thomhurst/TUnit#6084
* perf(engine): pool StringBuilder in DisplayNameBuilder.FormatArguments
by @​thomhurst in thomhurst/TUnit#6082
* Preserve specialized chaining after null assertions by @​thomhurst in
thomhurst/TUnit#6008
* perf: use EnumerateLines for line splitting in HtmlReportGenerator by
@​thomhurst in thomhurst/TUnit#6089
* perf: collapse Replace chain in TestNameFormatter.BuildTestId by
@​thomhurst in thomhurst/TUnit#6083
* perf: use OrdinalIgnoreCase Contains in HtmlReportGenerator span
mapping by @​thomhurst in thomhurst/TUnit#6093
* perf(assertions): avoid eager interpolated-string alloc in assertion
source ctors by @​thomhurst in
thomhurst/TUnit#6091
* perf: optimize TestNameFormatter argument and bool formatting by
@​thomhurst in thomhurst/TUnit#6095
* perf: use FrozenSet/FrozenDictionary for read-only static lookups by
@​thomhurst in thomhurst/TUnit#6099
* perf: avoid GetCustomAttributes() + LINQ chain for per-property
attribute scans by @​thomhurst in
thomhurst/TUnit#6098
* perf(engine): replace magic-string RequiredAttribute match with type
check in ConstructorHelper by @​thomhurst in
thomhurst/TUnit#6087
* perf(core): replace Select+Func factory chain in DataSourceHelpers by
@​thomhurst in thomhurst/TUnit#6081
* perf: replace LINQ dependency extraction with manual loop by
@​thomhurst in thomhurst/TUnit#6096
* perf(core): avoid string[] alloc in ArgumentFormatter.FormatArguments
by @​thomhurst in thomhurst/TUnit#6080
* perf: use [GeneratedRegex] in MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6094
* perf: dedupe GetSimpleTypeName into shared TypeNameFormatter by
@​thomhurst in thomhurst/TUnit#6097
* fix: remove GitVersion MSBuild task, pin local builds to 99.99.99
(#​6077) by @​thomhurst in thomhurst/TUnit#6101
* HTML Report: source link + code snippet on Source tab (#​5993) by
@​thomhurst in thomhurst/TUnit#6100
* perf(sourcegen): Single-pass attribute classification by @​thomhurst
in thomhurst/TUnit#6111
* perf(core): eliminate per-test allocations in TestDetails/HookMethod
by @​thomhurst in thomhurst/TUnit#6109
* perf: hoist char[] alloc in FsCheckPropertyTestExecutor to static
SearchValues by @​thomhurst in
thomhurst/TUnit#6108
* perf(core): de-LINQ data-source expansion by @​thomhurst in
thomhurst/TUnit#6110
* perf: avoid LINQ chains in TestDependency equality and
MethodDataSourceAttribute method matching by @​thomhurst in
thomhurst/TUnit#6092
* perf(engine): reduce allocations in reflection-mode
discovery/execution by @​thomhurst in
thomhurst/TUnit#6113
* perf(assertions): allocation-free passing path (TUnit.Assertions) by
@​thomhurst in thomhurst/TUnit#6112
### Dependencies
 ... (truncated)

## 1.46.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.46.0 -->

## What's Changed
### Other Changes
* docs: add Rider VSTest conflict troubleshooting by @​smolchanovsky in
thomhurst/TUnit#5989
* Populate generated test metadata with full source spans by @​Copilot
in thomhurst/TUnit#5991
* Add devcontainer configuration by @​Copilot in
thomhurst/TUnit#5995
* fix: treenode filter pre-filter rejects parenthesised segments
(#​6026) by @​thomhurst in thomhurst/TUnit#6027
* fix(engine): isolate per-session state under MTP server-mode
concurrency (#​6001) by @​thomhurst in
thomhurst/TUnit#6025
### Dependencies
* chore(deps): update dependency stackexchange.redis to 2.13.10 by
@​thomhurst in thomhurst/TUnit#5985
* chore(deps): update tunit to 1.45.29 by @​thomhurst in
thomhurst/TUnit#5986
* chore(deps): update dependency mockolate to 3.2.1 by @​thomhurst in
thomhurst/TUnit#5987
* chore(deps): update dependency microsoft.playwright to 1.60.0 by
@​thomhurst in thomhurst/TUnit#5988
* chore(deps): update dependency messagepack to 3.1.6 by @​thomhurst in
thomhurst/TUnit#5992
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5998
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5997
* chore(deps): update verify to 31.17.0 by @​thomhurst in
thomhurst/TUnit#6000
* chore(deps): update verify to 31.18.0 by @​thomhurst in
thomhurst/TUnit#6013
* chore(deps): update dependency microsoft.net.test.sdk to 18.6.0 by
@​thomhurst in thomhurst/TUnit#6016
* chore(deps): update dependency dompurify to v3.4.6 by @​thomhurst in
thomhurst/TUnit#6015
* chore(deps): update dependency dompurify to v3.4.7 by @​thomhurst in
thomhurst/TUnit#6019
* chore(deps): update dependency npgsql to 10.0.3 by @​thomhurst in
thomhurst/TUnit#6020
* chore(deps): update dependency stackexchange.redis to 2.13.17 by
@​thomhurst in thomhurst/TUnit#6021
* chore(deps): update dependency npgsql.entityframeworkcore.postgresql
to 10.0.2 by @​thomhurst in thomhurst/TUnit#6022

## New Contributors
* @​smolchanovsky made their first contribution in
thomhurst/TUnit#5989

**Full Changelog**:
thomhurst/TUnit@v1.45.29...v1.46.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.45.29...v1.48.6).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to IntelliTect/CodingGuidelines that referenced this pull request Jun 2, 2026
Updated [TUnit.Core](https://github.com/thomhurst/TUnit) from 1.45.29 to
1.48.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit.Core's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.48.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.6 -->

## What's Changed
### Other Changes
* fix(sourcegen): fully-qualify Linq calls in params array binding
(#​6140) by @​thomhurst in thomhurst/TUnit#6141
### Dependencies
* chore(deps): update tunit to 1.48.0 by @​thomhurst in
thomhurst/TUnit#6135
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6137
* chore(deps): update dependency polyfill to 10.7.1 by @​thomhurst in
thomhurst/TUnit#6138
* chore(deps): update verify to 31.19.0 by @​thomhurst in
thomhurst/TUnit#6139


**Full Changelog**:
thomhurst/TUnit@v1.48.0...v1.48.6

## 1.48.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.48.0 -->

## What's Changed
### Other Changes
* feat(html-report): baked-in C# syntax highlighting on Source tab by
@​slang25 in thomhurst/TUnit#6132
* feat(analyzers): suppress VSTHRD200 on test and hook methods by
@​thomhurst in thomhurst/TUnit#6123
* fix(source-gen): correct source location for cross-project inherited
tests by @​slang25 in thomhurst/TUnit#6133
* feat(assertions): add WasCalled to tunit mocks assertions by
@​robertcoltheart in thomhurst/TUnit#6126
* feat(arguments): bind array values to a single array test parameter by
@​thomhurst in thomhurst/TUnit#6122
* fix: populate retry/flaky attempt history in HTML report (#​6119) by
@​thomhurst in thomhurst/TUnit#6124
### Dependencies
* chore(deps): update tunit to 1.47.0 by @​thomhurst in
thomhurst/TUnit#6115
* chore(deps): update dependency
microsoft.visualstudio.threading.analyzers to 17.14.15 by @​thomhurst in
thomhurst/TUnit#6134


**Full Changelog**:
thomhurst/TUnit@v1.47.0...v1.48.0

## 1.47.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.47.0 -->

## What's Changed
### Other Changes
* perf(engine): hoist GetParameters and dict-dedup AfterTestDiscovery
hooks by @​thomhurst in thomhurst/TUnit#6062
* perf(engine): hoist GetParameters and drop LINQ in reflection
discovery by @​thomhurst in thomhurst/TUnit#6063
* perf(engine): cache treenode filter path on TestMetadata by
@​thomhurst in thomhurst/TUnit#6064
* perf: use is T pattern in ReflectionExtensions.HasAttribute fallback
(#​6060) by @​thomhurst in thomhurst/TUnit#6066
* perf: replace OrderBy().ToArray() with Array.Sort in
ConstraintKeyScheduler by @​thomhurst in
thomhurst/TUnit#6067
* perf: pool HashSet in WaitingTestIndex.GetCandidatesForReleasedKeys by
@​thomhurst in thomhurst/TUnit#6069
* perf: collapse OfType chains in JUnitXmlWriter (#​6052) by @​thomhurst
in thomhurst/TUnit#6070
* perf(engine): avoid closure allocation in
AfterHookPairTracker.GetOrCreateAfterAssemblyTask (#​6041) by
@​thomhurst in thomhurst/TUnit#6071
* perf: avoid closure allocation in
BeforeHookTaskCache.GetOrCreateBeforeAssemblyTask (#​6040) by
@​thomhurst in thomhurst/TUnit#6073
* perf: use TryAdd in TestDependencyResolver dependency dedupe by
@​thomhurst in thomhurst/TUnit#6068
* perf: replace LINQ Any with foreach in TestGenericTypeResolver
(#​6044) by @​thomhurst in thomhurst/TUnit#6072
* perf: avoid Cast<object>().FirstOrDefault() iterator alloc in
CastHelper (#​6029) by @​thomhurst in
thomhurst/TUnit#6074
* perf(engine): avoid string round-trip when building nested type names
(#​6049) by @​thomhurst in thomhurst/TUnit#6075
* perf(engine): replace Select+ToArray with manual Type[] build (#​6043)
by @​thomhurst in thomhurst/TUnit#6076
* perf(core): replace OfType().FirstOrDefault()/.Any() with foreach in
ClassConstructorHelper by @​thomhurst in
thomhurst/TUnit#6078
* perf(engine): avoid FirstOrDefault iterator alloc in
TestGenericTypeResolver by @​thomhurst in
thomhurst/TUnit#6079
* perf(engine): use SearchValues<char> for reporter filename
sanitization by @​thomhurst in
thomhurst/TUnit#6090
* perf: dedupe TestDataFormatter.FormatArguments with pooled
StringBuilder by @​thomhurst in
thomhurst/TUnit#6088
* perf(engine): use MemoryExtensions.Split for path parsing in
MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6085
* perf(engine): use CollectionsMarshal.GetValueRefOrAddDefault for
dictionary index builds by @​thomhurst in
thomhurst/TUnit#6086
* perf(engine): replace LINQ Where closure with inline filter in
MetadataDependencyExpander BFS by @​thomhurst in
thomhurst/TUnit#6084
* perf(engine): pool StringBuilder in DisplayNameBuilder.FormatArguments
by @​thomhurst in thomhurst/TUnit#6082
* Preserve specialized chaining after null assertions by @​thomhurst in
thomhurst/TUnit#6008
* perf: use EnumerateLines for line splitting in HtmlReportGenerator by
@​thomhurst in thomhurst/TUnit#6089
* perf: collapse Replace chain in TestNameFormatter.BuildTestId by
@​thomhurst in thomhurst/TUnit#6083
* perf: use OrdinalIgnoreCase Contains in HtmlReportGenerator span
mapping by @​thomhurst in thomhurst/TUnit#6093
* perf(assertions): avoid eager interpolated-string alloc in assertion
source ctors by @​thomhurst in
thomhurst/TUnit#6091
* perf: optimize TestNameFormatter argument and bool formatting by
@​thomhurst in thomhurst/TUnit#6095
* perf: use FrozenSet/FrozenDictionary for read-only static lookups by
@​thomhurst in thomhurst/TUnit#6099
* perf: avoid GetCustomAttributes() + LINQ chain for per-property
attribute scans by @​thomhurst in
thomhurst/TUnit#6098
* perf(engine): replace magic-string RequiredAttribute match with type
check in ConstructorHelper by @​thomhurst in
thomhurst/TUnit#6087
* perf(core): replace Select+Func factory chain in DataSourceHelpers by
@​thomhurst in thomhurst/TUnit#6081
* perf: replace LINQ dependency extraction with manual loop by
@​thomhurst in thomhurst/TUnit#6096
* perf(core): avoid string[] alloc in ArgumentFormatter.FormatArguments
by @​thomhurst in thomhurst/TUnit#6080
* perf: use [GeneratedRegex] in MetadataFilterMatcher by @​thomhurst in
thomhurst/TUnit#6094
* perf: dedupe GetSimpleTypeName into shared TypeNameFormatter by
@​thomhurst in thomhurst/TUnit#6097
* fix: remove GitVersion MSBuild task, pin local builds to 99.99.99
(#​6077) by @​thomhurst in thomhurst/TUnit#6101
* HTML Report: source link + code snippet on Source tab (#​5993) by
@​thomhurst in thomhurst/TUnit#6100
* perf(sourcegen): Single-pass attribute classification by @​thomhurst
in thomhurst/TUnit#6111
* perf(core): eliminate per-test allocations in TestDetails/HookMethod
by @​thomhurst in thomhurst/TUnit#6109
* perf: hoist char[] alloc in FsCheckPropertyTestExecutor to static
SearchValues by @​thomhurst in
thomhurst/TUnit#6108
* perf(core): de-LINQ data-source expansion by @​thomhurst in
thomhurst/TUnit#6110
* perf: avoid LINQ chains in TestDependency equality and
MethodDataSourceAttribute method matching by @​thomhurst in
thomhurst/TUnit#6092
* perf(engine): reduce allocations in reflection-mode
discovery/execution by @​thomhurst in
thomhurst/TUnit#6113
* perf(assertions): allocation-free passing path (TUnit.Assertions) by
@​thomhurst in thomhurst/TUnit#6112
### Dependencies
 ... (truncated)

## 1.46.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.46.0 -->

## What's Changed
### Other Changes
* docs: add Rider VSTest conflict troubleshooting by @​smolchanovsky in
thomhurst/TUnit#5989
* Populate generated test metadata with full source spans by @​Copilot
in thomhurst/TUnit#5991
* Add devcontainer configuration by @​Copilot in
thomhurst/TUnit#5995
* fix: treenode filter pre-filter rejects parenthesised segments
(#​6026) by @​thomhurst in thomhurst/TUnit#6027
* fix(engine): isolate per-session state under MTP server-mode
concurrency (#​6001) by @​thomhurst in
thomhurst/TUnit#6025
### Dependencies
* chore(deps): update dependency stackexchange.redis to 2.13.10 by
@​thomhurst in thomhurst/TUnit#5985
* chore(deps): update tunit to 1.45.29 by @​thomhurst in
thomhurst/TUnit#5986
* chore(deps): update dependency mockolate to 3.2.1 by @​thomhurst in
thomhurst/TUnit#5987
* chore(deps): update dependency microsoft.playwright to 1.60.0 by
@​thomhurst in thomhurst/TUnit#5988
* chore(deps): update dependency messagepack to 3.1.6 by @​thomhurst in
thomhurst/TUnit#5992
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5998
* chore(deps): update dependency polyfill to 10.7.0 by @​thomhurst in
thomhurst/TUnit#5997
* chore(deps): update verify to 31.17.0 by @​thomhurst in
thomhurst/TUnit#6000
* chore(deps): update verify to 31.18.0 by @​thomhurst in
thomhurst/TUnit#6013
* chore(deps): update dependency microsoft.net.test.sdk to 18.6.0 by
@​thomhurst in thomhurst/TUnit#6016
* chore(deps): update dependency dompurify to v3.4.6 by @​thomhurst in
thomhurst/TUnit#6015
* chore(deps): update dependency dompurify to v3.4.7 by @​thomhurst in
thomhurst/TUnit#6019
* chore(deps): update dependency npgsql to 10.0.3 by @​thomhurst in
thomhurst/TUnit#6020
* chore(deps): update dependency stackexchange.redis to 2.13.17 by
@​thomhurst in thomhurst/TUnit#6021
* chore(deps): update dependency npgsql.entityframeworkcore.postgresql
to 10.0.2 by @​thomhurst in thomhurst/TUnit#6022

## New Contributors
* @​smolchanovsky made their first contribution in
thomhurst/TUnit#5989

**Full Changelog**:
thomhurst/TUnit@v1.45.29...v1.46.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.45.29...v1.48.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit.Core&package-manager=nuget&previous-version=1.45.29&new-version=1.48.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: convert read-only static HashSet/Dictionary to FrozenSet/FrozenDictionary

1 participant