You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to PR #5764 (issue #5706 fix), which introduced the IAssertionSourceFor<TItem, TSelf> pattern with static-abstract Create for generic Satisfies dispatch.
The same per-type overload duplication still exists in Count(itemAssertion). Issue #5707 closed when the original per-type overloads landed; this issue tracks the architectural follow-up.
Current state
TUnit.Assertions/Extensions/AssertionExtensions.cs:1825-2077 has ~250 LOC of Count(itemAssertion) overloads, each containing inline new XxxAssertion<T>(item, $\"item[{index}]\") construction logic. Pattern matches what PR #5764 refactored away for ItemAt(...).Satisfies(...).
New interface: TUnit.Assertions/Core/IAssertionSourceFor.cs
Generic dispatch entry: Satisfies<TSource> on ListItemAtSource and ReadOnlyListItemAtSource in TUnit.Assertions/Conditions/ListAssertions.cs and ReadOnlyListAssertions.cs
Sources implement IAssertionSourceFor<TItem, TSelf> with one (or two, for concrete-type variants) static Create methods.
Steps to apply
Add a generic Count<TSource>(Func<TSource, IAssertion?>, ...) instance method on CollectionAssertionBase constrained where TSource : IAssertionSourceFor<TItem, TSource>, mirroring Satisfies<TSource> on ListItemAtSource.
Convert interface-shape Count overloads (IEnumerable, IList, IReadOnlyList, IDictionary, IReadOnlyDictionary, ISet, IReadOnlySet, T[]) into one-line delegators that call source.Count<XxxAssertion<T>>(itemAssertion, expression).
Concrete-type overloads (List<T>, Dictionary<K,V>) require their assertion sources (ListAssertion, MutableDictionaryAssertion) to implement an additional IAssertionSourceFor<ConcreteType, TSelf> variant with a second Create overload — already done for Satisfies in PR Fix item-at Satisfies source typing #5764. Reuse those.
HashSet<T>-typed items already work since HashSetAssertion implements IAssertionSourceFor<HashSet<T>, ...>.
Wrap the new generic entry + interface-shape delegators in #if !NETSTANDARD2_0. netstandard2.0 retains the existing specialised overload behaviour through the current CountSpecialised private helper.
Same pattern applies to
FirstItem.Satisfies / LastItem.Satisfies
Any future Member, Where, etc. combinators on collection items.
Estimated saving
~150 LOC out of the current ~250 LOC Count overload block.
Follow-up to PR #5764 (issue #5706 fix), which introduced the
IAssertionSourceFor<TItem, TSelf>pattern with static-abstractCreatefor generic Satisfies dispatch.The same per-type overload duplication still exists in
Count(itemAssertion). Issue #5707 closed when the original per-type overloads landed; this issue tracks the architectural follow-up.Current state
TUnit.Assertions/Extensions/AssertionExtensions.cs:1825-2077has ~250 LOC ofCount(itemAssertion)overloads, each containing inlinenew XxxAssertion<T>(item, $\"item[{index}]\")construction logic. Pattern matches what PR #5764 refactored away forItemAt(...).Satisfies(...).Reference implementation (PR #5764)
TUnit.Assertions/Core/IAssertionSourceFor.csSatisfies<TSource>onListItemAtSourceandReadOnlyListItemAtSourceinTUnit.Assertions/Conditions/ListAssertions.csandReadOnlyListAssertions.csTUnit.Assertions/Extensions/ListItemAtSatisfiesExtensions.csIAssertionSourceFor<TItem, TSelf>with one (or two, for concrete-type variants) staticCreatemethods.Steps to apply
Count<TSource>(Func<TSource, IAssertion?>, ...)instance method onCollectionAssertionBaseconstrainedwhere TSource : IAssertionSourceFor<TItem, TSource>, mirroringSatisfies<TSource>onListItemAtSource.Countoverloads (IEnumerable, IList, IReadOnlyList, IDictionary, IReadOnlyDictionary, ISet, IReadOnlySet, T[]) into one-line delegators that callsource.Count<XxxAssertion<T>>(itemAssertion, expression).List<T>,Dictionary<K,V>) require their assertion sources (ListAssertion,MutableDictionaryAssertion) to implement an additionalIAssertionSourceFor<ConcreteType, TSelf>variant with a secondCreateoverload — already done forSatisfiesin PR Fix item-at Satisfies source typing #5764. Reuse those.HashSet<T>-typed items already work sinceHashSetAssertionimplementsIAssertionSourceFor<HashSet<T>, ...>.#if !NETSTANDARD2_0. netstandard2.0 retains the existing specialised overload behaviour through the currentCountSpecialisedprivate helper.Same pattern applies to
FirstItem.Satisfies/LastItem.SatisfiesMember,Where, etc. combinators on collection items.Estimated saving
~150 LOC out of the current ~250 LOC
Countoverload block.