Skip to content

Commit 0d5b1a9

Browse files
authored
fix: pluralize item suffix in ComplyWith failure messages (#951)
The ComplyWith constraints hardcoded ` items` (always plural), producing ungrammatical output like `for exactly one items`. Route the suffix through EnumerableQuantifier.GetItemString() like the other collection constraints, so singular quantifiers (Exactly(1), AtLeast(1), AtMost(1)) render `item` instead. Also adds verification tests for the Exactly(n).ComplyWith chain and the AtLeast(n).ComplyWith chain, which previously had no coverage.
1 parent 16e2c24 commit 0d5b1a9

5 files changed

Lines changed: 133 additions & 9 deletions

File tree

Source/aweXpect/That/Collections/ThatAsyncEnumerable.Elements.ComplyWith.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
106106
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
107107
stringBuilder.Append(" for ");
108108
stringBuilder.Append(_quantifier);
109-
stringBuilder.Append(" items");
109+
stringBuilder.Append(' ');
110+
stringBuilder.Append(_quantifier.GetItemString());
110111
}
111112

112113
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -126,7 +127,8 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
126127
stringBuilder.Append(_quantifier);
127128
stringBuilder.Append(" for ");
128129
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
129-
stringBuilder.Append(" items");
130+
stringBuilder.Append(' ');
131+
stringBuilder.Append(_quantifier.GetItemString());
130132
}
131133

132134
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)

Source/aweXpect/That/Collections/ThatEnumerable.Elements.ComplyWith.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
104104
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
105105
stringBuilder.Append(For);
106106
stringBuilder.Append(_quantifier);
107-
stringBuilder.Append(ComplyItems);
107+
stringBuilder.Append(' ');
108+
stringBuilder.Append(_quantifier.GetItemString());
108109
}
109110

110111
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -115,7 +116,8 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
115116
stringBuilder.Append(_quantifier);
116117
stringBuilder.Append(For);
117118
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
118-
stringBuilder.Append(ComplyItems);
119+
stringBuilder.Append(' ');
120+
stringBuilder.Append(_quantifier.GetItemString());
119121
}
120122

121123
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
@@ -212,7 +214,8 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
212214
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
213215
stringBuilder.Append(For);
214216
stringBuilder.Append(_quantifier);
215-
stringBuilder.Append(ComplyItems);
217+
stringBuilder.Append(' ');
218+
stringBuilder.Append(_quantifier.GetItemString());
216219
}
217220

218221
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -223,7 +226,8 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
223226
stringBuilder.Append(_quantifier);
224227
stringBuilder.Append(For);
225228
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
226-
stringBuilder.Append(ComplyItems);
229+
stringBuilder.Append(' ');
230+
stringBuilder.Append(_quantifier.GetItemString());
227231
}
228232

229233
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
@@ -315,7 +319,8 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
315319
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
316320
stringBuilder.Append(For);
317321
stringBuilder.Append(_quantifier);
318-
stringBuilder.Append(ComplyItems);
322+
stringBuilder.Append(' ');
323+
stringBuilder.Append(_quantifier.GetItemString());
319324
}
320325

321326
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
@@ -326,7 +331,8 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
326331
stringBuilder.Append(_quantifier);
327332
stringBuilder.Append(For);
328333
_itemExpectationBuilder.AppendExpectation(stringBuilder, indentation);
329-
stringBuilder.Append(ComplyItems);
334+
stringBuilder.Append(' ');
335+
stringBuilder.Append(_quantifier.GetItemString());
330336
}
331337

332338
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)

Source/aweXpect/That/Collections/ThatEnumerable.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ namespace aweXpect;
2222
public static partial class ThatEnumerable
2323
{
2424
private const string For = " for ";
25-
private const string ComplyItems = " items";
2625
private const string SortOrder = " order";
2726
private const string CannotCompareToNull = " cannot compare to <null>";
2827

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace aweXpect.Tests;
2+
3+
public sealed partial class ThatEnumerable
4+
{
5+
public sealed partial class AtLeast
6+
{
7+
public sealed class ComplyWithTests
8+
{
9+
[Fact]
10+
public async Task WhenAtLeastOneItemMatches_ShouldSucceed()
11+
{
12+
int[] subject = [1, 2, 3, 4, 5,];
13+
14+
async Task Act()
15+
=> await That(subject).AtLeast(1).ComplyWith(it => it.IsEqualTo(3));
16+
17+
await That(Act).DoesNotThrow();
18+
}
19+
20+
[Fact]
21+
public async Task WhenNoItemsMatch_ShouldFail()
22+
{
23+
int[] subject = [1, 2, 3, 4, 5,];
24+
25+
async Task Act()
26+
=> await That(subject).AtLeast(1).ComplyWith(it => it.IsEqualTo(99));
27+
28+
await That(Act).Throws<XunitException>()
29+
.WithMessage("""
30+
Expected that subject
31+
is equal to 99 for at least one item,
32+
but found only 0
33+
""");
34+
}
35+
}
36+
}
37+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
namespace aweXpect.Tests;
2+
3+
public sealed partial class ThatEnumerable
4+
{
5+
public sealed partial class Exactly
6+
{
7+
public sealed class ComplyWithTests
8+
{
9+
[Fact]
10+
public async Task WhenExactlyOneItemMatches_ShouldSucceed()
11+
{
12+
int[] subject = [1, 2, 3, 4, 5,];
13+
14+
async Task Act()
15+
=> await That(subject).Exactly(1).ComplyWith(it => it.IsEqualTo(3));
16+
17+
await That(Act).DoesNotThrow();
18+
}
19+
20+
[Fact]
21+
public async Task WhenMoreItemsMatchThanExpected_ShouldFail()
22+
{
23+
int[] subject = [1, 2, 3, 2, 5,];
24+
25+
async Task Act()
26+
=> await That(subject).Exactly(1).ComplyWith(it => it.IsEqualTo(2));
27+
28+
await That(Act).Throws<XunitException>()
29+
.WithMessage("""
30+
Expected that subject
31+
is equal to 2 for exactly one item,
32+
but found 2
33+
""");
34+
}
35+
36+
[Fact]
37+
public async Task WhenNoItemsMatch_ShouldFail()
38+
{
39+
int[] subject = [1, 2, 3, 4, 5,];
40+
41+
async Task Act()
42+
=> await That(subject).Exactly(1).ComplyWith(it => it.IsEqualTo(99));
43+
44+
await That(Act).Throws<XunitException>();
45+
}
46+
47+
[Fact]
48+
public async Task WhenRichExpectationMatchesExactCount_ShouldSucceed()
49+
{
50+
int[] subject = [5, 10, 15, 20, 25, 30, 35,];
51+
52+
async Task Act()
53+
=> await That(subject).Exactly(3)
54+
.ComplyWith(it => it.IsGreaterThan(10).And.IsLessThan(30));
55+
56+
await That(Act).DoesNotThrow();
57+
}
58+
}
59+
60+
public sealed class NegatedComplyWithTests
61+
{
62+
[Fact]
63+
public async Task WhenExactlyOneItemMatches_ShouldFail()
64+
{
65+
int[] subject = [1, 2, 3, 4, 5,];
66+
67+
async Task Act()
68+
=> await That(subject).DoesNotComplyWith(it
69+
=> it.Exactly(1).ComplyWith(x => x.IsEqualTo(3)));
70+
71+
await That(Act).Throws<XunitException>()
72+
.WithMessage("""
73+
Expected that subject
74+
exactly one for is equal to 3 item,
75+
but it did
76+
""");
77+
}
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)