-
-
Notifications
You must be signed in to change notification settings - Fork 125
Comparing changes
Open a pull request
base repository: thomhurst/TUnit
base: v1.25.0
head repository: thomhurst/TUnit
compare: v1.27.0
- 18 commits
- 249 files changed
- 3 contributors
Commits on Apr 4, 2026
-
chore(deps): update dependency mockolate to 2.3.0 (#5370)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for eef7a70 - Browse repository at this point
Copy the full SHA eef7a70View commit details -
Fix Dependabot security vulnerabilities in docs site (#5372)
* Fix 15 Dependabot security vulnerabilities in docs site Add yarn resolutions to docs/package.json to force patched versions of vulnerable transitive dependencies in the Docusaurus docs site. * Scope path-to-regexp resolution to express only Only express uses the vulnerable 0.1.x range. react-router (^1.7.0) and serve-handler (3.3.0) have incompatible APIs and were incorrectly downgraded by the global resolution. * Fix broken anchor link to troubleshooting page The link pointed to #test-discovery-issues but the heading is "Tests Not Discovered" (#tests-not-discovered).
Configuration menu - View commit details
-
Copy full SHA for 677f618 - Browse repository at this point
Copy the full SHA 677f618View commit details -
chore(deps): update tunit to 1.25.0 (#5371)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for f3ad994 - Browse repository at this point
Copy the full SHA f3ad994View commit details -
chore(deps): update dependency minimatch to v9.0.9 (#5375)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for a8207e3 - Browse repository at this point
Copy the full SHA a8207e3View commit details -
fix: use 0.0.0-scrubbed sentinel version in snapshot scrubber to avoi…
…d false Dependabot alerts (#5374) * fix: scrub snapshot versions to 99.99.99 to avoid false Dependabot alerts The template snapshot test scrubber was replacing package versions with 1.0.0, which triggered Dependabot security alerts for packages with vulnerabilities fixed above 1.0.0 (e.g. OpenTelemetry.Instrumentation). Using 99.99.99 instead ensures scrubbed versions are always above any patched version threshold while still stabilizing snapshots. * refactor: use 0.0.0-scrubbed as sentinel version in snapshot scrubber Pre-release label makes the version structurally outside Dependabot's scan range and self-documenting, rather than relying on 99.99.99 being above all patched versions. * refactor: extract scrubbed version constant and remove redundant filter - Extract magic string to ScrubbedVersion constant - Remove redundant .Where(m => m.Success) — Matches() only returns successful matches
Configuration menu - View commit details
-
Copy full SHA for fd84fda - Browse repository at this point
Copy the full SHA fd84fdaView commit details -
Speed up Engine.Tests and fix missing [Test] attribute (#5379)
Remove ProcessorCountParallelLimit from TUnit.Engine.Tests assembly - these tests are I/O-bound subprocess launches, not CPU-bound, so capping parallelism at processor count unnecessarily serialises ~119 tests into sequential batches. Also add missing [Test] attribute to TimeoutTests1.Test() which was silently not running.
Configuration menu - View commit details
-
Copy full SHA for 5875588 - Browse repository at this point
Copy the full SHA 5875588View commit details -
Configuration menu - View commit details
-
Copy full SHA for 64327fe - Browse repository at this point
Copy the full SHA 64327feView commit details -
chore(deps): update dependency path-to-regexp to v0.2.5 (#5376)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for d466b96 - Browse repository at this point
Copy the full SHA d466b96View commit details -
ci: add concurrency groups to cancel redundant workflow runs (#5373)
Prevents redundant CI runs when new commits are pushed to a PR branch, saving runner time and reducing queue contention.
Configuration menu - View commit details
-
Copy full SHA for 022b93a - Browse repository at this point
Copy the full SHA 022b93aView commit details -
Add scope-aware initialization and disposal OpenTelemetry spans to tr…
…ace timeline and HTML report (#5339) * Track initialization and disposal times with OpenTelemetry activity spans - Move "test case" activity span to start before data source initialization - Add "data source initialization" child activity span in TestExecutor - Add "test instance disposal" activity span in TestCoordinator - Set TestStart before initialization so HTML report duration includes init time - Simplify TestInitializer now that test case span covers initialization Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/7e7dc4cb-23dd-4723-ba82-6355cfc6d354 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Address code review: rename activity, add explanatory comments - Rename "data source initialization" to "test object initialization" for accuracy - Add comment explaining TestStart semantic change (now includes init time) - Add comment explaining why disposal activity is parented under class activity Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/7e7dc4cb-23dd-4723-ba82-6355cfc6d354 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Address PR review: extract disposal helper, add error recording, fix stale comment - Extract disposal span logic into DisposeTestInstanceWithSpanAsync() helper to reduce #if NET nesting in the finally block (review issue #1) - Add TUnitActivitySource.RecordException() calls on disposal span when OnDispose or DisposeTestInstance throws (review issue #2) - Fix stale comment in TestInitializer.cs referencing "data source initialization" instead of "test object initialization" (review issue #4) Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/3802acb9-a7fe-4976-8c3f-5bb246c098d2 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Move init/disposal spans outside test case, add type names, restore TestStart - Initialization span now parented under session activity (not test case) so slow infrastructure setup doesn't inflate the test's reported duration - Restore TestStart to just before test body execution - Span names include the class type: "initialize {TypeName}", "dispose {TypeName}" - Restore Activity.Current swapping in TestInitializer.cs for session-level parenting - Error recording preserved on both init and disposal spans Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/26cf2c58-e50d-44f7-b5d4-34f5bdc54f52 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Address latest review: fix dead code, add missing tags, set Activity.Current, use FullName - Remove dead RecordException for DisposeTestInstance (swallows all exceptions) - Add tunit.test.class tag to dispose span for consistent trace filtering - Set Activity.Current = disposalActivity during disposal for child span parenting - Use FullName ?? Name for span names to handle nested/generic types - Restore Activity.Current after disposal completes Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/172f0096-6317-4169-8b89-b8bc122de149 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Add initialization and disposal spans to HTML report execution timeline Include 'initialize {TypeName}' and 'dispose {TypeName}' spans in the global Execution Timeline alongside session, assembly, and suite spans. Extracted isGlobalTimelineSpan() helper for readability. Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/472d120e-6d02-435d-bc01-4fbeb030c0ff Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Remove full name from class type in TestInitializer * Restore FullName ?? Name in TestInitializer.cs to fix regression Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/ad55c3d7-39fe-46bd-b02e-b217cf7ec4c8 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Implement scope-aware init/dispose tracing based on SharedType - Add TraceScopeRegistry to map data source objects to their SharedType - Register scope in ClassDataSources.Get based on SharedType - Move test case activity start before initialization so per-test init spans can be children of the test case - Create per-object init spans with scope-aware parent selection: - PerTestSession → session activity - PerAssembly → assembly activity - PerClass → class activity - None/Keyed/default → test case activity - Add tunit.trace.scope tag to init/dispose spans - Update HTML report isGlobalTimelineSpan() to show only shared init spans in global timeline (not per-test ones) - Simplify TestInitializer (tracing now in ObjectLifecycleService) Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/ccdbc811-2561-405a-87e0-7152014e4e69 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Address code review: extract GetScopeTag helper, fix null safety, document Keyed scope Agent-Logs-Url: https://github.com/thomhurst/TUnit/sessions/ccdbc811-2561-405a-87e0-7152014e4e69 Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com> * Fix TraceScopeRegistry memory leak and redundant registration - Call TraceScopeRegistry.Clear() in TUnitServiceProvider.DisposeAsync() so per-test entries are released at end of session - Use TryAdd instead of indexer in Register() to skip redundant writes for shared objects that are re-registered on every test - Remove unused Unregister() method (cleanup handled by Clear()) * Move TraceScopeRegistry registration from ClassDataSources to engine layer - Add ITraceScopeProvider interface for data source attributes to declare their SharedType per generated object - ClassDataSourceAttribute (all variants) implement ITraceScopeProvider - Remove TraceScopeRegistry.Register calls from ClassDataSources.Get, keeping it as pure user-facing data generation code - Add TraceScopeRegistry.RegisterFromDataSource helper that checks if a data source implements ITraceScopeProvider and registers objects - Call RegisterFromDataSource in TestBuilder (class + method data) and PropertyInjector (property data) after objects are produced * Simplify: remove dead code, fix stringly-typed tag, cache type lookups - Remove unused TraceScopeRegistry.Register(object, SharedType) — only RegisterFromDataSource is called - Restore direct return in ClassDataSources.Get (unnecessary local var left from removing TraceScopeRegistry.Register) - Use GetScopeTag(SharedType.None) instead of hardcoded "test" string in DisposeTestInstanceWithSpanAsync for consistency with init spans - Cache obj.GetType() and ClassType to avoid repeated property access in span creation paths * Address PR review: fix memory leak, add robustness, tests, and snapshots - Replace ConcurrentDictionary with ConditionalWeakTable in TraceScopeRegistry so per-test data source objects can be GC'd after tests complete - Remove TraceScopeRegistry.Clear() from TUnitServiceProvider (no longer needed) - Wrap DisposeTestInstance in try/catch with error recording on disposal span - Add Activity.Current thread-static limitation comments at restore sites - Add comments explaining dual RegisterFromDataSource calls in TestBuilder - Update all 4 public API snapshot files with ITraceScopeProvider interface - Add 8 unit tests for TraceScopeRegistry covering registration, lookup, null handling, duplicate semantics, and reference equality * Address code review: unify class init path, fix keyed scope tag - Remove duplicated #if NET class instance init in ObjectLifecycleService; call InitializeObjectWithSpanAsync instead (unregistered objects default to per-test scope via null SharedType) - Map SharedType.Keyed to "session" scope tag to match its parent activity selection, eliminating the inconsistency where "keyed" was a non-structural scope name * Improve docs: fix misleading TOCTOU comment, document ITraceScopeProvider contract * Return defensive copies from GetSharedTypes() and GetKeys() * Use simple type names in init/dispose span labels for readability * Deduplicate init spans: only the first caller for a shared object creates a trace span * Simplify: extract RunWithSpanAsync helper, add tag constants, remove #if NET nesting * Parent session/keyed init spans under assembly, not session Session-scoped and keyed init spans were parented under the session activity, putting them at the same depth as assemblies. This made suite spans (at the next depth level) appear visually nested under init spans in both OTel backends and the HTML timeline. Now all shared init spans (session, assembly, keyed) are parented under the assembly activity — siblings of suites. The tunit.trace.scope tag still carries the precise lifetime semantics. This removes the need for the JS reparenting workaround in the global timeline. * Make ITraceScopeProvider internal, revert defensive copies ITraceScopeProvider is an implementation detail of the tracing system — only ClassDataSourceAttribute variants implement it, all in the same assembly. Making it internal removes it from the public API surface. The defensive array copies ([..Shared]) are unnecessary since all callers are internal and iterate immediately. Revert to the original direct returns. * Use session span duration for header when available The header duration was calculated from test execution timing only, excluding initialization time. The session span captures the full wall-clock time. Falls back to test-based timing on non-.NET or when no session span exists. * Address review: span name constants, disposal error recording, memory leak fix - Extract span name constants (SpanTestSession, SpanTestAssembly, etc.) into TUnitActivitySource and replace all magic strings across C# call sites - Record disposal exceptions on the trace span before swallowing them, so disposal errors are visible in traces instead of always showing green - Clear _spannedObjects in ClearCache() to prevent memory leak for per-test objects that were kept alive by hard references - Gate _spannedObjects.TryAdd behind HasListeners() to skip work when no trace listener is attached - Update public API snapshots to remove internal ITraceScopeProvider from class declarations * Fix Activity.Current comment: AsyncLocal, not ThreadStatic * Use ConditionalWeakTable for span dedup gate, fix Activity.Current comment - Replace ConcurrentDictionary with ConditionalWeakTable for _spannedObjects so per-test objects can be GC'd after their test completes instead of being retained for the entire session - Use Interlocked.Exchange on StrongBox<int> for atomic first-caller-wins gate - Fix Activity.Current comment: it is AsyncLocal, not ThreadStatic * Polish: readable type names, omit test ID from shared spans, add disposal TODO - Add GetReadableTypeName helper that strips namespace but preserves nesting (Outer.Inner) and cleans generic arity suffixes (MySource`1 → MySource) - Use GetReadableTypeName for init and dispose span labels - Omit tunit.test.id tag from shared-scope init spans (the triggering test is arbitrary for shared objects, making the tag misleading) - Add TODO in ObjectTracker.UntrackObject for shared-object disposal spans - Add GetReadableTypeNameTests covering simple, nested, generic, and deeply nested types * Wrap GetReadableTypeNameTests in #if NET for net472 compatibility TUnitActivitySource is guarded by #if NET in TUnit.Core, so these tests cannot compile on net472. Matches the conditional compilation of the class under test. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for a24a468 - Browse repository at this point
Copy the full SHA a24a468View commit details -
chore(deps): update dependency minimatch to v10 (#5377)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for beccae2 - Browse repository at this point
Copy the full SHA beccae2View commit details -
chore(deps): update dependency picomatch to v4 (#5382)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for b0921a2 - Browse repository at this point
Copy the full SHA b0921a2View commit details -
Add WithInnerExceptions() for fluent AggregateException assertion cha…
…ining (#5380) * +semver:minor - Add WithInnerExceptions() for fluent AggregateException assertion chaining (#5345) * Address PR review: add metadata.Exception guard and fix error message * Constrain WithInnerExceptions to AggregateException at compile time Move WithInnerExceptions from instance methods on ThrowsAssertion<T> and ThrowsExactlyAssertion<T> to extension methods constrained to AggregateException. This prevents misuse at compile time rather than runtime. Also simplify WithInnerExceptionsAssertion to a non-generic class since TException is always AggregateException. * Update .gitattributes with EOF best practices * Regenerate Assertions public API snapshots for WithInnerExceptions changes * Propagate inner assertion failure message in WithInnerExceptions catch block Change bare `catch` to `catch (Exception ex)` and include ex.Message in the failure string, consistent with MappedSatisfiesAssertion and other sibling assertion patterns in the codebase.
Configuration menu - View commit details
-
Copy full SHA for e4c164f - Browse repository at this point
Copy the full SHA e4c164fView commit details -
chore(deps): update dependency svgo to v4 (#5383)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for bc313ca - Browse repository at this point
Copy the full SHA bc313caView commit details -
Drop net6.0 and net7.0 TFMs, keep net8.0+ and netstandard2.x (#5387)
Both net6.0 (Nov 2024) and net7.0 (May 2024) are out of support. Remove net6.0 from TargetFrameworks in test/nuget-tester projects and update all #if NET6_0_OR_GREATER / NET7_0_OR_GREATER preprocessor directives to NET8_0_OR_GREATER across 67 files. .NET Framework users are unaffected (covered by netstandard targets). Closes #4786
Configuration menu - View commit details
-
Copy full SHA for b9f6286 - Browse repository at this point
Copy the full SHA b9f6286View commit details -
Remove all [Obsolete] members and migrate callers (#5384)
* Remove all [Obsolete] members and migrate callers to current APIs - Remove ObjectBag properties from TestRegisteredContext and TestBuilderContext (use StateBag) - Remove Timing record and ITestOutput.Timings/RecordTiming (replaced by OpenTelemetry spans); internal TimingEntry record preserves engine functionality - Remove obsolete HasCount()/HasCount(int) from CollectionAssertionBase; migrate all callers to Count().IsEqualTo(N) or Count(c => c.IsEqualTo(N)) - Remove obsolete HasLength()/HasLength(int) from AssertionExtensions; migrate all callers to Length().IsEqualTo(N) or Length(l => l.IsEqualTo(N)) - Add Length(lambda) overload for inline assertions that preserve string context for .And chaining, matching the existing Count(lambda) pattern - Update docs, code examples, and XUnit migration code fixer * Extract shared inline assertion helper and propagate inner failure messages Deduplicate the lambda-assertion execution logic from StringLengthWithInlineAssertionAssertion and CollectionCountWithInlineAssertionAssertion into a shared InlineAssertionHelper. Inner assertion failure messages are now propagated instead of being replaced with a generic "count/length was N". * Fix tests to use Length(lambda) for string-context-preserving chaining Length() maps context to int, so And/Or chaining after it cannot return to string assertions. Use Length(l => l.IsEqualTo(N)) which preserves the string context for continued chaining. * Regenerate public API snapshots after removing obsolete members * Address PR review: delete dead wrappers, improve inline assertion messages, make helper generic - Delete CountWrapper and LengthWrapper (dead code after removing HasCount/HasLength no-arg overloads) - Make InlineAssertionHelper generic and return inner assertion for expectation delegation - Improve GetExpectation() in StringLengthWithInlineAssertionAssertion and CollectionCountWithInlineAssertionAssertion to delegate to inner assertion (e.g. "length to be equal to 5" instead of "to satisfy length assertion") - Fix null message from "value was null" to "string was null" for string length assertions - Remove unused Wrappers namespace imports - Regenerate public API snapshots
Configuration menu - View commit details
-
Copy full SHA for df31e91 - Browse repository at this point
Copy the full SHA df31e91View commit details -
chore(deps): update dependency path-to-regexp to v1 [security] (#5385)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Configuration menu - View commit details
-
Copy full SHA for 5db8137 - Browse repository at this point
Copy the full SHA 5db8137View commit details -
+semver:minor - Add AssertionResult.Failed overload that accepts an E…
…xception (#5388) * Add AssertionResult.Failed overload that accepts an Exception (#5381) Preserve original exceptions when nested/inline assertions fail by adding an Exception? property to AssertionResult and threading it through to AssertionException as an inner exception. Updated 22 catch sites across assertions and mock assertions. * Add context to GroupAssertion error messages The bare `Failed(ex.Message, ex)` calls gave no indication which group lookup failed. Now includes "failed to get group 'name': ..." for consistency with other catch sites. * Propagate exceptions through all metadata.Exception guards and cache Passed - Update ~110 remaining metadata.Exception guard sites across 32 files to pass the exception as second argument to AssertionResult.Failed() - Cache the Passed struct in a static readonly field to avoid repeated allocations on the happy path * Propagate exceptions in remaining guard sites Fix missed evaluationException guards in ExceptionPropertyAssertions (8 sites), ThrowsAssertion, WithInnerExceptionsAssertion, and MatchIndexAssertion. * Unwrap AssertionException in WaitsForAssertion to avoid double-wrapping WaitsForAssertion catches AssertionException from repeated assertion attempts. Passing it directly as inner exception produces a misleading AssertionException → AssertionException chain. Unwrap to the original root cause instead. * Address review feedback - Fix missed propagation site in StringAssertions.cs (line 613) - Add Failed(string, Exception?) overload to AssertionResult<T> for parity with non-generic AssertionResult - Revert WaitsForAssertion unwrapping — keep the full AssertionException as inner exception since it carries the formatted assertion message
Configuration menu - View commit details
-
Copy full SHA for 46555b5 - Browse repository at this point
Copy the full SHA 46555b5View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v1.25.0...v1.27.0