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.21.6
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.21.20
Choose a head ref
  • 14 commits
  • 80 files changed
  • 3 contributors

Commits on Mar 23, 2026

  1. fix: respect TUnitImplicitUsings set in Directory.Build.props (#5225)

    * perf: add startup performance measurement scripts
    
    Add PowerShell scripts for measuring and comparing TUnit startup
    performance, useful for tracking JIT overhead improvements:
    
    - measure-startup.ps1: wall-clock timing with statistical analysis
    - count-generated-methods.ps1: static analysis of generated method counts
    - compare-branches.ps1: side-by-side branch comparison
    - measure-jit.ps1: JIT trace collection and generated method analysis
    
    * fix: respect TUnitImplicitUsings set in Directory.Build.props (#5208)
    
    Add conditions to avoid overwriting user-set property values, matching
    the pattern already used in TUnit.Mocks.props.
    thomhurst authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    1575e72 View commit details
    Browse the repository at this point in the history
  2. chore(deps): update tunit to 1.21.6 (#5228)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    1d912c5 View commit details
    Browse the repository at this point in the history
  3. chore(deps): update dependency gitversion.msbuild to 6.7.0 (#5229)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    638fdba View commit details
    Browse the repository at this point in the history
  4. feat: covariant assertions for interfaces and non-sealed classes (#5226)

    * feat: covariant assertions for interfaces and non-sealed classes
    
    When the target type of a [GenerateAssertion] or [AssertionExtension] is an
    interface or non-sealed class, the generated extension method now uses a
    generic type parameter with a constraint instead of the concrete type:
    
      // Before:
      public static Assertion HasFoo(this IAssertionSource<IInterface> source)
    
      // After:
      public static Assertion HasFoo<TActual>(this IAssertionSource<TActual> source)
          where TActual : IInterface
    
    This allows assertions defined for a base type to work seamlessly on derived
    types without requiring explicit casts.
    
    Covariance is applied only when safe:
    - Interfaces and non-sealed classes: yes
    - Value types, sealed classes, arrays, type parameters: no
    - Types containing unresolved type parameters (e.g., Lazy<T>): no
    
    Closes #4830
    
    * refactor: extract shared CovarianceHelper, fix missing ContainsTypeParameter check
    
    - Extract duplicated covariance logic into CovarianceHelper static class
    - Fix bug: AssertionExtensionGenerator was missing ContainsTypeParameter
      check, which would incorrectly treat types like Lazy<T> as covariant
    - Remove dead code: unused isMultiParameterGeneric and isNullableReferenceType
    - Eliminate unnecessary List<string> allocation in non-covariant path
    - Remove redundant typeParamDisplay computation in AssertionExtensionGenerator
    
    * fix: avoid TActual name collision with existing generic parameters
    
    Use CovarianceHelper.GetCovariantTypeParamName() to pick a type parameter
    name that doesn't conflict with the method's existing generic parameters.
    Falls back to TActual_ (with appended underscores) if TActual is taken.
    
    * chore: update public API snapshots for covariant assertion signatures
    
    * refactor: minor cleanup in covariance helpers
    
    - Cache typeParam.ToDisplayString() to avoid duplicate call in
      AssertionExtensionGenerator covariant path
    - Replace HashSet with linear Contains() in GetCovariantTypeParamName
      (typical input has 0-2 items)
    - Inline single-use GetNullableCastType into GetCovariantContextExpr
    thomhurst authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    bee2ede View commit details
    Browse the repository at this point in the history
  5. chore(deps): update dependency gitversion.tool to v6.7.0 (#5230)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    b35dcde View commit details
    Browse the repository at this point in the history
  6. feat: support string-to-parseable type conversions in [Arguments] (#5227

    )
    
    * feat: support string-to-parseable type conversions in [Arguments] attributes
    
    Allow string arguments to be automatically converted to types that
    implement IParsable<TSelf> (DateTime, TimeSpan, Guid, DateTimeOffset,
    DateOnly, TimeOnly, etc.) when used with [Arguments] attributes.
    
    This enables patterns like:
      [Arguments("2022-5-31")]
      public void MyTest(DateTime testDate)
    
    Previously this would emit TUnit0001 at compile time.
    
    Closes #5186
    
    * refactor: simplify string-to-parseable conversion code
    
    - Remove redundant DateTime special case in TypedConstantFormatter
      (the generic IParsable path already handles it)
    - Use TryParse instead of Parse-and-catch in netstandard2.0 fallback
    - Narrow catch clause in .NET path to expected exception types
    - Remove unnecessary comments that restate what the code does
    
    * fix: address PR review comments for string-to-parseable feature
    
    - Escape string literals with SymbolDisplay.FormatLiteral to prevent
      invalid C# when strings contain backslashes or quotes
    - Move TryParseFromString out of TryAotSafeConversion since it uses
      reflection, separating it from the AOT-safe path
    - Deduplicate IsParsableFromString into shared ParsableTypeExtensions
      linked from both Analyzers and SourceGenerator projects
    - Assert exact expected values in tests instead of just non-default
    
    * fix: replace trimmer warning suppression with proper DynamicallyAccessedMembers annotations
    
    Use [DynamicallyAccessedMembers] on TryParsableConvert and TryParseFromString
    parameters instead of [UnconditionalSuppressMessage] to properly inform the
    trimmer which metadata to preserve for AOT scenarios.
    thomhurst authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    f570293 View commit details
    Browse the repository at this point in the history
  7. perf: add CI solution filter and mock test pipeline modules (#5231)

    Add TUnit.CI.slnx that excludes 24 projects not needed for CI builds:
    Playground, CloudShop examples (7), template content projects (13),
    SourceGenerator.Benchmarks, TUnit.Profile, and
    TUnit.SourceGenerator.IncrementalTests.
    
    Update dotnet.yml to build TUnit.CI.slnx instead of the full solution
    to reduce CI build times.
    
    Add RunMockHttpTestsModule and RunMockLoggingTestsModule to run the
    Mocks.Http and Mocks.Logging test projects in the pipeline.
    thomhurst authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    e140fb7 View commit details
    Browse the repository at this point in the history
  8. feat: add string length range assertions (#4935)

    * feat: add string length range assertions (HasMinLength, HasMaxLength, HasLengthBetween)
    
    Add three new string assertion methods for validating string length ranges:
    - HasMinLength(int) - asserts string length >= minLength
    - HasMaxLength(int) - asserts string length <= maxLength
    - HasLengthBetween(int, int) - asserts min <= string length <= max
    
    Closes #4868
    
    * chore: update source generator snapshot files after rebase
    
    * refactor: use [GenerateAssertion] for string length assertions and add bounds guard
    
    Convert HasMinLength, HasMaxLength, HasLengthBetween from manual assertion
    classes to [GenerateAssertion] source-generated assertions, reducing ~170
    lines of boilerplate. Add ArgumentOutOfRangeException guard when
    minLength > maxLength in HasLengthBetween.
    
    * test: add tests for HasMinLength, HasMaxLength, and HasLengthBetween assertions
    
    Cover pass/fail cases, null input handling, bounds guard validation,
    and And-chaining for the new string length range assertions.
    thomhurst authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    bb4d985 View commit details
    Browse the repository at this point in the history
  9. chore(deps): update aspire to 13.2.0 (#5232)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    75c8c90 View commit details
    Browse the repository at this point in the history
  10. chore(deps): update dependency typescript to v6 (#5233)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 23, 2026
    Configuration menu
    Copy the full SHA
    e84cce6 View commit details
    Browse the repository at this point in the history

Commits on Mar 24, 2026

  1. Configuration menu
    Copy the full SHA
    54d9353 View commit details
    Browse the repository at this point in the history
  2. chore(deps): update dependency polyfill to 9.23.0 (#5235)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 24, 2026
    Configuration menu
    Copy the full SHA
    1cf8644 View commit details
    Browse the repository at this point in the history
  3. chore(deps): update dependency polyfill to 9.23.0 (#5236)

    Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
    thomhurst and renovate-bot authored Mar 24, 2026
    Configuration menu
    Copy the full SHA
    c199ce3 View commit details
    Browse the repository at this point in the history
  4. Fix BeforeEvery/AfterEvery hooks for Class and Assembly not being exe…

    …cuted (#5239)
    
    * Initial plan
    
    * Fix BeforeEvery/AfterEvery hooks for Class and Assembly not being executed
    
    The HookExecutor was missing invocation of BeforeEvery(Class), AfterEvery(Class),
    BeforeEvery(Assembly), and AfterEvery(Assembly) hooks. While the Test-level hooks
    had the correct pattern of executing both BeforeEvery and Before hooks, the same
    pattern was missing for Class and Assembly levels.
    
    Updated ExecuteBeforeClassHooksAsync, ExecuteAfterClassHooksAsync,
    ExecuteBeforeAssemblyHooksAsync, and ExecuteAfterAssemblyHooksAsync to also
    collect and execute the corresponding BeforeEvery/AfterEvery hooks, following the
    same pattern already used for Test-level hooks.
    
    Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
    Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/89836764-b81e-472f-9f00-c6e7e61c02ca
    
    * Add regression tests for BeforeEvery/AfterEvery Class and Assembly hooks
    
    Test targets in TUnit.TestProject:
    - BeforeEveryClassTests: [BeforeEvery(Class)] hook sets StateBag flag, test verifies
    - BeforeEveryAssemblyTests: [BeforeEvery(Assembly)] hook sets StateBag flag, test verifies
    - AfterEveryClassTests: [AfterEvery(Class)] hook writes file as proof of execution
    - AfterEveryAssemblyTests: [AfterEvery(Assembly)] hook writes file as proof of execution
    
    Integration test runners in TUnit.Engine.Tests:
    - BeforeEveryClassHookTests: Runs filtered tests, asserts 1 passed / 0 failed
    - BeforeEveryAssemblyHookTests: Same pattern for assembly-level hooks
    - AfterEveryClassHookTests: Validates test passes and hook file was created
    - AfterEveryAssemblyHookTests: Validates test passes and hook file was created
    
    Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
    Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/3e2fe83b-5e07-41db-9d58-975349f40a31
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
    Copilot and thomhurst authored Mar 24, 2026
    Configuration menu
    Copy the full SHA
    c0c6155 View commit details
    Browse the repository at this point in the history
Loading