镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix: bind a tuple row whole to a tuple parameter followed by optional parameters - #7341

Merged
thomhurst merged 3 commits into
mainfrom
issue-7212-tuple-optional
Nov 1, 2026
Merged

thomhurst merged 3 commits into
mainfrom
issue-7212-tuple-optional

Conversation

@thomhurst

@thomhurst thomhurst commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

A row holding only a tuple was spread across the parameters when a tuple parameter was followed by an optional parameter, so ((int, int) pair, int extra = 5) got pair = 25 and failed with a cast error in both modes.

DataUnwrapper.UnwrapWithTypesInternal now keeps the tuple whole when:

  • it is already an instance of the first data parameter's tuple type, and
  • every later data parameter is optional or params (CancellationToken parameters are skipped, as before).

ParameterMetadata.IsParams now also recognises C# 13 params collections (ParamCollectionAttribute). Before, it checked only ParamArrayAttribute, so params IEnumerable<T> still spread the tuple.

Rows that supply a value for every parameter ([(25, 26), 7]) and nested tuple rows (((25, 26), 7)) are spread as before. The type check runs before the optional-parameter scan, so other rows do no extra work.

Typed sources (decision)

A typed IEnumerable<(int, int)> source for the same signature is still rejected by TUnit0001. In source-gen mode the generated factory (DataSourceFactories.FromEnumerable → ToObjectArray) spreads typed tuple rows before DataUnwrapper runs and has no parameter types, so supporting typed rows needs either a new public factory overload or a change to the generated invoker. That is out of scope here and filed as #7340. A new analyzer test records the current diagnostic. The issue's "consistent in both modes" requirement still holds: object[] rows bind whole in both modes, and typed rows are rejected at compile time.

Tests

  • tests/TUnit.TestProject/Bugs/_7212: 8 cases (tuple + optional, two optionals, optional + token, leading token, params array, params collection, supplied optional, nested tuple row) pass in source-gen and reflection mode. Before the fix, 5 of them failed in both modes.
  • Issue7212Tests (engine test): passes.
  • Regression filters, both modes: _7173, _7092, TupleUnwrappingTests, ArgsAsArrayTests, NestedTupleDataSourceTests, EnumerableTupleDataSourceDrivenTests, ClassTupleDataSourceDrivenTests all green.
  • MethodDataSourceAnalyzerTests: all pass.

ClassDataSourceTupleTests fails on main too and is tracked in #7184.

Closes #7212

Summary by CodeRabbit

  • Bug Fixes

    • Fixed method data binding so a tuple is correctly passed as a single argument when followed by optional or params parameters. Supplied optional values and default values are preserved, including when cancellation tokens are present.
  • Tests

    • Added regression coverage for tuple data with optional parameters, cancellation tokens, and params collections.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Walkthrough

Data unwrapping now preserves a single tuple-valued row for the first tuple parameter when later data parameters are optional or params. Params detection also recognizes ParamCollectionAttribute. Regression tests cover binding behavior and typed-source diagnostics.

Changes: Tuple row binding

Layer / File(s) Summary
Recognize params collection parameters
src/TUnit.Core/Models/TestModels/ParameterMetadata.cs
Uncached params detection now recognizes ParamArrayAttribute and ParamCollectionAttribute.
Preserve tuple rows and validate binding
src/TUnit.Engine/Helpers/DataUnwrapper.cs, tests/TUnit.TestProject/Bugs/_7212/*, tests/TUnit.Engine.Tests/Issue7212Tests.cs, tests/TUnit.Analyzers.Tests/MethodDataSourceAnalyzerTests.cs
Data unwrapping preserves a tuple row when later data parameters are optional or params, and skips cancellation tokens when checking those parameters. Tests cover omitted defaults, supplied optional values, nested tuples, and typed-source diagnostics.

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: Moderate · up to d4aa4

A valid tuple row with an omitted params collection can fail when the test runs. Fix or explicitly reject that parameter shape before merging.

A rabbit checks each tuple row,
And keeps it whole when defaults flow.
The tokens pass; the params wait,
The tests confirm each binding state.
Then hops away through fields of green.

@thomhurst

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T21:11:50.970165Z d4aa46e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 3a25a48871

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps

greptile-apps Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the test-count mismatch is fixed.

Summary

Keeps a tuple row whole when it matches the first tuple parameter and all later data parameters can be omitted.

  • A single tuple row stays whole when later parameters can be omitted.

Reviews (4) · Last reviewed commit: "test: expect all eight _7212 cases in Is..." · Reviewed by Greptile

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review

The change is small and correct. I read the diff and the surrounding DataUnwrapper code. I didn't build or run the tests.

  • Guard order: the checks go from cheapest to costliest (dataParameterCount > 1, then the tuple-type check, then IsInstanceOfType, then the optional scan). Rows that don't match skip the extra work.
  • Null and length: values.Length == 1 and IsTuple(values[0]) are already guaranteed by the early return above. firstDataParameterIndex is also always set when dataParameterCount > 1. So there is no null or index risk.
  • AOT: the change uses only IsInstanceOfType and metadata flags, with no new reflection.
  • Tests: they cover tuple plus optional, two optionals, a token before and after, params, a supplied optional, and a nested tuple row. The nested row confirms the old spread behaviour is unchanged.
  • Analyzer test: it records the current TUnit0001 behaviour for typed rows, and Support typed tuple sources for a tuple parameter followed by optional parameters #7340 tracks the follow-up.

Optional, not blocking: the fix is applied at unwrap time, so the typed-source case (#7340) will need a second fix in the factory path. A longer-term approach is to make ToObjectArray in the source-gen factories aware of parameter types, so the spread decision is made in one place.

LGTM.

… or params parameters (#7212)

DataUnwrapper spread a row holding only a tuple whenever the method had
more than one data parameter, so ((int, int) pair, int extra = 5) received
pair = 25 and failed with a cast error in both modes. When the tuple is
already an instance of the first data parameter's tuple type and every
later data parameter is optional or params, the tuple now binds whole and
the defaults apply. Rows with a value for every parameter, and nested
tuple rows, are spread as before.

Typed tuple sources stay rejected by TUnit0001 (follow-up #7340); an
analyzer test records that.
@thomhurst
thomhurst force-pushed the issue-7212-tuple-optional branch from 3a25a48 to 8e4acf3 Compare November 1, 2026 18:11
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review

The fix is small and correct, and I found no blocking issues.

  • The new guard in DataUnwrapper.UnwrapWithTypesInternal is narrow. It needs a single tuple row, a first data parameter that is a tuple type, an exact type match through IsInstanceOfType, and every later data parameter optional or params. Rows like [(25, 26), 7] and nested tuple rows still take the existing path.
  • Skipping CancellationToken parameters when finding the first data parameter is consistent with the existing handling.
  • The tests cover tuple plus optional, two optionals, optional plus token, leading token, params, a supplied optional, and a nested row. They run through an engine test, and the analyzer test records the current TUnit0001 behaviour for typed sources.
  • Typed IEnumerable<(int,int)> sources are still rejected (Support typed tuple sources for a tuple parameter followed by optional parameters #7340). I agree with deferring that, but the two modes now differ in what they accept: object[] rows bind whole, while typed rows are rejected at compile time. That is worth a docs note once Support typed tuple sources for a tuple parameter followed by optional parameters #7340 is resolved.
  • One small suggestion: RemainingDataParametersAreOmittable is only reached after the tuple-type check, so it adds no cost on the hot path. If you ever need to tighten it, there is a design question about a tuple whose arity differs from the declared type, but that is outside this PR.

Looks good to merge once CI is green.

…Params (#7212)

A tuple row followed by 'params IEnumerable<T>' was still spread because
IsParams only recognised ParamArrayAttribute. Also match
ParamCollectionAttribute by name, as ReflectionTestDataCollector does.
@thomhurst

Copy link
Copy Markdown
Owner Author

@codex review

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review of #7341

The fix is well-scoped. The type check runs first, so other rows pay nothing extra. Recognising ParamCollectionAttribute by name is a sensible way to handle target frameworks that lack the type. The analyzer test that records the typed-source limitation, with #7340 filed for it, is a good way to leave that gap documented.

Issue to fix before merge: the engine test count doesn't match the test project.
tests/TUnit.Engine.Tests/Issue7212Tests.cs:18-19 asserts Total == 7 and Passed == 7. TupleParameterWithOptionalParameterTests.cs has 8 test methods, and the PR description also says 8 cases. The filter //TUnit.TestProject.Bugs._7212//* selects all of them, so this engine test should fail in CI with 8 against 7. Change both assertions to 8. The PR says this test passes, but that can't be right with these values. It may have been run against an earlier version of the project.

Minor suggestions

  • IsParamsParameter calls GetCustomAttributesData() on every uncached IsParams access. The impact is small, because it only runs after the tuple-type check passes. It would still be worth populating CachedIsParams at metadata creation if it isn't already.
  • RemainingDataParametersAreOmittable rescans the parameters after the first loop already walked them. Folding the check into the first loop would avoid the second pass. This is optional.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 234cec439c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@thomhurst

Copy link
Copy Markdown
Owner Author

Dispositions for the latest Claude review (comment 6563348124):

  • Engine test count (blocking): fixed in d4aa46e. Both assertions now expect 8. The _7212 filter runs 8 tests locally and all 8 pass.
  • IsParams reflection on uncached access (minor): not changed. CachedIsParams is never set by either mode today, so this predates the PR. The new code reaches it only after the tuple-type and instance checks pass, which is a rare path. It's not worth widening this PR for.
  • Second pass in RemainingDataParametersAreOmittable (optional): not changed. The scan runs only on the narrow matching path, and a separate helper keeps the guard readable.

@thomhurst

Copy link
Copy Markdown
Owner Author

@codex review

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review

The fix is targeted and I found no blocking issues.

What I checked

  • The new tuple-binding condition in DataUnwrapper has three parts. The first data parameter must be a tuple type, the row value must be an instance of it, and every later data parameter must be optional or params. Together they keep the whole-tuple binding narrow. Rows that supply every parameter, and nested tuple rows, still spread as before, and the tests cover both.
  • The type check runs before the optional-parameter scan, so unrelated rows pay no extra cost.
  • Matching ParamCollectionAttribute by name is a reasonable way to avoid a target-framework dependency, and the test for params IEnumerable<int> covers it.
  • Documenting the typed-source limitation with an analyzer test, and filing Support typed tuple sources for a tuple parameter followed by optional parameters #7340 for it, is a sensible scope decision.

Minor suggestions (non-blocking)

  1. IsParamsParameter calls GetCustomAttributesData() whenever CachedIsParams is null. That is reflection, and it allocates on every IsParams call. If source-gen mode always sets the cached value, this only affects reflection mode. Even so, caching the result in a field (as the Cached* pattern does) would keep it off hot paths and out of the AOT/trimming analysis.
  2. One case stays ambiguous by design. (int, int) pair, int extra = 5 with a row [(25, 26)] now always binds the tuple whole. That is the right call given the issue, but a short note in the docs on tuple unwrapping would help users who expected a spread.

Tests cover all eight scenarios in both modes, plus the regression filters. Looks good to merge.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: d4aa46e0ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@thomhurst

Copy link
Copy Markdown
Owner Author

Dispositions for the Claude review of d4aa46e (comment 6563547811). Both notes are non-blocking.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review of #7341

I found no blocking issues. The fix is narrow and well scoped.

What I checked

  • The new tuple-whole check in DataUnwrapper runs only after the cheap IsTupleType and IsInstanceOfType tests. Rows that don't match skip the optional-parameter scan, so the hot path is unchanged for them.
  • Rows that supply every parameter ([(25, 26), 7]) and nested tuple rows are still spread as before. The tests cover both cases.
  • ParameterMetadata.IsParams matches ParamCollectionAttribute by name through GetCustomAttributesData. That avoids a dependency on a type missing from some target frameworks and is trim/AOT-safe.
  • The analyzer test records the current TUnit0001 behaviour for typed tuple rows, and Support typed tuple sources for a tuple parameter followed by optional parameters #7340 tracks the follow-up. That is an honest way to leave the gap.

Suggestions (non-blocking)

  1. IsParams now calls GetCustomAttributesData() on every access when CachedIsParams is null. That can allocate in reflection mode. If it's used in a hot path, cache the result in a lazy field.
  2. When CachedIsParams is populated by the source generator, check that the generator also recognises C# 13 params collections. Your source-gen-mode test for params IEnumerable<int> suggests it does, but a short comment would make that explicit.
  3. The ExpectedResult.Pass count of 8 in Issue7212Tests is hardcoded. That's fine, but it will need updating whenever a case is added to _7212.

The change looks good to merge once CI is green.

eriklieben pushed a commit to eriklieben/erikterm that referenced this pull request Nov 11, 2026
Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.76.0 to
1.81.10.

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

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

## 1.81.10

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

## What's Changed
### Other Changes
* Preserve private type values in generated executable test attributes
by @​thomhurst in thomhurst/TUnit#7667
* feat(sourcegen): inherit XML docs from [AssertionExtension] classes by
@​JohnVerheij in thomhurst/TUnit#7692
### Dependencies
* Update all non-major dependencies to 1.81.5 by @​thomhurst in
thomhurst/TUnit#7690


**Full Changelog**:
thomhurst/TUnit@v1.81.5...v1.81.10

## 1.81.5

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

## What's Changed
### Other Changes
* feat(sourcegen): inherit XML docs from [GenerateAssertion] source
methods by @​JohnVerheij in thomhurst/TUnit#7687
* fix(mocks): stop verification leaving setups on void-shaped members by
@​thomhurst in thomhurst/TUnit#7688
### Dependencies
* Update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7681
* Update dependency OpenTelemetry.Instrumentation.AspNetCore to 1.20.2
by @​thomhurst in thomhurst/TUnit#7685


**Full Changelog**:
thomhurst/TUnit@v1.81.0...v1.81.5

## 1.81.0

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

## What's Changed
### Other Changes
* Extract Windows engine hang dump stacks in CI by @​thomhurst in
thomhurst/TUnit#7584
* Cut STAThreadTests repeats so the Windows reflection pass run fits its
timeout by @​thomhurst in thomhurst/TUnit#7594
* Preserve expected-value semantics when migrating xUnit Assert.Single
by @​thomhurst in thomhurst/TUnit#7586
* Capture Windows loader ownership and thread CPU times by @​thomhurst
in thomhurst/TUnit#7603
* Isolate the full passing engine session from sibling test processes by
@​thomhurst in thomhurst/TUnit#7606
* Remove unused concrete metadata generation chain by @​thomhurst in
thomhurst/TUnit#7569
* Avoid temporary arrays in singleton tuple binding by @​thomhurst in
thomhurst/TUnit#7583
* Fix ParallelTests overlap assertion for late repetitions by
@​thomhurst in thomhurst/TUnit#7600
* Fix nullable generic class method-row analyzer validation by
@​thomhurst in thomhurst/TUnit#7613
* Fix generated property injection into boxed structs by @​thomhurst in
thomhurst/TUnit#7612
* Make Playwright template navigation deterministic by @​thomhurst in
thomhurst/TUnit#7604
* Release objects and complete teardown for dependency-skipped tests by
@​thomhurst in thomhurst/TUnit#7605
* Support typed tuple rows before optional parameters by @​thomhurst in
thomhurst/TUnit#7608
* Cover null rows in generic class type inference by @​thomhurst in
thomhurst/TUnit#7621
* Skip certificate trust preparation for HTTP-only Aspire test resources
by @​thomhurst in thomhurst/TUnit#7618
* Accept convertible typed rows before optional test parameters by
@​thomhurst in thomhurst/TUnit#7619
* Preserve nullable class discovery parity and constructor precedence by
@​thomhurst in thomhurst/TUnit#7614
* Preserve whole tuple rows before omitted trailing arrays by
@​thomhurst in thomhurst/TUnit#7625
* Fix reflection inference for concrete params arrays by @​thomhurst in
thomhurst/TUnit#7627
* Remove obsolete nullable method-row analyzer suppression by
@​thomhurst in thomhurst/TUnit#7626
* Infer generic method arguments from instance data sources by
@​thomhurst in thomhurst/TUnit#7630
* test: cover discarded method-row lifecycle isolation (#​7373) by
@​thomhurst in thomhurst/TUnit#7632
* Allow DI scopes to opt out of resolved object ownership by @​thomhurst
in thomhurst/TUnit#7633
* Give TestBuilder rows explicit cleanup owners by @​thomhurst in
thomhurst/TUnit#7637
* Preserve whole-tuple inference across wrapped and async sources by
@​thomhurst in thomhurst/TUnit#7641
* Fix reported compiler warnings in regression fixtures by @​thomhurst
in thomhurst/TUnit#7645
* fix(core): track external ownership per row scope by @​thomhurst in
thomhurst/TUnit#7635
* Fix remaining regression fixture compiler warnings by @​thomhurst in
thomhurst/TUnit#7646
* Fix generic class argument row edge cases by @​thomhurst in
thomhurst/TUnit#7647
* Preserve sole-tuple inference and runtime conversion parity by
@​thomhurst in thomhurst/TUnit#7643
* Match method data source attributes by fully qualified identity by
@​thomhurst in thomhurst/TUnit#7649
* Treat null method data sources as empty in both execution modes by
@​thomhurst in thomhurst/TUnit#7652
* Fix xUnit proper-set migration operands and strictness by @​thomhurst
in thomhurst/TUnit#7653
* Fix mock setup identifier collisions by @​thomhurst in
thomhurst/TUnit#7658
* fix(generator): qualify built-in data-source row classification by
@​thomhurst in thomhurst/TUnit#7651
* Capture macOS native runtime crashes for diagnosis by @​thomhurst in
thomhurst/TUnit#7659
* Restore nullable diagnostics in mock generated-code regression guards
by @​thomhurst in thomhurst/TUnit#7661
* Avoid mock predicate conversion local name collisions by @​thomhurst
in thomhurst/TUnit#7655
* Install browsers with the resolved .NET Playwright package by
@​thomhurst in thomhurst/TUnit#7673
* Remove nullable and assertion warnings from unit tests by @​thomhurst
in thomhurst/TUnit#7670
* Preserve keyword escapes in generated attribute factory type names by
@​thomhurst in thomhurst/TUnit#7669
* Fix default mock argument matching by @​thomhurst in
thomhurst/TUnit#7676
* Preserve category and property filters on generic discovery failures
by @​thomhurst in thomhurst/TUnit#7663
* Preserve keyword escapes in generated type expressions by @​thomhurst
in thomhurst/TUnit#7675
* Encapsulate row lifetime and constructor state replay by @​thomhurst
in thomhurst/TUnit#7678
* Diagnose unsupported span params on test methods by @​thomhurst in
thomhurst/TUnit#7679
 ... (truncated)

## 1.80.0

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

## What's Changed
### Other Changes
* Share evaluated constructor-row state across discovery modes by
@​thomhurst in thomhurst/TUnit#7497
* Diagnose static data-source properties in inaccessible containing
types by @​thomhurst in thomhurst/TUnit#7503
* Extract typed-row binding and verify invocation parity by @​thomhurst
in thomhurst/TUnit#7507
* Accept omitted optional MethodDataSource arguments in TUnit0001 by
@​thomhurst in thomhurst/TUnit#7486
* Preserve null-containing tuples from static method data sources by
@​thomhurst in thomhurst/TUnit#7469
* Fix dependencies on deferred enumeration tests by @​thomhurst in
thomhurst/TUnit#7471
* Preserve DI scope ownership and synchronize concurrent property
registration by @​thomhurst in
thomhurst/TUnit#7476
* Infer typed row generic arguments through interfaces and base classes
by @​thomhurst in thomhurst/TUnit#7508
* Keep session cleanup from disposing another session’s data sources by
@​thomhurst in thomhurst/TUnit#7509
* Fix recursive generated tuple argument conversions by @​thomhurst in
thomhurst/TUnit#7515
* Share generic class row selection and pairing policy by @​thomhurst in
thomhurst/TUnit#7498
* Raise data-source delegates at test lifecycle stages by @​thomhurst in
thomhurst/TUnit#7521
* Fix class argument literals to use constructor parameter types by
@​thomhurst in thomhurst/TUnit#7496
* Accept numeric widening for single reference-tuple data parameters by
@​thomhurst in thomhurst/TUnit#7510
* fix(core): preserve optional F# async support without AOT warnings by
@​thomhurst in thomhurst/TUnit#7526
* Fix timeouts for synchronously blocking test bodies by @​thomhurst in
thomhurst/TUnit#7527
* Fix Native AOT getters for generic test class property metadata by
@​thomhurst in thomhurst/TUnit#7524
* Refresh stale core generator snapshots by @​thomhurst in
thomhurst/TUnit#7549
* Infer generic class types from inherited literal arguments by
@​thomhurst in thomhurst/TUnit#7544
* Make duplicate-stop cancellation regression independent of thread-pool
scheduling by @​thomhurst in
thomhurst/TUnit#7546
* Fix colliding generator diagnostic IDs by @​thomhurst in
thomhurst/TUnit#7538
* Fix generic array binding inside tuple data-source parameters by
@​thomhurst in thomhurst/TUnit#7541
* Discover AOT converters from method data source return types by
@​thomhurst in thomhurst/TUnit#7547
* Check tuple conversion analyzer policy against runtime binding by
@​thomhurst in thomhurst/TUnit#7559
* Deduplicate disposal span callbacks on .NET 8 by @​thomhurst in
thomhurst/TUnit#7557
* Preserve generic tuple rows from instance data sources by @​thomhurst
in thomhurst/TUnit#7548
* Expect source operators to bind in AOT in the tuple conversion matrix
by @​thomhurst in thomhurst/TUnit#7580
* Preserve containing generic types in TUnit0001 diagnostics by
@​thomhurst in thomhurst/TUnit#7563
* Populate reflection class property metadata by @​thomhurst in
thomhurst/TUnit#7550
* Verify every generic class/method argument pair executes once by
@​thomhurst in thomhurst/TUnit#7558
* Exclude indexers from generated class property metadata by @​thomhurst
in thomhurst/TUnit#7560
* Fix synchronous factory timeout cancellation classification by
@​thomhurst in thomhurst/TUnit#7561
* Add packaged F# async trimming smoke coverage by @​thomhurst in
thomhurst/TUnit#7562
* Remove unused metadata generation entry points by @​thomhurst in
thomhurst/TUnit#7570
* Remove unused streaming test builder path by @​thomhurst in
thomhurst/TUnit#7535
* Isolate test registration callback failures by @​thomhurst in
thomhurst/TUnit#7556

### Dependencies
* Update mcr.microsoft.com/dotnet/sdk Docker tag to v11 by @​thomhurst
in thomhurst/TUnit#7513
* Update dependency Microsoft.Kiota.Abstractions to 2.1.6 by @​thomhurst
in thomhurst/TUnit#7512
* Update all non-major dependencies to 1.79.0 by @​thomhurst in
thomhurst/TUnit#7528
* Update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7536


**Full Changelog**:
thomhurst/TUnit@v1.79.0...v1.80.0

## 1.79.0

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

## What's Changed
### Other Changes
* test(sourcegen): parse fixtures as a real build in all generator test
harnesses by @​thomhurst in thomhurst/TUnit#7319
* test(sourcegen): fix net472 compile of AotConverterScanTests
obsolete-conversion fixture by @​thomhurst in
thomhurst/TUnit#7330
* fix(sourcegen): emit typeof(Nullable<>) for a T? parameter of a
generic test method by @​thomhurst in
thomhurst/TUnit#7322
* test: fix ClassDataSourceTupleTests to exercise class-level tuple
unwrapping by @​thomhurst in
thomhurst/TUnit#7318
* fix(fsharp): pin FSharp.Core in TUnit.Assertions.FSharp independent of
the building SDK by @​thomhurst in
thomhurst/TUnit#7321
* fix(sourcegen): pick MethodDataSource overloads declared on base types
like reflection by @​thomhurst in
thomhurst/TUnit#7323
* fix(reflection): close generic methods over a typed data source's
declared types without [GenerateGenericTest] by @​thomhurst in
thomhurst/TUnit#7324
* fix(engine): run every overload of a [Test] method in filtered runs by
@​thomhurst in thomhurst/TUnit#7332
* fix: bind a tuple row whole to a tuple parameter followed by optional
parameters by @​thomhurst in
thomhurst/TUnit#7341
* fix(core): keep and dispose data-source roots when object-graph
tracking throws by @​thomhurst in
thomhurst/TUnit#7342
* fix(engine): lower default maximum parallel tests to 2x processor
count by @​thomhurst in thomhurst/TUnit#7354
* ci: cut duplicate TFM and packaging work from the Windows and macOS
jobs by @​thomhurst in thomhurst/TUnit#7357
* ci: run engine tests in their own job and drop the per-child test-host
relaunch by @​thomhurst in thomhurst/TUnit#7364
* fix(sourcegen): split untyped class data source rows by the generic
class type they infer by @​thomhurst in
thomhurst/TUnit#7339
* fix(engine): read a generic class's own class-level [MethodDataSource]
member on the closed class by @​thomhurst in
thomhurst/TUnit#7336
* fix(analyzers): TUnit0001 unwraps only the Func/TestDataRow layers the
runtime removes by @​thomhurst in
thomhurst/TUnit#7347
* test: make SharedType.None leakage tests independent of build order by
@​thomhurst in thomhurst/TUnit#7385
* fix(generic): infer method type arguments from [Arguments<T>] rows in
both modes by @​thomhurst in
thomhurst/TUnit#7343
* fix(generic): infer class type arguments through T[] constructor
parameters from any class row by @​thomhurst in
thomhurst/TUnit#7346
* fix(engine): await the Task of async runtime dynamic tests by
@​thomhurst in thomhurst/TUnit#7363
* feat(engine): add dispose spans for shared data-source objects by
@​thomhurst in thomhurst/TUnit#7396
* fix(engine): stop copying build-time output to TestSessionContext by
@​thomhurst in thomhurst/TUnit#7397
* feat(mocks): argument-aware Returns for Task/ValueTask members by
@​thomhurst in thomhurst/TUnit#7404
* fix(generic): a type-free class [Arguments] row lets method rows infer
T, with matching constructor binding in both modes by @​thomhurst in
thomhurst/TUnit#7392
* feat(scripts): finish open loop PRs before starting new issues by
@​thomhurst in thomhurst/TUnit#7423
* fix(mocks): preserve nullable generic constraints by @​thomhurst in
thomhurst/TUnit#7414
* Retain class sources sharing an inferred generic instantiation by
@​thomhurst in thomhurst/TUnit#7420
* Fix reflection data source overloads with omitted optional arguments
by @​thomhurst in thomhurst/TUnit#7421
* feat(playwright): honor HEADED and BROWSER environment variables by
@​thomhurst in thomhurst/TUnit#7395
* docs: enable Windows long paths before worktree checkout by
@​thomhurst in thomhurst/TUnit#7416
* Fix duplicate dynamic builder invocation in reflection mode by
@​thomhurst in thomhurst/TUnit#7424
* fix(mocks): bind explicit method type arguments on
Mock.Of<IGeneric<X>>() by @​thomhurst in
thomhurst/TUnit#7406
* fix(mocks): Is<T>(predicate) passes T, not T?, for non-nullable T by
@​thomhurst in thomhurst/TUnit#7405
* fix(engine): deliver row builder-context events to the test and raise
OnDispose once per test (#​7381) by @​thomhurst in
thomhurst/TUnit#7384
* fix: report generic classes whose data cannot infer types at compile
time by @​thomhurst in thomhurst/TUnit#7425
* fix(core): hold shared instances fetched while runtime tests register
by @​thomhurst in thomhurst/TUnit#7391
* fix(mocks): match null literals in generated predicate overloads by
@​thomhurst in thomhurst/TUnit#7415
* fix(mocks): qualify extern-aliased types with their alias in generated
code by @​thomhurst in thomhurst/TUnit#7403
* fix(generic): fail wrongly sized [GenerateGenericTest] in
source-generated mode by @​thomhurst in
thomhurst/TUnit#7344
* fix(sourcegen): generate a data source factory for
[InstanceMethodDataSource] (#​7225) by @​thomhurst in
thomhurst/TUnit#7348
* fix(aspire): preserve caller cancellation over startup cleanup faults
by @​thomhurst in thomhurst/TUnit#7447
* fix(tests): remove polling throughput requirement on shared runners by
@​thomhurst in thomhurst/TUnit#7448
* fix(html-reporter): scope report state per session when sessions
overlap by @​thomhurst in thomhurst/TUnit#7400
* fix(analyzers): validate class data against TestConstructor by
@​thomhurst in thomhurst/TUnit#7449
* Infer generic method types from typed array rows in both discovery
modes by @​thomhurst in thomhurst/TUnit#7460
* Share generic method inference policy between discovery modes by
@​thomhurst in thomhurst/TUnit#7455
 ... (truncated)

## 1.78.0

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

## What's Changed
### Other Changes
* fix: Should().HaveSingleItem() returns the single item by @​mvanhorn
in thomhurst/TUnit#7035
* feat(mocks): TM011 analyzer + code fix to declare mocks with the
generated mock type by @​thomhurst in
thomhurst/TUnit#7311
* fix(sourcegen): skip [Obsolete(error: true)] conversion operators in
AotConverterGenerator by @​thomhurst in
thomhurst/TUnit#7317
### Dependencies
* chore(deps): bump joi from 17.13.8 to 17.13.9 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7312
* chore(deps): bump follow-redirects from 1.16.1 to 1.16.2 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7313


**Full Changelog**:
thomhurst/TUnit@v1.77.0...v1.78.0

## 1.77.0

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

## What's Changed
### Other Changes
* fix(engine): invoke OnTestRegistered on property-injected data sources
by @​thomhurst in thomhurst/TUnit#7292
* fix(sourcegen): globally qualify type names in property injection
output by @​lucaxchaves in thomhurst/TUnit#7291
* test(sourcegen): snapshot property injection output for Core.*
namespaces by @​thomhurst in
thomhurst/TUnit#7293
* fix(aspire): detach kept resources from removed resources in
ResourcesToRemove by @​thomhurst in
thomhurst/TUnit#7295
* feat(engine): report unobserved task exceptions in session results by
@​thomhurst in thomhurst/TUnit#7296
* fix(mocks): rename method type parameters that collide with the mocked
type's by @​thomhurst in thomhurst/TUnit#7303
* feat(mocks): TM010 analyzer + code fix for Mock.Of<T>() -> T.Mock() by
@​thomhurst in thomhurst/TUnit#7307
* feat(playwright): failure screenshots/traces and shared-browser
disconnect diagnostics by @​thomhurst in
thomhurst/TUnit#7309


**Full Changelog**:
thomhurst/TUnit@v1.76.45...v1.77.0

## 1.76.45

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

## What's Changed
### Other Changes
* chore(docs): remark Forgejo test summary compatability by @​koryphaee
in thomhurst/TUnit#7272
* fix(aspire): cancel and join startup waits (#​7277) by @​thomhurst in
thomhurst/TUnit#7279
* fix(aspire): follow DCP runtime instances when reading resource logs
by @​thomhurst in thomhurst/TUnit#7283
### Dependencies
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7259
* chore(deps): update dependency imposter to 1.0.7 by @​thomhurst in
thomhurst/TUnit#7264
* chore(deps): update dependency imposter to 1.0.8 by @​thomhurst in
thomhurst/TUnit#7265
* chore(deps): update dependency polly to 8.8.1 by @​thomhurst in
thomhurst/TUnit#7266
* chore(deps): update dependency awssdk.sqs to 4.0.100.21 by @​thomhurst
in thomhurst/TUnit#7267
* chore(deps): update dependency node-forge to v1.4.1 by @​thomhurst in
thomhurst/TUnit#7268
* chore(deps): update dependency qs to v6.17.0 by @​thomhurst in
thomhurst/TUnit#7270
* chore(deps): bump postcss-selector-parser from 6.1.4 to 6.1.5 in /docs
by @​dependabot[bot] in thomhurst/TUnit#7269
* chore(deps): update dependency node-forge to v1.4.2 by @​thomhurst in
thomhurst/TUnit#7273
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7274
* chore(deps): update dependency minimatch to v11 by @​thomhurst in
thomhurst/TUnit#7275
* chore(deps): update dependency minimatch to v11.0.1 by @​thomhurst in
thomhurst/TUnit#7276
* chore(deps): update dependency node to v26 by @​thomhurst in
thomhurst/TUnit#7278
* chore(deps): update dependency minimatch to v11.0.2 by @​thomhurst in
thomhurst/TUnit#7280


**Full Changelog**:
thomhurst/TUnit@v1.76.28...v1.76.45

## 1.76.28

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

## What's Changed
### Other Changes
* Remove legacy JSON output implementation by @​Saad-elnagar in
thomhurst/TUnit#7234
* fix(engine): drop row-scoped data sources from failed test metadata by
@​kenny-ish in thomhurst/TUnit#7079
* Merge the analyzer release tables under one New Rules section (RS2007)
by @​bfs2021 in thomhurst/TUnit#7174
* fix: release finished test instances before session end by @​thomhurst
in thomhurst/TUnit#7262
* fix: never hand out a disposed shared data-source instance by
@​thomhurst in thomhurst/TUnit#7248
### Dependencies
* chore(deps): update all non-major dependencies to 1.76.0 by
@​thomhurst in thomhurst/TUnit#7233
* chore(deps): bump follow-redirects from 1.16.0 to 1.16.1 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7232
* chore(deps): bump launch-editor from 2.14.1 to 2.14.2 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7231
* chore(deps): update all non-major dependencies to 1.20.1 by
@​thomhurst in thomhurst/TUnit#7235
* chore(deps): update dependency awssdk.sqs to 4.0.100.20 by @​thomhurst
in thomhurst/TUnit#7236
* chore(deps): update dependency microsoft.playwright to 1.64.0 by
@​thomhurst in thomhurst/TUnit#7237
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7238
* chore(deps): update dependency path-to-regexp to v9 by @​thomhurst in
thomhurst/TUnit#7241
* chore(deps): update all non-major dependencies by @​thomhurst in
thomhurst/TUnit#7242
* chore(deps): update dependency serialize-javascript to v7.1.3 by
@​thomhurst in thomhurst/TUnit#7243
* chore(deps): update dependency imposter to 1.0.4 by @​thomhurst in
thomhurst/TUnit#7244
* chore(deps): update dependency stackexchange.redis to 3.4.20 by
@​thomhurst in thomhurst/TUnit#7245
* chore(deps): update dependency serialize-javascript to v7.1.4 by
@​thomhurst in thomhurst/TUnit#7246
* chore(deps): update dependency imposter to 1.0.5 by @​thomhurst in
thomhurst/TUnit#7247
* chore(deps): update all non-major dependencies to 13.6.4 by
@​thomhurst in thomhurst/TUnit#7251
* chore(deps): update dependency imposter to 1.0.6 by @​thomhurst in
thomhurst/TUnit#7258
* chore(deps): bump fast-uri from 3.1.8 to 3.1.9 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7253
* chore(deps): bump body-parser from 1.20.6 to 1.20.9 in /docs by
@​dependabot[bot] in thomhurst/TUnit#7252

## New Contributors
* @​Saad-elnagar made their first contribution in
thomhurst/TUnit#7234
* @​kenny-ish made their first contribution in
thomhurst/TUnit#7079
* @​bfs2021 made their first contribution in
thomhurst/TUnit#7174

**Full Changelog**:
thomhurst/TUnit@v1.76.0...v1.76.28

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

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit&package-manager=nuget&previous-version=1.76.0&new-version=1.81.10)](https://github.com/proxy/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 <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This was referenced Nov 11, 2026

This branch was previously deployed

1 inactive deployment
Pull Requests — d4aa46e0 Deployed Nov 1, 2026 by thomhurst via modularpipeline (macos-latest) #20550
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.

A tuple parameter followed by an optional parameter is spread instead of bound whole

1 participant