Skip to content

Commit 3cc8bf4

Browse files
committed
Abstract IEnumerable<T> to TCollection
1 parent b4bf378 commit 3cc8bf4

File tree

7 files changed

+206
-539
lines changed

7 files changed

+206
-539
lines changed

Src/FluentAssertions/AssertionExtensions.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ public static GenericCollectionAssertions<T> Should<T>(this IEnumerable<T> actua
279279
return new GenericCollectionAssertions<T>(actualValue);
280280
}
281281

282+
[Pure]
283+
public static GenericCollectionAssertions<TCollection, T> Should<TCollection, T>(this TCollection actualValue)
284+
where TCollection : IEnumerable<T>
285+
{
286+
return new GenericCollectionAssertions<TCollection, T>(actualValue);
287+
}
288+
282289
/// <summary>
283290
/// Returns an <see cref="StringCollectionAssertions"/> object that can be used to assert the
284291
/// current <see cref="IEnumerable{T}"/>.
@@ -290,13 +297,30 @@ public static StringCollectionAssertions Should(this IEnumerable<string> @this)
290297
}
291298

292299
/// <summary>
293-
/// Returns an <see cref="GenericDictionaryAssertions{TKey, TValue}"/> object that can be used to assert the
300+
/// Returns an <see cref="GenericDictionaryAssertions{TCollection, TKey, TValue}"/> object that can be used to assert the
294301
/// current <see cref="IDictionary{TKey, TValue}"/>.
295302
/// </summary>
296303
[Pure]
297-
public static GenericDictionaryAssertions<TKey, TValue> Should<TKey, TValue>(this IDictionary<TKey, TValue> actualValue)
304+
public static GenericDictionaryAssertions<IDictionary<TKey, TValue>, TKey, TValue> Should<TKey, TValue>(this IDictionary<TKey, TValue> actualValue)
305+
{
306+
return new GenericDictionaryAssertions<IDictionary<TKey, TValue>, TKey, TValue>(actualValue);
307+
}
308+
309+
/// <summary>
310+
/// Returns an <see cref="GenericDictionaryAssertions{TCollection, TKey, TValue}"/> object that can be used to assert the
311+
/// current <see cref="IDictionary{TKey, TValue}"/>.
312+
/// </summary>
313+
[Pure]
314+
public static GenericDictionaryAssertions<IEnumerable<KeyValuePair<TKey, TValue>>, TKey, TValue> Should<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> actualValue)
315+
{
316+
return new GenericDictionaryAssertions<IEnumerable<KeyValuePair<TKey, TValue>>, TKey, TValue>(actualValue);
317+
}
318+
319+
[Pure]
320+
public static GenericDictionaryAssertions<TCollection, TKey, TValue> Should<TCollection, TKey, TValue>(this TCollection actualValue)
321+
where TCollection : IEnumerable<KeyValuePair<TKey, TValue>>
298322
{
299-
return new GenericDictionaryAssertions<TKey, TValue>(actualValue);
323+
return new GenericDictionaryAssertions<TCollection, TKey, TValue>(actualValue);
300324
}
301325

302326
/// <summary>

Src/FluentAssertions/Collections/GenericCollectionAssertions.cs

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,36 @@
1111

1212
namespace FluentAssertions.Collections
1313
{
14-
[DebuggerNonUserCode]
15-
public class GenericCollectionAssertions<T> :
16-
SelfReferencingCollectionAssertions<T, GenericCollectionAssertions<T>>
14+
public class GenericCollectionAssertions<T>
15+
: GenericCollectionAssertions<IEnumerable<T>, T, GenericCollectionAssertions<T>>
1716
{
1817
public GenericCollectionAssertions(IEnumerable<T> actualValue)
1918
: base(actualValue)
2019
{
2120
}
21+
}
22+
23+
public class GenericCollectionAssertions<TCollection, T>
24+
: GenericCollectionAssertions<TCollection, T, GenericCollectionAssertions<TCollection, T>>
25+
where TCollection : IEnumerable<T>
26+
{
27+
public GenericCollectionAssertions(TCollection actualValue)
28+
: base(actualValue)
29+
{
30+
}
31+
}
32+
33+
[DebuggerNonUserCode]
34+
public class GenericCollectionAssertions<TCollection, T, TAssertions> :
35+
SelfReferencingCollectionAssertions<TCollection, T, TAssertions>
36+
where TCollection : IEnumerable<T>
37+
where TAssertions : GenericCollectionAssertions<TCollection, T, TAssertions>
38+
39+
{
40+
public GenericCollectionAssertions(TCollection actualValue)
41+
: base(actualValue)
42+
{
43+
}
2244

2345
/// <summary>
2446
/// Asserts that the collection does not contain any <c>null</c> items.
@@ -31,7 +53,7 @@ public GenericCollectionAssertions(IEnumerable<T> actualValue)
3153
/// <param name="becauseArgs">
3254
/// Zero or more objects to format using the placeholders in <see cref="because" />.
3355
/// </param>
34-
public AndConstraint<GenericCollectionAssertions<T>> NotContainNulls<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
56+
public AndConstraint<TAssertions> NotContainNulls<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
3557
where TKey : class
3658
{
3759
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
@@ -58,7 +80,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotContainNulls<TKey>(Expre
5880
values);
5981
}
6082

61-
return new AndConstraint<GenericCollectionAssertions<T>>(this);
83+
return new AndConstraint<TAssertions>((TAssertions)this);
6284
}
6385

6486
/// <summary>
@@ -72,7 +94,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotContainNulls<TKey>(Expre
7294
/// <param name="becauseArgs">
7395
/// Zero or more objects to format using the placeholders in <see cref="because" />.
7496
/// </param>
75-
public AndConstraint<GenericCollectionAssertions<T>> OnlyHaveUniqueItems<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
97+
public AndConstraint<TAssertions> OnlyHaveUniqueItems<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
7698
{
7799
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
78100

@@ -110,7 +132,7 @@ public AndConstraint<GenericCollectionAssertions<T>> OnlyHaveUniqueItems<TKey>(E
110132
}
111133
}
112134

113-
return new AndConstraint<GenericCollectionAssertions<T>>(this);
135+
return new AndConstraint<TAssertions>((TAssertions)this);
114136
}
115137

116138
/// <summary>
@@ -130,7 +152,7 @@ public AndConstraint<GenericCollectionAssertions<T>> OnlyHaveUniqueItems<TKey>(E
130152
/// <remarks>
131153
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
132154
/// </remarks>
133-
public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder<TSelector>(
155+
public AndConstraint<TAssertions> BeInAscendingOrder<TSelector>(
134156
Expression<Func<T, TSelector>> propertyExpression, string because = "", params object[] args)
135157
{
136158
return BeInAscendingOrder(propertyExpression, Comparer<TSelector>.Default, because, args);
@@ -153,7 +175,7 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder<TSelecto
153175
/// <remarks>
154176
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
155177
/// </remarks>
156-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder<TSelector>(
178+
public AndConstraint<TAssertions> NotBeInAscendingOrder<TSelector>(
157179
Expression<Func<T, TSelector>> propertyExpression, string because = "", params object[] args)
158180
{
159181
return NotBeInAscendingOrder(propertyExpression, Comparer<TSelector>.Default, because, args);
@@ -176,7 +198,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder<TSele
176198
/// <remarks>
177199
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
178200
/// </remarks>
179-
public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder(
201+
public AndConstraint<TAssertions> BeInAscendingOrder(
180202
IComparer<T> comparer, string because = "", params object[] args)
181203
{
182204
return BeInAscendingOrder(item => item, comparer, because, args);
@@ -199,7 +221,7 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder(
199221
/// <remarks>
200222
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
201223
/// </remarks>
202-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder(
224+
public AndConstraint<TAssertions> NotBeInAscendingOrder(
203225
IComparer<T> comparer, string because = "", params object[] args)
204226
{
205227
return NotBeInAscendingOrder(item => item, comparer, because, args);
@@ -225,7 +247,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder(
225247
/// <remarks>
226248
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
227249
/// </remarks>
228-
public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder<TSelector>(
250+
public AndConstraint<TAssertions> BeInAscendingOrder<TSelector>(
229251
Expression<Func<T, TSelector>> propertyExpression, IComparer<TSelector> comparer, string because = "", params object[] args)
230252
{
231253
return BeOrderedBy(propertyExpression, comparer, SortOrder.Ascending, because, args);
@@ -251,7 +273,7 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInAscendingOrder<TSelecto
251273
/// <remarks>
252274
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
253275
/// </remarks>
254-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder<TSelector>(
276+
public AndConstraint<TAssertions> NotBeInAscendingOrder<TSelector>(
255277
Expression<Func<T, TSelector>> propertyExpression, IComparer<TSelector> comparer, string because = "", params object[] args)
256278
{
257279
return NotBeOrderedBy(propertyExpression, comparer, SortOrder.Ascending, because, args);
@@ -274,7 +296,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotBeInAscendingOrder<TSele
274296
/// <remarks>
275297
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
276298
/// </remarks>
277-
public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder<TSelector>(
299+
public AndConstraint<TAssertions> BeInDescendingOrder<TSelector>(
278300
Expression<Func<T, TSelector>> propertyExpression, string because = "", params object[] args)
279301
{
280302
return BeInDescendingOrder(propertyExpression, Comparer<TSelector>.Default, because, args);
@@ -297,7 +319,7 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder<TSelect
297319
/// <remarks>
298320
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
299321
/// </remarks>
300-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInDescendingOrder<TSelector>(
322+
public AndConstraint<TAssertions> NotBeInDescendingOrder<TSelector>(
301323
Expression<Func<T, TSelector>> propertyExpression, string because = "", params object[] args)
302324
{
303325
return NotBeInDescendingOrder(propertyExpression, Comparer<TSelector>.Default, because, args);
@@ -320,7 +342,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotBeInDescendingOrder<TSel
320342
/// <remarks>
321343
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
322344
/// </remarks>
323-
public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder(
345+
public AndConstraint<TAssertions> BeInDescendingOrder(
324346
IComparer<T> comparer, string because = "", params object[] args)
325347
{
326348
return BeInDescendingOrder(item => item, comparer, because, args);
@@ -343,7 +365,7 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder(
343365
/// <remarks>
344366
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
345367
/// </remarks>
346-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInDescendingOrder(
368+
public AndConstraint<TAssertions> NotBeInDescendingOrder(
347369
IComparer<T> comparer, string because = "", params object[] args)
348370
{
349371
return NotBeInDescendingOrder(item => item, comparer, because, args);
@@ -369,7 +391,7 @@ public AndConstraint<GenericCollectionAssertions<T>> NotBeInDescendingOrder(
369391
/// <remarks>
370392
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
371393
/// </remarks>
372-
public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder<TSelector>(
394+
public AndConstraint<TAssertions> BeInDescendingOrder<TSelector>(
373395
Expression<Func<T, TSelector>> propertyExpression, IComparer<TSelector> comparer, string because = "", params object[] args)
374396
{
375397
return BeOrderedBy(propertyExpression, comparer, SortOrder.Descending, because, args);
@@ -395,13 +417,13 @@ public AndConstraint<GenericCollectionAssertions<T>> BeInDescendingOrder<TSelect
395417
/// <remarks>
396418
/// Empty and single element collections are considered to be ordered both in ascending and descending order at the same time.
397419
/// </remarks>
398-
public AndConstraint<GenericCollectionAssertions<T>> NotBeInDescendingOrder<TSelector>(
420+
public AndConstraint<TAssertions> NotBeInDescendingOrder<TSelector>(
399421
Expression<Func<T, TSelector>> propertyExpression, IComparer<TSelector> comparer, string because = "", params object[] args)
400422
{
401423
return NotBeOrderedBy(propertyExpression, comparer, SortOrder.Descending, because, args);
402424
}
403425

404-
private AndConstraint<GenericCollectionAssertions<T>> BeOrderedBy<TSelector>(
426+
private AndConstraint<TAssertions> BeOrderedBy<TSelector>(
405427
Expression<Func<T, TSelector>> propertyExpression,
406428
IComparer<TSelector> comparer,
407429
SortOrder direction,
@@ -429,10 +451,10 @@ private AndConstraint<GenericCollectionAssertions<T>> BeOrderedBy<TSelector>(
429451
Subject, orderString, expectation);
430452
}
431453

432-
return new AndConstraint<GenericCollectionAssertions<T>>(this);
454+
return new AndConstraint<TAssertions>((TAssertions)this);
433455
}
434456

435-
private AndConstraint<GenericCollectionAssertions<T>> NotBeOrderedBy<TSelector>(
457+
private AndConstraint<TAssertions> NotBeOrderedBy<TSelector>(
436458
Expression<Func<T, TSelector>> propertyExpression,
437459
IComparer<TSelector> comparer,
438460
SortOrder direction,
@@ -460,7 +482,7 @@ private AndConstraint<GenericCollectionAssertions<T>> NotBeOrderedBy<TSelector>(
460482
Subject, orderString, expectation);
461483
}
462484

463-
return new AndConstraint<GenericCollectionAssertions<T>>(this);
485+
return new AndConstraint<TAssertions>((TAssertions)this);
464486
}
465487

466488
private bool IsValidProperty<TSelector>(Expression<Func<T, TSelector>> propertyExpression, string because, object[] args)
@@ -517,7 +539,7 @@ private string GetExpressionOrderString<TSelector>(Expression<Func<T, TSelector>
517539
/// <param name="becauseArgs">
518540
/// Zero or more objects to format using the placeholders in <see cref="because" />.
519541
/// </param>
520-
public AndConstraint<GenericCollectionAssertions<T>> AllBeEquivalentTo<TExpectation>(TExpectation expectation,
542+
public AndConstraint<TAssertions> AllBeEquivalentTo<TExpectation>(TExpectation expectation,
521543
string because = "", params object[] becauseArgs)
522544
{
523545
return AllBeEquivalentTo(expectation, options => options, because, becauseArgs);
@@ -547,7 +569,7 @@ public AndConstraint<GenericCollectionAssertions<T>> AllBeEquivalentTo<TExpectat
547569
/// <param name="becauseArgs">
548570
/// Zero or more objects to format using the placeholders in <see cref="because" />.
549571
/// </param>
550-
public AndConstraint<GenericCollectionAssertions<T>> AllBeEquivalentTo<TExpectation>(TExpectation expectation,
572+
public AndConstraint<TAssertions> AllBeEquivalentTo<TExpectation>(TExpectation expectation,
551573
Func<EquivalencyAssertionOptions<TExpectation>, EquivalencyAssertionOptions<TExpectation>> config,
552574
string because = "",
553575
params object[] becauseArgs)

0 commit comments

Comments
 (0)