Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: thomhurst/TUnit
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.56.35
Choose a base ref
...
head repository: thomhurst/TUnit
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.57.0
Choose a head ref
  • 18 commits
  • 87 files changed
  • 3 contributors

Commits on Jun 24, 2026

  1. chore(deps): update tunit to 1.56.35 (#6306)

    Co-authored-by: Renovate Bot <[email protected]>
    thomhurst and renovate-bot authored Jun 24, 2026
    Configuration menu
    Copy the full SHA
    e1f72ce View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    cea5abe View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    e2b3592 View commit details
    Browse the repository at this point in the history
  4. chore(deps): update dependency opentelemetry.instrumentation.aspnetco…

    …re to 1.16.0 (#6309)
    
    Co-authored-by: Renovate Bot <[email protected]>
    thomhurst and renovate-bot authored Jun 24, 2026
    Configuration menu
    Copy the full SHA
    a71b45a View commit details
    Browse the repository at this point in the history
  5. chore(deps): update dependency qs to v6.15.3 (#6310)

    Co-authored-by: Renovate Bot <[email protected]>
    thomhurst and renovate-bot authored Jun 24, 2026
    Configuration menu
    Copy the full SHA
    31a0680 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    8180f99 View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    232ab7e View commit details
    Browse the repository at this point in the history

Commits on Jun 25, 2026

  1. Configuration menu
    Copy the full SHA
    2cd32f2 View commit details
    Browse the repository at this point in the history

Commits on Jun 26, 2026

  1. Configuration menu
    Copy the full SHA
    0564258 View commit details
    Browse the repository at this point in the history

Commits on Jun 27, 2026

  1. Configuration menu
    Copy the full SHA
    86c110d View commit details
    Browse the repository at this point in the history

Commits on Jun 28, 2026

  1. Configuration menu
    Copy the full SHA
    f861209 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    1b0d3ff View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    cbaa4bc View commit details
    Browse the repository at this point in the history
  4. chore(deps): bump http-proxy-middleware from 2.0.9 to 2.0.10 in /docs (

    …#6303)
    
    Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.9 to 2.0.10.
    - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases)
    - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.10/CHANGELOG.md)
    - [Commits](chimurai/http-proxy-middleware@v2.0.9...v2.0.10)
    
    ---
    updated-dependencies:
    - dependency-name: http-proxy-middleware
      dependency-version: 2.0.10
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jun 28, 2026
    Configuration menu
    Copy the full SHA
    eaddb68 View commit details
    Browse the repository at this point in the history
  5. perf(sourcegen): consolidate per-file ModuleInitializers into merged …

    ….cctor (#6226) (#6286)
    
    * perf(sourcegen): consolidate per-file ModuleInitializers into merged .cctor (#6226)
    
    Several generators emitted a separate [ModuleInitializer] per file/class, each
    costing a type load + serial tier-0 JIT at module load. Fold them into the
    existing consolidated-.cctor pattern: per-file static field initializers on
    shared partial shells declared by InfrastructureGenerator, triggered once via
    RunClassConstructor.
    
    - InfrastructureGenerator declares + triggers 4 new shells in TUnit.Generated:
      TUnit_PropertyRegistration, TUnit_ConverterRegistration,
      TUnit_StaticPropertyRegistration, TUnit_DynamicTestRegistration.
    - PropertyInjection (4 sites), AotConverter, StaticProperty and DynamicTests
      now contribute `static readonly int _r_X = Registry.Register(...)` fields
      instead of per-file [ModuleInitializer] methods.
    - 5 registry Register/RegisterDynamic methods return int (dummy 0) so they can
      be used as field initializers (matches existing RegisterEntries/RegisterHook).
    
    Registrations are emitted eager-inline with no factory lambdas: a factory
    lambda would add one compiler-generated method (a new JIT call) per type. The
    test/hook generators are unchanged - they already consolidate into a merged
    .cctor and deliberately keep a lazy `() => Source.Entries` factory to defer
    heavy, parallelizable metadata construction to discovery.
    
    Free aggregation via the compiler's partial-class merge - no .Collect() fan-in
    added to the incremental pipeline. Reflection mode is unaffected: registry
    consumer methods are unchanged and reflection never calls Register.
    
    * refactor(sourcegen): tidy registration-shell emission
    
    - InfrastructureGenerator: emit the 6 registration-shell declarations and
      their RunClassConstructor triggers from one shared RegistrationShells list
      instead of 12 hand-written AppendLine pairs (output byte-identical).
    - AotConverterGenerator: rename `registrations` -> `converterClassNames` now
      that the list holds class names rather than registration statements.
    
    * fix(sourcegen): make consolidated registration field names collision-proof
    
    Addresses code review on #6286.
    
    - StaticPropertyInitializationGenerator: `SafeName` maps every non-alphanumeric
      char to `_`, so two distinct types whose fully-qualified names differ only in
      `.` vs `_` (e.g. A_B.C vs A.B_C) produced the same `_r_...` field in the single
      merged `TUnit_StaticPropertyRegistration` .cctor -> duplicate-field compile
      error. Append a stable per-build hash of the FQN + property name.
    
    - DynamicTestsGenerator: `_r_Dynamic_{class}_{method}` (and the generated file
      name) collided for same-named overloads on one class, or same-minimal-name
      classes in different namespaces. Add a stable hash of the fully-qualified
      type + method + line to both the file name and the field, so such cases now
      generate distinct files/fields instead of failing.
    
    * fix(sourcegen): collision-proof + deterministic registration field names
    
    Addresses follow-up code review on #6286.
    
    - PropertyInjectionSourceGenerator: the four `_r_..._PropSource` / `_InitProps`
      (and Generic variants) fields on the merged `TUnit_PropertyRegistration` .cctor
      were keyed only on `GetSafeClassName`, which collapses every separator to `_`.
      Two types whose FQNs differ only in `.` vs `_` produced a duplicate field ->
      compile error in user code. Append a stable hash of the full type name, matching
      the StaticProperty/Dynamic fix in 106a842.
    
    - Replace `string.GetHashCode()` disambiguators (randomized per-process since
      .NET Core 2.1) with the existing deterministic FNV-1a `FileNameHelper.
      GetStableHashCode` across PropertyInjection, StaticProperty and DynamicTests.
      Generated hint/field names now stay stable across compiler restarts, preserving
      Roslyn's incremental cache. `GetStableHashCode` made public for reuse.
    
    Property/Static/Dynamic outputs aren't snapshotted; Infra/AotConverter snapshots
    unchanged (untouched generators). Snapshot suite green.
    
    * fix(sourcegen): wrap AotConverter registration in explicit namespace block
    
    Code-review finding B: AotConverterGenerator emitted its converter classes
    and the TUnit_ConverterRegistration partial under a file-scoped
    `namespace TUnit.Generated;`. While functionally correct, this diverged from
    the shell pattern used by InfrastructureGenerator and
    StaticPropertyInitializationGenerator, which use an explicit
    `namespace TUnit.Generated { ... }` block. Convert to the block form so the
    partial reliably merges with the shell and the codebase stays consistent.
    
    Finding A (PropertyInjectionSourceGenerator field-name collision) was already
    resolved in commit 85d1f7f: all four merged-partial field names
    (_PropSource, _InitProps, and their _Generic variants) already carry a
    deterministic FileNameHelper.GetStableHashCode suffix. No further change
    needed.
    
    * fix(sourcegen): make static property initializer method names FQN-unique
    
    The static property initializer method name was built from the simple
    ContainingType.Name only, while the registration field name already used
    an FQN-based stable hash. Two types sharing a simple name in different
    namespaces (e.g. Acme.Tests.MyFixture and Acme.Shared.MyFixture) each with
    a same-named static property collapsed to ONE generated initializer method
    (hardcoding the first type's FQN), yet emitted two field registrations both
    pointing at that single method. The second type's property was then
    initialized against the wrong type silently.
    
    Hoist the per-FQN stable hash into a shared helper and suffix the method
    name with it, so distinct FQNs generate distinct methods and the field
    registration references the matching hash-suffixed method name.
    
    * refactor(sourcegen): consolidate SafeName into FileNameHelper
    thomhurst authored Jun 28, 2026
    Configuration menu
    Copy the full SHA
    b0b60ea View commit details
    Browse the repository at this point in the history
  6. fix: resolve CS0121 IsEqualTo ambiguity on .NET 8 SDK (#6296) (#6313)

    * fix: resolve CS0121 IsEqualTo ambiguity on .NET 8 SDK (#6296)
    
    The cross-type IsEqualTo<TValue,TOther> / IsNotEqualTo<TValue,TOther>
    overloads were deprioritized against their same-type siblings only via
    [OverloadResolutionPriority]. That attribute is honored by the Roslyn
    compiler shipped in the .NET 9 SDK and later, NOT by LangVersion, so
    consumers who pin the .NET 8 SDK via global.json (whose Roslyn predates
    ORP) still got CS0121 on same-type calls like Assert.That(guid).IsEqualTo(guid)
    -- even with the LangVersion=latest bump from #6282, which is a no-op here.
    
    Give the cross-type overloads a trailing `params object[]` so they are
    applicable only in expanded form and lose to the normal-form same-type
    overload via the "normal beats expanded" tie-break, which every Roslyn
    version honors. The [CallerArgumentExpression] capture is preserved; ORP
    is kept as a redundant signal. Genuine cross-type value-object calls
    (e.g. Assert.That(productCode).IsEqualTo("X")) are unaffected.
    
    Verified end-to-end by packing the fix and consuming it from a project
    pinned to SDK 8.0.422: both same-type and value-object calls now compile
    and pass. PublicAPI snapshots updated; regression tests added.
    
    * docs: trim duplicated rationale comments in cross-type IsEqualTo overloads
    
    * fix: prevent params marker from swallowing trailing args (#6313 review)
    
    The cross-type IsEqualTo/IsNotEqualTo overloads used `params object[] _`
    to force expanded-form-only applicability (so same-type calls win the
    "normal beats expanded" tie-break). But `object[]` is applicable to ANY
    trailing argument, so a call like
    
        Assert.That(productCode).IsEqualTo("x", StringComparer.OrdinalIgnoreCase)
    
    bound to the cross-type overload and silently DISCARDED the comparer — a
    false-pass footgun for a test framework. Before #6296 this was a compile
    error.
    
    Replace the element type with a dedicated `CrossTypeOverloadMarker` that
    has no accessible constructor. The empty-expanded-form tie-break still
    works (verified on the .NET 8 SDK's Roslyn), but a stray trailing argument
    is a compile error again instead of being swallowed.
    
    - Add regression tests confirming the same-type-with-comparer overload
      still binds and the comparer is applied.
    - Regenerate PublicAPI snapshots (all 4 TFMs).
    thomhurst authored Jun 28, 2026
    Configuration menu
    Copy the full SHA
    aff22c9 View commit details
    Browse the repository at this point in the history
  7. chore(docs): apply Codacy markdownlint fixes (#6284)

    * chore(docs): apply Codacy markdownlint fixes
    
    Apply Codacy code-quality patch across docs and instruction files:
    - MD022/MD032: blank lines surrounding headings and lists
    - MD034: wrap bare URLs in angle brackets (copilot-instructions.md)
    - MD026: strip trailing colons from some headings (requirements-start.md)
    
    Docs/.claude/.github only; no source or runtime changes.
    
    * chore(docs): fix MD047 single trailing newline in docs
    
    * chore(docs): add EOF newlines to two command files; restore CONTRIBUTING legal-notice period
    
    * chore(docs): finish MD026/MD022 fixes in requirements-start.md
    thomhurst authored Jun 28, 2026
    Configuration menu
    Copy the full SHA
    fdc8e49 View commit details
    Browse the repository at this point in the history
  8. +semver:minor - fix(mocks): generate mock for qualified-name X.Mock()…

    … calls (#6298) (#6314)
    
    * fix(mocks): generate mock for qualified-name X.Mock() calls (#6298)
    
    A fully-qualified reference like `Namespace.IFoo.Mock()` parses as a
    MemberAccessExpressionSyntax in expression position, not a
    QualifiedNameSyntax (which only appears in type/using contexts). The
    discovery predicate gated the left-hand side of `X.Mock()` on node kind
    and so dropped this form, leaving the mock surface ungenerated (CS1061).
    
    Drive discovery off the resolved symbol instead of the syntactic shape:
    the predicate now matches any `<expr>.Mock()`, and the existing semantic
    transform already bails unless the LHS resolves to an INamedTypeSymbol,
    filtering out variables, fields, and namespaces.
    
    Adds a snapshot test for the qualified-name form and a runtime
    regression test mirroring the issue repro.
    
    * docs(mocks): tighten Issue6298 regression test comment
    
    * test(mocks): clarify intentional using in Issue6298 regression test
    
    Addresses review feedback on #6314. Removing the 'using Issue6298Namespace;'
    directive breaks compilation because the generated mock setup/proxy members
    are emitted into the interface namespace. Added a comment documenting that the
    using is required and that the qualified-name call site is the thing under test.
    thomhurst authored Jun 28, 2026
    Configuration menu
    Copy the full SHA
    e0061ab View commit details
    Browse the repository at this point in the history
Loading